How to Upload a Web Shell with Filter Bypass Methods By File Extension

If during pentest, in this tutorial you can learn that how to upload a web shell with filter bypass methods by file extension. the system or application allows you to download any files, the task of getting access to the server and executing malicious code is simplified.


If during pentest, the system or application allows you to download any files, the task of getting access to the server and executing malicious code is simplified. On the other hand, if there are restrictions and the filter of downloadable files by extension, you must first bypass this check. In this article, we’ll talk about how web applications process and check files uploaded to the server, as well as workarounds for these checks.

Client-side filtering

In this case, the check is performed in the browser using JavaScript, VBScript or HTML5 before sending files to the server. Programmers use this method to optimize user interaction with the application and quickly issue a response at the browser level.

Client-side filtering bypass

Basically, this class of filters can be circumvented in two ways: by disabling JavaScript or modifying HTTP requests that are generated in the browser, before being sent to the server.


1. <script type = “text / javascript”>

2. var _validFileExtensions = [“.jpg”, “.jpeg”, “.bmp”, “.gif”, “.png”];

3. function Validate (oForm) {

4. var arrInputs = oForm.getElementsByTagName (“input”);

5. for (var i = 0; i <arrInputs.length; i ++) {

6. var oInput = arrInputs [i];

7. if (oInput.type == “file”) {

8. var sFileName = oInput.value;

9. if (sFileName.length> 0) {

10. var blnValid = false;

11. for (var j = 0; j <_validFileExtensions.length; j ++) {

12. var sCurExtension = _validFileExtensions [j];

13. if (sFileName.substr (sFileName.length – sCurExtension.length, sCurExtension.length) .toLowerCase () == sCurExtension.toLowerCase ()) {

14. blnValid = true;

15. break;

sixteen. }



19. if (! BlnValid) {

20. alert (“Sorry,” + sFileName + “is invalid, allowed extensions are:” + _validFileExtensions.join (“,”));

21. return false;






27. return true;


29. </ script>

As shown above, JavaScript processes the request before being sent to the server. Inside the code, it is checked whether the file extension belongs to the graphic format (jpg, jpeg, bmp, gif, png). This filtering method can be circumvented after changing the contents of the request and the file itself to malicious code with an extension that facilitates the execution of this code.

We were able to bypass this check by loading the image through the browser, then changing the extension in the request that will be sent to the server, as well as changing the contents of the file. We changed the extensions from .jpeg to .php and replaced the contents of the file with malicious code.

Server side check

A more thorough check of the file name occurs during upload to the server. In this case, the expansion analysis can be performed in a variety of ways, but there are two main ways: checking against black and white lists.

The black list contains file extensions that are not accepted for downloading under any circumstances, for example, php, aspx. In the case of the white list, the situation is completely opposite. This list contains only those file extensions that are allowed to be uploaded to the server, for example, jpg, jpeg, gif.

Server side inspection bypass

Some types of checks can be circumvented by downloading a file with a not very popular extension or using various tricks during the download.

In the case of a blacklist bypass, you can try to download files with the following extensions: pht, phpt, phtml, php3, php4, php5, php6.

The white list is traversed using some tricks, such as adding a blank byte to the file name (shell.php% 00.gif) or using the double extension (shell.jpg.php).

In some cases, the test can be bypassed using extensions with a modified register of one of the characters: pHp, Php, phP.


1. if ($ imageFileType! = “Jpg” && $ imageFileType! = “Png” && $ imageFileType! = “Jpeg”

2. && $ imageFileType! = “Gif”) {

3. echo “Sorry, only JPG, JPEG, PNG & GIF files are allowed.”;

The code above shows an example of a file uploader code that accepts only a few extensions (jpg, jpeg, gif). Next, we consider an example of bypassing various types of checks.

CONTENT-TYPE header check

In this method, the server checks the contents of the file for the presence of a valid MIME type, which can be seen in an HTTP request. For example, some image downloaders verify that image type is present in the Content-Type header.

Content – Type verification bypass

This filter class can be circumvented by changing the contents of the Content-Type parameter in the file shell.php or shell.aspx to a value of “image / png”, “image / jpeg” or “image / gif”.


1. <? Php


3. $ mimetype = mime_content_type ($ _ FILES [‘file’] [‘tmp_name’]);

4. if (in_array ($ mimetype, array (‘image / jpeg’, ‘image / gif’, ‘image / png’))) {

5. move_uploaded_file ($ _ FILES [‘file’] [‘tmp_name’], ‘/ uploads /’. $ _FILES [‘file’] [‘name’]);

6. echo ‘OK’;


8.} else {

9. echo ‘Upload a real image’;

10. }

In the code above, we see that the MIME type, which is part of the Content-Type header, is checked on the file uploaded to the server. In this case, the loader only accepts files with the following types: image / jpeg, image / gif and image / png. We can easily bypass this filter by changing the Content-Type field while loading the executable file to the MIME type that is received by the web server.

CONTENT-LENGTH header check

In this case, the server checks the size of the contents of the Content-Length header of the uploaded file and does not allow download of files that have this size exceeds a certain value. Although this method is not as popular, it can be used in some loaders.

CONTENT-LENGTH inspection bypass

This filter is bypassed by downloading a very small malicious code depending on the maximum value used when comparing a web server. The maximum value can be found out by downloading several files of different sizes in order to find out which files will be received and which ones will not.


1. if ($ _FILES [“fileToUpload”] [“size”]> 30) {

2. echo “Sorry, your file is too large.”;


In the code above, the loader does not accept files more than 30 bytes. As mentioned above, this filter can be circumvented by downloading very small malicious code.

Leave a Reply