Day 040 #FromZeroToHacker – Upload Vulnerabilities

Uploading files to web applications is something common nowadays. A profile picture for social media, a report to cloud storage, a project on GitHub, etc. But when handled badly, file uploads can make a website vulnerable.

Let’s see how we can profit from upload vulnerabilities in our daily #FromZeroToHacker challenge.

Table of contents
Introduction
What I have learnt today?
Stats
Resources

Introduction to Upload Vulnerabilities

Uploading files to web applications is something common nowadays. A profile picture for social media, a report to cloud storage, a project on GitHub…

But, when handled badly, file uploads can make a website vulnerable. From something minor such as web defacing, up to full Remote Code Execution or RCE if an attacker manages to upload and/or create a shell (As we did in What the shell?). If an attacker does this, they can do almost anything they want: Injecting malicious content, hosting and serving illegal content, leaking sensitive information…

What I have learnt today?

General Methodology

We found a website with an upload point. How can we exploit it?

The first step in any attack is enumeration, as the more we understand how a website works, the easier will be to attack it. Look at the source code to see if there are any kind of client-side filtering, scan with a directory brute forcer such as Gobuster (That we can easily install with sudo apt install gobuster) and more

Intercepting uploads requests with Burp suite will help too, and also browser extensions such as Wappalyser which can provide us with valuable information about the site we are going to attack.

After doing all of this, we have a basic understanding of how the website may handle our input. If the website is using client-side filtering, we can look at the source code for the filter and see how we can bypass it. If the website has server-side filtering, we can upload a file and look at the error code if the upload fails and adapt. Tools like Burp Suite or OWASP Zap can help us in this step.

Overwriting existing files

When files are uploaded to a site, the server should prevent overwriting existing files. Sometimes the server gives the file a new name based on the date and time it was uploaded or a random ID. Or it could check if the file exists, returning an error message asking the user to pick a new name.

But also, sometimes no such things are used, potentially letting us overwrite existing files on the server: a serious vulnerability.

For example, we have a web page with an upload form:

Upload vulnerabilities demo page

Let’s check the source code:

Demo source code

The image is in a folder called images with the name spaniel.jpg. Can we overwrite this image? Let’s upload an image also called spaniel.jpg:

Upload vulnerabilities demo page success

We managed to overwrite the original spaniel.jpg image as no checks were in place.

Remote Code Execution

Remote Code Execution, as the name suggests, allow us to execute code on the web server. Even if we are a low-level account (normally, www-data on Linux servers), it is a serious vulnerability. We can upload a code called web shell that immediately spawns a shell we can control, granting us access (full or partial) to the server.

There are two ways to achieve RCE when using a file upload vulnerability: Webshells and reverse/bind shells. A fully featured reverse or bind shell is ideal, sometimes the only option available is using a web shell. Normally, we upload the web shell and then we activate it by either navigating to the file uploaded or by forcing the web app to run the script for us.

Web shells:

We have found a webpage with an upload form. What is our next step? Let’s start with a Gobuster scan:

Gobuster scan

We have found two directories: uploads and assets. The images uploaded probably will be placed in the uploads directory (I took a wild guess). Let’s upload an image first:

Web shell upload

Now, if we go to the uploads route we should see the image we have uploaded:

Upload directory

Cool, we can upload images. Let’s try to upload a webshell.

After doing enumeration, we know that this server uses PHP language. Even if we didn’t know, PHP is a good language to try a blind guess. Let’s create a web shell (a piece of code that will grant us terminal access to the server) by creating a file with the following code:

<?php  
&nbsp; &nbsp; echo system($_GET["cmd"]);  
?>

This simple code executes the value of the key cmd, then it echoes the result to the screen.

We uploaded the file as we did with the image. Then, we opened the newly uploaded file and used the cmd parameter to perform a whoami action:

whoami

We can use this shell to read files (like the ones that contain passwords 🙂 ), or we can create a reverse shell.

Reverse shells

Creating a reverse shell is fairly easy. To do it, we upload a file with malicious code. The Pentest Monkey reverse shell is a famous code we could try. Just remember to edit line 49 with your IP: $ip = '127.0.0.1';&nbsp; // CHANGE THIS.

After the file is created, we start a listener which will stand by until it receives the connection:

nc -lvnp 1234

Standing by:

Netcat listener

Now, we upload the shell and we open the file in the URL. This should be the original URL + /uploads/ + the name of the file. For example, WEBSITE/uploads/shell.php.

The website should freeze, but if we go to the terminal, the listener has captured a petition from the website, granting us remote access to the server:

Reverse shell

Filtering

But what happens when the website has filtering, unlike the ones we saw until now?

This filtering can be client-side or server-side.

A client-side filter happens in the browser, using JavaScript language, and it will run before the upload of a file. Server-side filters run on the server and are more difficult to bypass, as we don’t have the code available.

There are two different kinds of filtering:

Extension Validation

This kind of filter either blacklists an extension (they are not allowed) or whitelists an extension (which it is allowed, rejecting them otherwise).

File type Filtering

This is similar to Extension validation but more intense. This type directly checks the file type instead of inferring it from the extension:

  • MIME validation (Multipurpose Internet Mail Extension) types are used as an identifier for files. The MIME type for a file is attached in the header of the request:
MIME validation
  • Magic Number validation: The “magic number” of a file is a string of bytes at the very beginning of the file which identifies the content:
Magic Number validation

File length filtering

This filters files by length. That’s it.

File name filtering

This filters files by name. If there is a file with the same name, either add a random aspect to the file (the date and time, for example) or return an error message. File names should be sanitised to ensure they don’t contain “bad characters”.

File content filtering

The most advanced filtering systems scan the full contents of an upload file to ensure it is not spoofing its extension, MIME type and Magic Number.

None of these filters are perfect by themselves and sometimes we need to place some, if not all of them, providing a multi-layered filter.

Bypassing Client-Side filtering

As we have access to these filters in our browser, they are the weakest filters. We can bypass them in four ways:

  1. Turn off JavaScript in your browser.
  2. Intercept and modify the incoming page with Burp Suite to strip out the JavaScript filter.
  3. Intercept and modify the file upload with Burp Suite.
  4. Send the file directly to the upload point, via curl curl -X POST -F "submit:<VALUE>" -F "<FILE_PARAMETER>:@<PATH_TO_FILE>" <SITE_URL>.

Mind you that if you want to capture JavaScript code with Burp Suite you need to go to the Options tab, and under the Intercept Client Requests remove ^js$| from the first option:

Burp Suite Configuration

Bypassing Server-Side filtering: File extensions

Client-side filters are easy to bypass, but what to do when we can’t manipulate or even see the code? We need to perform a lot of testing to guess what’s happening behind the scenes.

Let’s try an example where the website is using a blacklist for file extensions as a server-side filter. Normally, we couldn’t read the code, but for the sake of this exercise, let’s say it is:

<?php  
&nbsp;&nbsp;&nbsp; //Get the extension  
&nbsp;&nbsp;&nbsp; $extension = pathinfo($_FILES["fileToUpload"]["name"])["extension"];  
&nbsp;&nbsp;&nbsp; //Check the extension against the blacklist -- .php and .phtml  
&nbsp;&nbsp;&nbsp; switch($extension){  
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "php":  
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "phtml":  
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case NULL:  
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $uploadFail = True;  
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;  
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; default:  
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $uploadFail = False;  
&nbsp;&nbsp;&nbsp; }  
?>

This code checks for the last period in the file name as its extension and filters out any file ending in .php or .phtml.

Thanks to our vast knowledge, and just a bit of reading the Wikipedia PHP page, we know that there are rarely used extensions for PHP including .php3, .php4, .php-s, .phar, etc. As the filter only blocks .php and .phtml, we could use those extensions.

![[day_040_bypassing_server_side_filters_phar.png]]

In normal websites, we can’t tell which files they will filter out unless we do a bit of the good old trial-and-error. If they don’t let .jpg files try .jpeg, .png, .bmp, etc. Enumeration is key.

Sometimes, the devs whitelist files. For example, a server checks if the file has a .png or .jpg extension. Why not try a file called shell.png.php? Sometimes this will work. More than you think.

![[day_040_duo_extension.png]]

Bypassing Server-Side filtering: Magic Numbers

Magic numbers are used as a more accurate identifier of files. The magic number of a file is a string of hex digits and the very first thing in a file. Knowing this, we can use magic numbers to validate a file upload.

For example, if we know that an upload only JPEG files are accepted, we could change our file magic numbers to FF D8 FF DB (JPEG files magic numbers) so it will pass as a JPEG file. You can see a list of file signatures on Wikipedia here.

Checking file type with file

Now, let’s change the magic numbers with hexeditor:

Hexeditor pre change
Hexeditor post change

Let’s check what file type is now:

Checking file type with file after changes

Cool! It will work?

Magic number filter passed

Yes 🙂

Example methodology

Sometimes we have a black box: We can do things but we don’t have any output to view what’s happening, or if it is working. Here is an example methodology for this case:

  1. Enumerate: Make a request to the website, and intercept the response with Burp Suite. Check headers such as server or x-powered-by to gain information and learn about vectors of attack like an upload page. Read the code, use Wappalyzer to see what languages and frameworks are used, etc.
  2. We have found an upload page. Look at the source code for client-side scripts.
  3. Make an innocent file upload. See how our file is accessed. Can we access it via uploads folder? It is embedded in a page? What naming scheme follows this website? Use Gobuster to find non-obvious locations. Use the Gobuster -x flag to search for specific extensions: -x php,html,txt.
  4. Once we know where our uploads can be accessed, upload a malicious file. Client-side filters should be no problem now, but a server-side filter will stop our upload. The error message we get will give us a hint of how to bypass it.

Oh no! The server has sopped our malicious file in its tracks! What can we do now??

  • Upload a file with an invalid extension (for example, image.fakefilextension). You were successful? The server blacklists extensions. Did it fail? It uses a whitelist.
  • Reupload the file changing the magic number.
  • Reupload the file, intercept the request with Burp Suite and change the MIME type.
  • Upload a smaller file, then keep uploading files increasing their length until you hit the filter. Now you know what the acceptable limit is.

Summary

What we learnt today:

  • Overwriting existing files on a server.
  • Upload and Execute shells on a server.
  • Bypassing Client-Side filtering.
  • Fooling content type validation checks.

Stats

From 113.663th to 111.371th. Sitting right now in the Top 6%.

Here is also the Skill Matrix:

Skills Matrix

Resources

Random Room

TryHackMe: Upload Vulnerabilities

Other resources

What the shell? 1
What the shell? 2
Enumeration
Content discovery
Pentest Monkey reverse shell
Wikipedia PHP page