Upload Vulnerabilities Room

 
main.jpg
 

The link for this lab is located here: https://tryhackme.com/room/uploadvulns


The purpose of this room is to explore some of the vulnerabilities resulting from improper (or inadequate) handling of file uploads


heading10.jpg

Task 1 - Getting Started

For starters, if you are using Linux or MacOS, open up a terminal and type in the following command, then hit enter:

echo "10.10.208.138 overwrite.uploadvulns.thm shell.uploadvulns.thm java.uploadvulns.thm annex.uploadvulns.thm magic.uploadvulns.thm jewel.uploadvulns.thm" | sudo tee -a /etc/hosts

hosts.png

This simply adds hostnames to IPs - for example, you can type "overwrite.uploadvulns.thm"


heading11.png

Task 2 - Introduction

The ability to upload files to a server has become an integral part of how we interact with web applications. Be it a profile picture for a social media site, a report being uploaded to cloud storage or saving a project on GitHub; the applications for file upload features are limitless.

Unfortunately, when handled badly, file uploads can also open up severe vulnerabilities in the server. This can lead to anything from relatively minor, nuisance problems all the way up to full RCE (Remote Code Execution) if an attacker manages to upload and execute a shell.

With unrestricted upload access to a server (and the ability to retrieve data at will), an attacker could deface or otherwise alter existing content - up to and including injection malicious webpages which lead to further vulnerabilities such as XSS or CSRF

By uploading arbitrary files, an attacker could potentially also use the server to host and/or serve illegal content, or to leak sensitive information. Realistically speaking, an attacker with the ability to upload a file of their choice is very dangerous.

The purpose of this room is to explore some of the vulnerabilities resulting from improper (or inadequate) handling of file uploads. Specifically looking at:

  • Overwriting existing files on a server

  • Uploading and Executing Shells on a server

  • Bypassing Client-Side filtering

  • Bypassing various kinds of Server-Side filtering

  • Fooling content type validation checks


Hacker_Loop.gif

Task 3 - General Methodology

Looking at the source code for the page is good to see if any kind of client-side filtering is being applied. Scanning with a directory bruteforcer such as Gobuster is usually helpful in web attacks and may reveal where files are being uploaded to.

Intercepting upload requests with Burp Suite will also be handy. Browser extensions such as Wappalyzer can provide valuable information at a glance about the site you are targeting.

With a basic understanding of how the website might be handling our input, we can then try to poke around and see what we can and cannot upload. If the website is employing client-side filtering, then we can easily look at the code for the filter and look to bypass it.

If the website has server-side filtering, then we may need to take a guess at what the filter is looking for, upload a file, then try something slightly different based on the error message if the upload fails.

Uploading files designed to provoke errors can help with this. Tools like Burp Suite or OWASP ZAP can be extremely helpful at this stage.


heading21.png

Task 4 - Overwriting Existing Files

When files are uploaded to the server, a range of checks should be carried out to ensure that the file will not overwrite anything which already exists on the server. Common practice is to assign the file with a new name - often either random or with the data and time of upload added to the start or end of the original filename.

Alternatively, checks may be applied to see if the filename already exists on the server; if a file with the same name already exists, then the server will return an error message asking the user to pick a different file name.

File permissions also come into play when protecting existing files from being overwritten. Web pages should NOT be writeable to the web user, thus preventing them from being overwritten with a malicious version uploaded by an attacker.

If no such precautions are taken, then we might be able to overwrite existing files on the server. Realistically speaking, the chances are that file permissions on the server will prevent this from being a serious vulnerability. That said, it could still be quite the nuisance and is worth keeping an eye out for in a pentest or bug hunting environment.

In the following image, we have a web page with an upload form:

image1.png

You may need to enumerate more for a real challenge but in this instance, we can take a look at the source code first.

image2.png

We see code that is responsible for displaying the image that we saw on the page. It is being sourced from a file called "spaniel.jpg" inside a directory called "images".

Now we know where the image is being pulled from - can we overwrite it?

Download any image from the internet and call it spaniel.jpg. Then, you can try uploading it to the site and see if we can overwrite the existing image:

image3.png
image4.png

Our attack was successful. We managed to overwrite the original "images/spaniel.jpg" with our own copy.

Now for your own practice. First, open your browser and navigate to "overwrite.uploadvulns.thm" - the goal is to overwrite a file on the server with an upload of your own.

Questions

Q1: What is the name of the image file which can be overwritten? A: Looking at the source code for the site reveals that there is a background image called "mountains.jpg" that can be overwritten

Background image

Q2: Overwrite the image. What is the flag you receive? A: First, simply download any image you want. I downloaded a Kali wallpaper and rename it to the same as the one on the site - mountains.jpg

downloaded image Then, simply upload it to the website and you should get the flag.

Flag on site To test if it actually changed the image however, simply refresh the site and you should see your image as the new background


Background changed

heading20.png

Task 5 - Remote Code Execution

RCE would allow us to execute code arbitrarily on the web server. Whilst this is likely to be as a low-privileged web user account (such as www-data on Linux), it is extremely serious. Remote Code Execution through a web application tends to be a result of uploading a program written in the same language as the back-end of the website.

Traditionally, this would be PHP however in more recent times, other back-end languages have become more common (Python Django and JavaScript in the form of Node.js being examples).

There are two basic ways to achieve RCE on a webserver; webshells and reverse shells. Realistically a fully featured reverse shell is the ideal goal for an attacker; however, a webshell may be the only option available.

As a general methodology, we would be looking to upload a shell of one kind or another, then activating it, either by navigating directly to the file if the server allows it or by otherwise forcing the web app to run the script for us.

Web Shells

Let's assume we found a webpage with an upload form:

rce1.png

First, we start with a Gobuster scan.

rce2.png

Looking at the results, we have two directories - uploads and assets. Of these, it seems likely that any files we upload will be placed in the "uploads" directory. We can try uploading a legitimate image file first. Here, we choose a random photo.

rce3.png
rce4.png

Now, if we go to http://demo.uploadvulns.thm/uploads we should see that the spaniel picture is there.

rce5.png
rce6.png

Next, we can try uploading a web shell. We know that the web server is running with a PHP back-end so we can skip straight to creating and uploading the shell. In real life, we may need to do a little enumeration; however, PHP is a good place to start regardless.

A simple webshell works by taking a parameter and executing it as a system command. In PHP, the syntax for this would be:

webshell.png

This code takes a GET parameter and executes it as a system command. It then echoes the output back to the screen.

We can try uploading a shell to the site and then using it to show the current user and contents of the current directory.

rce7.png

We can now use this shell to read files from the system, or upgrade from here to a reverse shell. Now that we have RCE, the options are limitless. Note however, that when using webshells, it is usually easier to view the output by looking at the source code of the page.

Reverse Shells

The process for uploading a reverse shell is almost identical. For this, we will use the Pentest Monkey reverse shell from here. Before using it however, you need to change the IP inside of it to the TryHackMe IP address you are assigned.

With the shell edited, the next thing to do is start a Netcat listener to receive the connecton via the "nc -nvlp 1234" command.

rce8.png

Now, let's upload the shell then activate it by navigating to http://demo.uploadvulns.thm/uploads/shell.php. The name of the shell will be whatever you called it.

The website should hang and not load properly - if you switch back to the terminal however, we have a shell.

rce9.png

Once again, we obtained RCE on the webserver. From here, we would want to stabilize the shell and escalate the privileges.

Now, try it yourself on the shell.uploadvulns.thm website

Questions

Q1: Run a Gobuster scan on the website using the syntax from the screenshot above. What directory looks like it might be used for uploads? A: To run a Gobuster scan, we use the syntax "gobuster dir -u http://shell.uploadvulns.thm -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt"

gobuster scan After a while, you will see a couple of directories listed. The most likely folder where uploads get stored is probably /resources

resources directory

Q2: What's the flag in the /var/www/ directory of the server? A: For this, I will decide to use a reverse shell. The first step to take is to download the Pentest Monkey PHP reverse shell onto our machine and changing the IP inside the code

changing IP
Next, we have to start a Netcat listener on our local Kali machine on whatever port is specified inside your PHP reverse shell code - for me it's port 1234

netcat listener
Then, we simply upload the .php file to the server using the Upload button. Once it is uploaded, we simply navigate to the /resources folder and should be able to see it there

executing shell
Finally, we simply click on the PHP file in /resources and go back to our Netcat listener - we should have a shell

gaining shell
The next step is simply navigate to the /var/www directory and cat out the flag.txt document

flag

heading22.png

Task 6 - Filtering

Up until now, we have largely been ignoring the counter-defenses employed by web developers to defend against file upload vulnerabilites. Every website that you successfully attacked so far has been completely insecure. From here on out, we will look at some of the defense mechanisms used to prevent malicious file uploads and how to circumvent them.

When we talk about a script being "Client-Side" in the context of web applications, it means that is is running in the user's browser as opposed to on the web server itself. JavaScript is pretty much ubiquitous as the client-side scripting language.

Regardless of the language being used, a client-side script will be run in your web browser. In the context of file-uploads, this means that the filtering occurs before the file is even uploaded to the server.

Theoretically, this would seem like a good thing. In an ideal world, it would be; however, because the filtering is happening on our computer, it is trivial to bypass. As such client-side filtering by itself is a highly insecure method of verifying that an uploaded file is not malicious.

Conversely, a server-side script will be run on the server. Traditionally, PHP was the predominant server-side language; however, in recent years, other options (C#, Node.js, Python, Ruby on Rails etc..) have become more widely used.

Server-side filtering tends to be more difficult to bypass as you do not have the code in front of you. As the code is executed on the server, in most cases, it will also be impossible to bypass the filter completely; instead, you have to form a payload that conforms to the filters in place, but still allows us to execute the code.

Extension Validation

File extensions are used (in theory) to identify the contents of a file. In practice, they are very easy to change, so actually do not mean much; however, Windows still uses them to identify file types, although Unix based systems tend to rely on other methods.

Filters that check for extensions work in one of two ways. They either blacklist extensions (list of extensions which are NOT allowed) or they whitelist extensions (list of extensions which ARE allowed).

File Type Filtering

Similiar to Extension Validation, but more intensive. File Type Filtering looks to verify that the contents of a file are acceptable to upload. We can look at two types of file type validation:

MIME validation: MIME (Multipurpose Internet Mail Extension) types are used as an identifier for files - originalyl when transferred as attachments over email but now also when files are being transferred over HTTP(S). The MIME type for a file upload is attached in the header of the request and looks like this.

filtering1.png

MIME types follow the format "<type>/<subtype>". In the request above, you can see that the image "spaniel.jpg" was uploaded to the server. As a legitimate JPEG image, the MIME type for this upload was "image/jpeg". The MIME type for a file can be checked client-side and/or server-side; however, as MIME is based on the extension of the file, this is extremely easy to bypass.

Magic Number Validation: Magic numbers are the more accurate way of determining the contents of a file although they are not impossible to fake. The "magic number" of a file is a string of bytes at the very beginning of the file content which identify the content. For example, a PNG file would have these bytes at the very top of the file: 89 50 4E 47 0D 0A 1A 0A.

filtering2.png

Unlike Windows, Unix systems use magic numbers for identifying files; however, when dealing with file uploads it is possible to check the magic number of the uploaded file to ensure that it is safe to accept. This is by no means a guaranteed solution but it is more effective than checking the extension

File Length Filtering

File length filters are used to prevent huge files from being uploaded to the server via an upload form (as this can potentially starve the server of resources). In most cases, this will not cause any issues when uploading shells; however, it is worth bearing in mind that if an upload form only expects a very small file to be uploaded, there may be a length filter in place to ensure that the file length requirement is met.

As an example, the PHP reverse shell from earlier is 5.4KB big - if the form was expecting a max of 2KB, we would need to find an alternative shell to upload.

File Name Filtering

As touched upon earlier, files uploaded to a server should be unique. Usually, this would mean adding a random aspect to the file name, however an alternative strategy would be to check if a file with the same name already exists on the server and give the user an error if so.

Additionally, file names should be sanitized on upload to ensure that they don't contain any "bad characters" which could potentially cause problems on the file system when uploaded (e.g. null bytes or forward slashes on Linux as well as control characters such as ";" and potentially unicode characters).

This means that on a well administered system, our uploaded files are unlikely to have the same name we gave them before uploading, so be aware you may have to go hunting for your shell in the event that you manage to bypass the content filtering.

File Content Filtering

More complicated filtering systems may scan the full contents of an uploaded file to ensure that it is not spoofing its extension, MIME type and Magic Number. This is a significantly more complex process than the majority of basic filtration systems employ, and thus is not covered.

It is worth noting that none of these filters are perfect by themselves - they will usually be used in conjunction with each other, providing a multi-layered filter thus increasing the security of the upload significantly. Any of these filters can all be applied client-side, server-side or both.

Similiarly, different frameworks and languages come with their own inherent methods of filtering and validating uploaded files. As a result, it is possible for language specific exploits to appear; for example, until PHP major version five, it was possible to bypass an extension filter by appending a null byte followed by a valid extension to the malicious .php file.

More recently, it was also possible to inject PHP code into the EXIF data of an otherwise valid image file, then force the server to execute it.

Questions

Q1: What is the traditional server-side scripting language? A: PHP

Q2: When validating by file extension, what would you call a list of accepted extensions (whereby the server rejects any extension not in the list)? A: Whitelist

Q3: What MIME type would you expect to see when uploading a CSV file? A: Doing a quick Google search for "CSV MIME type" reveals that it should be "text/csv"

CSV MIME type

heading23.jpg

Task 7 - Bypassing Client-Side Filtering

As mentioned, client-side filtering tends to be extremely easy to bypass as it occurs entirely on a machine that you control. When you have access to the code, it is very easy to alter it.

There are four easy ways to bypass your average client-side file upload filter:

  1. Turn off JavaScript in your browser - this will work provided the site does not require JavaScript in order to provide basic functionality. If turning off JavaScript completely will prevent the site from working at all, then one of the other methods would be more desirable

  2. Intercept and modify the incoming page - Using Burp Suite, we can intercept the incoming web page and strip out the JavaScript filter before it has a chance to run. The process for this will be covered below

  3. Intercept and modify the file upload - where the previous method works before the webpage is loaded, this method allows the web page to load as normal but intercepts the file upload after it is already passed (and been accepted by the filter)

  4. Send the file directly to the upload point - posting the data directly to the page which contains the code for handling the file upload is another effective method for completely bypassing a client side filter. To use this method, you would first aim to intercept a successful upload (using Burp or the browser console) to see the parameters being used in the upload which can then be slotted into the above command. The syntax for this command would look like this:

filtering3.png

Example

First, let's assume that we have found an upload page on the website:

f1.png

As always, we will take a look at the source code. Here, we see a basic JavaScript function checking for the MIME type of uploaded files:

f2.png

In this instance, we can see that the filter is using a whitelist to exclude any MIME type that is NOT "image/jpeg".

Our next step is to attempt a file upload - as expected, if we choose a JPEG, the function accepts. Anything else and the upload is rejected.

Having established this, we start Burp Suite and reload the page. We see our own request to the site, but we want to see the server's response so right-click on the intercepted data, scroll down to "Do intercept" and then select "Response to this request"

f3.png

When we click the "Forward" button at the top, we then see the server's response to our request. Here, you can delete, comment out, or otherwise break the JavaScript function before it has a chance to load.

f4.png

Having deleted the function, we once again click "Forward" until the site has finished loading, and are now free to upload any kind of file to the website.

f5.png

It is worth noting that Burp Suite will not intercept any external JavaScript files that the web page is loading by default. If you need to edit a script which is NOT inside the main page being loaded, you need to go to "Options" tab at the top of Burp Suite, then under the "Intercept Client Requests" section, edit the condition of the first line to remove "^js$|"

f6.png

We've already bypassed this filter by intercepting and removing it prior to the page being loaded, but let's try doing it by uploading a file with a legitimate extension and MIME type then intercepting and correcting the upload with Burp Suite.

Having reloaded the webpage to put the filter back in place, take the reverse shell we used before and rename it to be called "shell.jpg". As the MIME type automatically checks out, the Client-Side filter lets our payload through.

f7.png

Once again, we intercept via Burp Suite and then click "Upload" and catch the request.

f8.png

Observe that the MIME type of our PHP shell is currently "image/jpeg". We can change this to "text/x-php" and the file extension from ".jpg" to ".php" then forward the request to the server:

f9.png

Now, when we navigate to http://demo.uploadvulns.thm/uploads/shell.php having set up a netcat listener, we receive a connection from the shell.

f10.png

Questions

Q1: What is the flag in /var/www? A: First, navigating to the site reveals an upload page

upload page
Next, we take a look at the source code. We see a JavaScript file called "client-side-filter.js"

JS file Knowing this we can do two things - stop it from loading or see what MIME is accepted and bypass it. First, we will stop it from loading. To do this, first we can read the JS file to see that it ONLY accepts PNG files for uploading

JS Source code Next, we simply start Burp Suite and reload the page.

intercept main page
Once intercepted, we select to intercept the response to the request

intercept response
Then, we simply hit "Forward" and get the server's response.

server response
Next, simply delete the script that is loading the filter out of the response

delete script
Having deleted it, click "Forward" once again until the site is finished loading. Once it has loaded, we are now free to upload any kind of document we want - in this case, the PHP reverse shell file.

free upload
Next, we have to find out where our file got uploaded to. In this case, I used gobuster to find directories that it could be stored.

find directories via gobuster There are two main folders - /images and /assets. Navigating to both of these reveals that "/images" folder stores our malicious PHP file.

images folder
The final step is to start a netcat listener on our machine with the port we specified in the reverse shell earlier - mine is 1234.

netcat listener
Once we have a listener, we simply click the PHP file to execute it and hopefully get a shell back.

shell And we do indeed get a shell back!

Second Way (OPTIONAL) We can also do this by manipulating the MIME type it checks for. First, we have to hard reset the page by hitting CTRL+F5 to reload like we are visiting it for the first time. Next, let's take the shell we used previously and make a copy to be called "shell.png" - as you remember, it ONLY accepts PNGs for this site.

png file change Next, we simply upload "shell.png" to the site and intercept the Upload request.

upload shell png and intercept We see that the MIME type of our PHP shell is currently "image/png". Simply change this to "text/x-php" and the file extension from .png to .php and forward the request to the server.

changing mime type Now, if we go back to that /images folder, we should see two PHP files.

2 php files Once again, starting a listener and clicking the "php-reverse-shell2.php" file will establish a shell connection for us.

second shell way

heading24.png

Task 8 - Bypassing Server-Side Filtering: File Extensions

Client-side filters are easy to bypass as you can see the code for them even if it has been obfuscated and needs processed before you can read it; but what happens when you cannot see or manipulate the code?

In short, we have to perform a lot of testing to build up an idea of what is or is not allowed through the filter, then gradually put together a payload which conforms to the restrictions.

For the first part of this task, we will take a look at a website that is using a blacklist for file extensions as a server side filter. There are a variety of ways that this could be coded, and the bypass we use is dependent on that. In the real world, we wouldn't be able to see the code for this

black1.png

In this instance, the code is looking for the last period (.) in the file name and uses that to confirm the extension. Other ways the code could be working include:

  • Searching for the first period in the filename

  • Splitting the file name at each period and checking to see if any blacklisted extensions show up

We can see that the code is filtering out the ".php" and ".phtml" extensions. If we want to upload a PHP script, we have to find another extension. The Wikipedia page reveals a bunch of optional extensions to try - many of which bypass the filter (which only blocks the two aforementioned extensions).

Unfortunately, it appears that the server is configured to not recognized them as PHP files as in the below example

black2.png

This is the default behaviour of Apache2 servers; however, the sysadmin may have changed the default configuration so it's worth trying.

Eventually, through trial and error, we find that the ".phar" extension bypasses the filter and works giving us our shell.

black3.png

Let's try again although this time we will do it without the source code. Once again, we have the upload form:

black4.png

And we start by scoping it out with a legitimate upload of an image for example.

black5.png

That tells us that JPEGS are accepted at least. We can go for one that will be rejected - shell.php

black6.png

From here, we enumerate further by trying the techniques from above and just generally trying to get an idea of what the filter will accept or reject.

In this case, we find that there are no shell extensions that both execute and are not filtered. In the previous example, we saw that the code was using the "pathinfo()" PHP function to get the last few characters after the "." but what happens if it filters the input slightly differently?

We can try uploading a file called "shell.jpg.php". We know that JPEG files are accepted so what if the filter is just checking to see if the ".jpg" file extension is somwehere within the input?

Pseudocode for this kind of filter may look something like this:

pseudo.png

When we try to upload our file, we get a success message. Navigating to the "/uploads" directory confirms that the payload was successfully uploaded.

black7.png

This is by no means an exhaustive list of upload vulnerabilities related to file extensions. As with everything in hacking, we are looking to exploit flaws in code that others have written; this code may very well be uniquely written for the task at hand.

This is the really important point to take away from this task; there are a million different ways to implement the same feature when it comes to programming - your exploit must be tailored to the filter at hand.

The key to bypassing any kind of server side filter is to enumerate and see what is allowed and blocked and then try to craft a payload which can pass the criteria the filter is looking for.

Questions

Q1: What is the flag in /var/www? A: First, we have to determine what kind of files are accepted and blocked. We can try uploading a random image file (in this case, PNG) and we can see it is allowed

uploading image files success image file
Next, we can try uploading a ".php" file and see if that works.

php file php upload error
As you can see, .php files are blocked. What happens if we try to use two extensions such as "php-reverse-shell.png.php"?

png.php file png.php also invalid
We see it still gets blocked. Reading back through the material, we can see that some server-side code will simply look for the ".php" anywhere in the filename. But what about other variations of PHP file extensions as listed on Wikipedia?

php variable extensions
Doing a bit of trial and error here, going through each one naming it "shell.png.(php,phtml,php3,php4)" etc... we finally reach one that gets successfully uploaded - the ".php5" extension

php5 file php5 successful upload
Now, we need to find where our uploaded files are getting stored. Once again, using Gobuster, we find an interesting directory called "privacy".

privacy folder
Navigating there, we can see our original PNG image and our PHP shell with the ".php5" extension at the end.

php5 in folder
We successfully bypassed the filter. Now, as always, we simply run our netcat listener and open the PHP file and get our reverse shell.

reverse shell
Once there, we can simply navigate to the /var/www directory and grab the flag

flag

heading25.jpg

Task 9 - 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 is always the very first thing in a file. Knowing this, it is possible to use magic numbers to validate file uploads, simply by reading those first few bytes and comparing them against either a whitelist or a blacklist.

Keep in mind however, that this technique can be very effective against a PHP based webserver but can sometimes fail against other types of web servers.

As usual, we have an upload page:

magic1.png

As expected, if we upload a ".php" file, we get an error. However, if we upload a JPEG image, the website is fine with it.

From the previous attempt at an upload, we know that JPEG files are accepted, so let's try adding the JPEG magic number to the top of our shell.php file. A quick look at the list of file signatures on Wikipedia shows us that there are several possible magic numbers of JPEG files.

It should not matter which one you use so pick any for example - FF D8 FF DB. You could add the ASCII representation of the digits (ÿØÿÛ) directly to the top of the file but it is often easier to work directly with the hexadecimal representation.

Before getting started, we can use the Linux "file" command to check the file type of our shell.

magic2.png

As expected, the command tells us that the filetype is PHP. We can see that the magic number we chose is four bytes long. Oppen up the reverse shell script and add four random characters on the first line. These characters do not matter.

magic3.png

Save the file and exit. Next, reopen the file in "hexeditor". In hexeditor, the file looks like this.

magic4.png

Note the four bytes in the red box; they are all 41 which is the hex code for a capital "A".

Change this to the magic number we found earlier for JPEG files: FF D8 FF DB

magic5.png

Now, save and exit and use the file command once again. You will see that the file is now identifed as JPEG image data.

magic6.png

If you try uploading the modified shell, it will bypass the filter.

magic7.png

There we have it - we bypassed the server-side magic number filter and received a reverse shell.

Questions

Q1: Grab the flag from /var/www A: First, we can try uploading a valid image file to the site and see if it acecpts that format (in my case, PNG).

png image upload gifs only error
As we can see, it only accepts GIFs. Knowing this, we can Google the magic numbers for a GIF image and we get this:

GIF magic numbers
Once we know these numbers, we can open our standard "php-reverse-shell.php" file with "hexeditor" and change the first section to the GIF magic numbers.

hexeditor adding magic numbers
One thing to note is to open the PHP file with any text editor and change the top slightly by adding "<?php" data-preserve-html-node="true" below the GIF87a text to ensure that it identifies it as valid PHP code.

modifying code in nano
If we now run the "file" command on this file, it should show up as a GIF file.

file command ran
Now, we should be able to successfully upload it and bypass the filter.

fake gif shell success upload
However, we don't know where our file actually is to execute it. Running Gobuster again, we find the directory it is stored in.

graphics directory
However, navigating to this page is forbidden.

forbidden error
To get around this, we can try executing the shell by referencing it's name in the URL directly - magic.uploadvulns.thm/graphics/fakegifshell.php. If we type that in and hit enter, our netcat listener should have a shell.

executing shell
Now, simply navigate to /var/www and grab the flag.

flag

heading7.png

Task 10 - Example Methodology

We’ve seen various different types of filters. Let’s now discuss the common methodology used.

  1. The first thing we do is take a look at the website as a whole. Using browser extensions such as Wappalyzer we would look for indicators of what languages and frameworks the web application might have been built with. Be aware that Wappalyzer is not always 100% accurate. A good start to enumerating this manually would be by making a request to the website and intercepting the response with Burp Suite. Headers such as server or x-powered-by can be used to gain information about the server.

  2. Having found an upload page, we aim to inspect it further. Looking at the source code for client-side scripts to determine if there are any client-side filters to bypass would be a good thing to start with.

  3. We would then attempt a completely innocent file upload. From there, we would look to see how the file is accessed. In other words, can we access it directly in an uploads folders? Is it embedded in a page somewhere? What is the naming scheme of the website? This is where tools such as Gobuster might come in handy. This step is extremely important as it not only improves our knowledge of the virtual landscape but also gives us a baseline “accepted” file which we can base further testing on.

  4. Having ascertained how and where our uploaded files can be accessed, we would then attempt a malicious file upload, bypassing any client-side filters we found in step two. We would expect our upload to be stopped by a server side filter, but the error message that it gives us can be extremely useful.

Assuming that our malicious file upload was stopped by the server, here are some ways to ascertain what kind of server-side filter may be in place:

  • If you can upload a file with an invalid extension (image.invalidfileextension) then the chances are that the server is using an extension blacklist to filter out executable files. If this upload fails, then any extension filter will be operating on a whitelist.

  • Try re-uploading the original innocent file, but change the magic number of the file to be something that you would expect to be filtered. If the upload fails, then you know that the server is using a magic number filter.

  • As with the previous point, try to upload your innocent file but intercept the request and change the MIME type of the upload to something that you would expect to be filtered. If the upload fails, then you know that the server is filtering based on MIME types.

  • Enumerating file length filters is a case of uploading a small file, then uploading progressively bigger files until you hit the filter. At that point, you know what the acceptable limit is. If you are lucky, then the error message of the original upload may outright tell you what the size limit is.


heading5.png

Task 11 - Challenge

A good idea before starting anything is to run a Gobuster scan and let it run in the background.

gobuster_initial.png

First, we can take a look at the source code of the site.

sourecode.png

As we can see, most of the code is coming from a folder called "assets". If we go back to the main page and use a tool called "Wappalyzer", it will give some information.

nodejs.png

It tells us that it is written in Node.js and using the Express framework. Now, we can go back to our Gobuster scan and see that it has identified a few directories.

gobusterdone.png

It's found things such as an admin page, content page and a modules page. The "/content" page seems like it would host most of the images or content on the site itself. To check that images are hosted in that /content directory, we can use "Inspect Element" in Firefox to see where the background image is coming from.

contentdir.png

As you can see, checking the source code for the background image reveals that it is coming from "/content/LKQ.jpg". This also seems like a randomized naming scheme being applied by the server-side code. We can check and find all JPEG images hosted in that content directory by doing another Gobuster scan using the provided wordlist.

findingjpgs.png

While that runs, we can check out the "/admin" page as it seems interesting.

adminpage.png

Knowing a little bit of Node.js reveals that this page is likely to be where we can execute the shell as Node.js will NOT let you navigate to it like PHP.

The next step is to try and upload a shell. Knowing that it is running Node.js, we can find a Node.js reverse shell payload from here.

Next, we can simply copy the code from the GitHub into a .js file and change the IP address and port numbers to your TryHackMe IP and a random port (I used 8080).

change.png

Now, we can try uploading this raw shell in the upload form. If we do, we will get an error.

invalid.png

Right now, we do not know if this is a client-side or server-side filter. We can check for client-side using Burp Suite by intercepting a full refresh of the main page while intercepting the JavaScript files as well (remember to change the rules)

removejs.png

Once removed, simply full refresh the page (CTRL+F5) and intercept the files. We want to try and identify any filters being applied. These will most likely be in a separate JS file. Forwarding multiple requests, we get to a GET request for an "upload.js" script.

uploadjs.png

Once on this request, right-click and go to the "Do intercept" menu and then check "Response to the request" to intercept the server response to this request.

response.png

Once done, simply forward all other packets until you reach the response. This response contains the full code for the upload.js script. As you can see this file has three filters - file size, magic number and checking file extensions.

filters.png

Simply delete all these from the request and forward it. This should effectively remove all the client-side filters for uploads.

removedfilters.png

Once again, we can simply try uploading the shell.js file. Unfortunately, we get the same error - this indicates that there is also some server-side filter in place.

error2.png

A very simple filter could be checking for the MIME type. If we try changing the file name from "shell.js" to "shell.jpg" and uploading the JPG, it successfully uploads the file.

JPG.png
success.png

If you remember back, we performed a scan to identify all JPG images on the server. Looking back at these results, we see that there are 4 images with what seem to be randomly generated 3-letter filenames

alljpgs.png

If we run that same scan again and compare the results, we will see 5 images this time, indicating that our "shell.jpg" successfully got uploaded and renamed to "CRZ.jpg" - it will be a different name in your scenario.

crz.png

Now that we know where the file is (/content) and it got uploaded (CRZ.jpg) we can try navigating to it and see if it is there

errors.png

It provides us an error because it is not a JPG file but this does confirm that the file got uploaded successfully and is sitting on the server passed all the filters.

To fully execute this reverse shell, we first need to set up our netcat listener (nc -nvlp 8080) to whatever port you specified in the Node.js shell a while back

8080.png

And then, if you remember the /admin page we could execute modules from the modules directory. To get past this, we can use a little Linux terminology to go up one directory and then into the /contents directory and execute our malicious shell.

execute.png

Once we hit enter and go back to our netcat listener, we should have a shell

shellsuc.png

Finally, navigate to the /var/www directory and grab the flag.txt

flag.png

sloth2.gif

Task 12 - Conclusion

Well, that's us done! Hopefully you've learnt something from completing this room. This was a very brief introduction to the basics of file upload vulnerabilities -- there is a lot more to learn! Use what you've learnt here to go and research more advanced exploits related to malicious file uploads.

Previous
Previous

Pickle Rick

Next
Next

OWASP Juice Shop Room