Back to HTBHack The Box
Write-up

🖥️Interpret

Mirth Connect RCEMariaDB PBKDF2 CrackingPython fstring Eval Injection

Hacking "Interpret": A Journey Through Frustration, Code, and Final Victory

The world of penetration testing is rarely a straight line. It is a jagged path of trial and error, where the most significant breakthroughs often come only after a period of intense frustration. Our experience with the "Interpret" machine on Hack The Box was a perfect embodiment of this reality. It wasn't just a technical challenge; it was a psychological one that tested our methodology, our patience, and our ability to pivot when the "obvious" path led to a dead end.

The Deceptive Beginning

The journey began with the "Interpret" machine, a medium-difficulty Linux box that immediately signaled its complexity through its name. Our initial foothold was achieved through a known vulnerability in Mirth Connect (CVE-2023-43208). Exploiting a flaw in how the application handled XML data allowed us to land on the system as the mirth service user. At that moment, the rush of adrenaline was palpable. We were inside. However, this early success was a siren’s song, luring us into a false sense of security. We thought the rest of the path would be just as straightforward. We were wrong.

The "INVALID_INPUT" Era

Once we were in as mirth, we discovered a service running locally on port 54321. We identified a Python script, notif.py, running as root. This was clearly the target for privilege escalation. However, we were trapped in a "black box" scenario. We couldn't read the script because it belonged to the sedric group, and we were merely mirth.

We spent a significant amount of time attempting to "brute-force" our way into an RCE (Remote Code Execution) on this port. We sent JSON payloads, XML payloads, and various shell metacharacters, only to be met with a cold, repetitive response: [INVALID_INPUT]. This was our first major lesson in methodology. We were trying to force a square peg into a round hole. Without knowing why the input was invalid, we were just tossing coins into a dark well, hoping to hear a splash. This "blind" phase was a massive time sink, but it forced us to realize that we needed more context. We needed to move laterally before we could move up.

The Grind of Lateral Movement

Realizing we couldn't bypass the notif.py filter without seeing it, we pivoted to the database. Accessing the MariaDB instance (mc_bdd_prod) with credentials found in mirth.properties was a turning point. We extracted a Base64-encoded hash for the user sedric.

This is where the real technical grind began. The hash wasn't a simple MD5 or SHA-1; it was a complex PBKDF2-HMAC-SHA256 structure. We had to manually deconstruct the Base64 string to identify the 8-byte salt and the 32-byte hash. Our initial attempts to crack it failed because we weren't using the correct format for Hashcat. It was a moment of technical humility. After carefully reconstructing the hash into the sha256:600000:salt:hash format and running it against the rockyou.txt wordlist, we finally saw the password: snowflake1.

Landing as sedric was more than just a new shell; it was the key to the library. We finally had the permissions to read /usr/local/bin/notif.py.

The "Aha!" Moment: Source Code Analysis

The moment we ran cat /usr/local/bin/notif.py, the dark clouds vanished. Seeing the code was like having a map after wandering in the woods for hours. We immediately identified the "villain" of our story: a restrictive regex pattern r"^[a-zA-Z0-9._'\"(){}=+/]+$" and a terrifyingly insecure use of eval().

The script was taking our XML input and placing it inside a Python f-string, which was then passed to eval(). In Python, f-strings evaluate any expression inside curly braces {}. Because the script ran as root, any code we could sneak into those braces would execute with total system authority.

However, the regex was a clever gatekeeper. It allowed curly braces, but it strictly forbade spaces, semicolons, and pipes. This explained why our earlier bash -i payloads failed miserably. The regex wasn't just checking for malicious intent; it was checking for specific characters. This was the most profound learning moment of the entire process: Security filters are often just puzzles waiting to be solved by understanding the underlying language's syntax.

The Final Strike: Root

With the constraints clearly defined, we had to get creative. We couldn't use spaces, but Python is a rich language. We realized we didn't need a full reverse shell to get the flag. We could use Python’s built-in open().read() function. Since these functions don't require spaces when called directly on a string path, we crafted a payload that looked like this: {open("/root/root.txt").read()}.

We injected this into the firstname tag of our XML request. The script received it, the regex validated it (because it contained no forbidden characters), and the eval() function dutifully executed it. The server responded not with an error, but with the high-entropy string of the root flag. We had won.

Reflections on the Learning Process

Looking back, the "Interpret" machine taught us more about the "Hacker Mindset" than any entry-level tutorial ever could. We learned that:

  1. Enumeration is Continuous: We never stopped gathering info. When the port 54321 path failed, we didn't give up; we went back to the database.
  2. Source Code is King: If you can find a way to read the source code of a custom service, prioritize it. It turns a "guessing game" into an "engineering problem."
  3. Constraints Breed Creativity: The "no-space" regex was a brilliant touch by the machine creator. It forced us to dig deeper into Python’s internal mechanics rather than relying on standard "copy-paste" payloads.
  4. Lateral Movement is Often Mandatory: You can't always jump from a service account to root. Sometimes you need to become a "legitimate" user first to gain the visibility required for the final escalation.

In the end, we didn't just "beat" a machine. We decoded a puzzle, bypassed a firewall of our own making (the blind guessing), and learned to speak the language of the target system. The "Interpret" machine was a grueling instructor, but its lessons are now permanently etched into our methodology. The transition from the frustrated "INVALID_INPUT" screen to the triumphant root flag was the result of a deliberate, analytical, and ultimately successful shift in how we approached the problem.