Expose is a TryHackMe room with the tagline “Use your red teaming knowledge to pwn a Linux machine.” That’s not much in the way of details besides exposing (no pun intended!) that it’s a Linux box, so let’s get straight to nmap and find out what I’m dealing with.
The initial nmap scan showed five open ports on the machine. A service scan enumerated the service versions running on those ports.
Anonymous access was enabled on the FTP server, but the share was empty. Attempting to cd
to other directories didn’t discover any files. And this is not a vulnerable version of vsFTPd so it’s time to move on to another service for now.
Apache is a web server so we can try to load the site in Burpsuite. Accessing the site root returns a generic page with just the room name.
I ran gobuster
to find interesting directories and discovered an admin page and the exposed phpmyadmin directory.
The /admin/ page displays a login form and asks, “Is this the right admin portal?” By looking at the page code, we see the form is invalid and the “Continue” button doesn’t actually do anything. The button is only styled like a button but doesn’t link anywhere. This page is just a distraction.
Since those were the only two directories found, I went back and ran gobuster again with a larger wordlist. This time found an /admin_101/ directory that wasn’t in the first list.
The page appeared the same, but this time there was embedded Javascript to handle the form submission.
Burpsuite showed an interesting field in the server response to the POST form. It showed a SQL query in the ‘messages’ field.
By altering the data in the email parameter, it was possible to manipulate the returned value in the ‘messages’ response data. This demonstrated that the email parameter was vulnerable to SQL injection. Forcing an error revealed that the server is running MySQL version 8.0.33 on Ubuntu 20.04.2.
With a working SQLi vulnerability discovered, I wanted to enumerate the users table and see if we can discover the login for the website. I started enumeration the manual way to learn more about how the enumeration process works behind the scenes. I’m getting better at Windows and Linux OS exploitation but have a lot to learn in webapp and specifically SQLi exploitation. Yes, I could just run sqlmap
and dump the entire table, but I want to understand what it’s doing in the background and how it finds the table data. I used the PayloadsAllTheThings MySQL Injection page to help develop my queries. Based on the response message, I already know the table I’m looking for is named ‘user’.
First, I identified that there are 4 columns in the user table with this query:
email=nothing' AND(SELECT * FROM user)=(1)-- -&password=password
Starting with the first column, I identified the column name:
email=nothing' UNION SELECT * FROM (SELECT * FROM user JOIN user b)a-- -&password=password
Then I kept adding the next discovered column names to the query until reaching the end of the table:
email=nothing' UNION SELECT * FROM (SELECT * FROM user JOIN user b USING(id,email,password,created))a-- -&password=password
Now that I figured out the table structure of what I’m probing, I ran sqlmap
to automate the database dump with the following command:
sqlmap -u "<http://10.10.80.121:1337/admin_101/includes/user_login.php>" --data "email=hacker%40root.thm&password=password" -p email
In the dump, I retrieved the username and password for the site:
I also discovered a “config” table that listed two php files and what appeared to be a password hash for one of the pages:
The /file1010111/index.php
page was password protected, so I ran the associated hash through Crackstation.net to get the plaintext password:
After entering the plaintext in the /file1010111/index.php
password prompt, I logged in successfully. The resulting page referenced parameter fuzzing and/or hiding DOM elements. Looking closer at the request in Burpsuite, the source code shows hidden text which hints at checking parameters of the GET request.
The parameters in a GET request tell the server which file to load. If this is unsecured server-side, I can leverage this to access other files on the system by exploiting a local file inclusion vulnerability. Let’s see if the index.php page will load another copy of the index.php page by adding the ?file=index.php
parameter:
It does load the page again, and again, and recurses so this is a working LFI vulnerability. I want to get a list of users next so I need to load the /etc/passwd file. Since I don’t know which directory I’m in currently, I’ll add several ../
characters to go back far enough to reach the root directory and then read the /etc/passwd file.
Toward the bottom is the username I’m looking for. In the config table found earlier, the notes on the /upload-cv00101011/index.php
file indicated that file is only accessible with the username starting with “Z”. Entering that username in the password field of that page logged in successfully and loaded a file upload page:
On this upload page, there is inline Javascript file validation that only permits .jpg and .png files. I’ll have to work around this in order to upload my shellcode.
I tested the upload functionality with a PNG file and found the path of the upload folder:
Using the PentestMonkey repo, I saved a reverse PHP shell as revshell.phpA.png on my Kali VM. I captured the upload request in Burpsuite and tried modifying the request to insert a null byte into the filename. This should have saved a revshell.php file on the target file system but it would not work for me. The file uploaded as a literal “revshell.php%00.png
” filename. I tried several different combinations but could not get the file to save with a .php extension as expected.
When I tried to load the .png file in the browser, it would complain that there were errors in the PNG file. That sounded like the code had uploaded successfully but not been named correctly. I ran wget
on that PNG file and confirmed that it was my PHP shellcode, only saved with a .png extension. That got me thinking: how can I make the server execute this code instead of the web browser loading the file directly? Since I knew there was already a working LFI vulnerability exploited above, I could get the server to load and execute code in attempt to present it to me through the index page. I tried it on my revshell.php shellcode that saved as the “0.png” file server-side.
That worked and I caught the shell as the www-data user on my Kali VM:
Browsing through the home directories, I found a flag file that’s only readable by the Z-named user above. There was also a ssh_creds.txt file that’s readable by everybody and I was able to obtain SSH login credentials for the Z-named user. From the nmap scan in the beginning, I know that SSH is open on the machine.
I connected through SSH and was able to cat the user flag:
Now all that’s left is to escalate my privileges to root. I searched for SUID binaries and found that the /usr/bin/find file had the SUID bit set. I executed the command below from GTFOBins and was able to spawn a root bash shell and cat the root flag:
/usr/bin/find . -exec /bin/bash -p \; -quit
References:
https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL Injection/MySQL Injection.md
https://www.thehacker.recipes/web/inputs/null-byte-injection