File Uploads
Last updated
Was this helpful?
Last updated
Was this helpful?
This can lead to server compromise, execution of malicious code, and unauthorized access to sensitive data.
Validate file types, use secure file storage paths, implement antivirus scanning, and enforce strict access controls on uploaded files.
Enumerate the technologies used on the server -> upload a same-language webshell.
The example below is based on TCM's course.
We should start by using the application as intended in order to understand how it works. In doing so, the uploads directory is revealed (/uploads
) as well as some extension filters (Figure 1).
If we inspect the front-end code, we will notice that the file validation check happens on the client-side (Figure 2).
If the server implicitly trusts the Content-Type
header's value and no further validation is performed, then by changing its value to an expected content type before it reaches the server will result in bypassing this filter (Figure 4).
Next, we can check if the file is now recognized as an image file instead of a PHP script.
To upload the shell we must first bypass the client-side extension filter by adding an image extension to the file and then remove that extension via our proxy, so the server is able to execute it (Figure 7).
Finally, we can interact with the webshell either via the browser or using curl
.
Sometimes a server-side filter can be based on a whitelist or a blacklist (Figure 8).
By trying both php5
and phtml
, we see that only the latter works as the server is not configured to interpret the former as a valid PHP script.
Some filters might only check if the extension exists within the file name, which can be bypassed by renaming the file to webshell.jpg.phar
(double extension method). Others, might require for the file name to end with an allowed extension so we will have to switch the extensions over, i.e., webshell.phar.jpg
(Figure 10) (reverse double extension method).
In case we can use the reverse double extension method, the file will be uploaded but it might not be able to execute. Instead it can be served as a direct download (Figure 11.1) or as a page (Figure 11.2).
This can be potentially bypassed by a null byte injection. The null byte (\x00
) marks the end of a string in various programming languages. By injecting a URL-encoded null byte after the script's extension (.php
) (Figure 13), the server might interpret it as the end of the string and ignore what comes after it, in this case, the .png
extension. However, when the server later processes the file, it could read it as a PHP script and execute it.
To access the file only the part before the null byte might be called, i.e., revshell.php
.
When the uploaded file name is refected on the page. If the OS moves the file with a command such as mv <file> /tmp
, then we achieve RCE.
Similarly, an XSS or SQLi attack can be performed.
Check source code after uploading a file.
Fuzz for an /uploads
directory, and then for the file itself.
Forcing error messages that might disclose the uploads directory:
Uploading a file that already exists or sending 2 identical requests simultaneously.
Uploading a file with a very (very) long name.
If the web application displays the image's metadata, a payload can be injected in one of the metadata's fields. When the image's metadata is displayed, the payload will be triggered.
If the metadata is not directly displayed, chaning the MIME-type to text/html
, might cause the file to be treated as an HTML document and directly trigger the payload.
We can include XSS payloads within the XML data of SVG images. Once the image is displayed, the payload will be triggered.
If the vulnerable function has code Execute
capabilities, then the code within the file we upload will get executed if we include it, regardless of the file extension or type. The file upload form does not need to be vulnerable, just allowing file uploads.
PHP
include()
/include_once()
✅
✅
✅
require()
/require_once()
✅
✅
❌
NodeJS
res.render()
✅
✅
❌
Java
import
✅
✅
✅
.NET
include
✅
✅
✅
We can also use the phar://
wrapper to achieve RCE. The script below can be compiled into a phar
file that when called would write a web shell to a shell.txt
sub-file, which can be accessed using /
.
We can try bypassing this check and upload a by intercepting the request before it reaches the server, but after passing the above validateFileInput
check (Figure 3).
-> indicates that nature and format of a file.
header -> tells the receiving machine what type of data to expect and how to interpret it.
The example below is based on TCM's course.
Except checking the Content-Type
header's value, or in addition to it, the server might actually check the file's content. In this case, polyglot files, i.e., files that different application interpret in different ways, can be created to trick the application. This can be achieve by modifying the file's , aka headers or signatures. For instance, the application below has both a client-side and a server-side filter (Figure 5).
We can try adding the to our webshell using a tool such as hexedit
or (Figure 6), which might trick the system into uploading it.
In this case, we can fuzz the file extension and see if any has been left out of it (Figure 9).
We can also perform attacks using SVG images. This can be used for reading the web application's source files.
We can create a malicious image containing PHP code, using an allowed image extension (bypassing extension filters), in this case .gif
,and including the image's at the beginning of the file content (GIF8
) (bypassing content type filters).
This file on its own is harmless and would not affect normal web application. However, if we combine it with an LFI flaw, then we may be able to achieve RCE after finding its .
The wrapper (not enabled by default) allows to achieve RCE by archiving a webshell into a zip file ending in an allowed extension, e.g. .jpg
. The files within the archived can be reached using #
. This has a higher chance to work if ZIP uploads are allowed by the application, as content-type filters may block it.
There is another obsolete LFI/uploads attack worth noting, which occurs if file uploads is enabled in the PHP config and the phpinfo()
page is somehow exposed to us. This attack has very specific requirements to work: LFI + uploads enabled + old PHP + exposed phpinfo()
. You can find more info .
Content-Type
header..php
file extensions.php
extensions.