Skip to main content

🗂️PortSwigger Lab Writeup: Web Shell Upload via Race Condition

PortSwigger lab banner showing race condition in file upload validation


🎯 Objective

The objective of this lab is to exploit a file upload vulnerability where the app has a vulnerable image upload function which can be exploited using a race condition. The goal is to upload a basic web shell and exfiltrate the contents of file /home/carlos/secret

  • Lab URL: https://portswigger.net/web-security/file-upload/lab-file-upload-web-shell-upload-via-race-condition
  • Category: File Upload
  • Difficulty: Expert

🧪 Exploitation Steps

🕵️Step 1: Observe the Website

  • Firstly open the lab URL in your browser, and observe what it is about and how it works. Blogging website homepage displaying blog posts and navigation menu
    Login page interface with username and password fields
  • At first glance, the website seems to be a blogging website with a login page. In the lab description, it is mentioned that we need to exfiltrate the secret of carlos.

📝Step 2: Upload the payload

  • First login with the given credentials - wiener:peter to access file upload function. Login page with wiener credentials
  • Now, we can see the file upload function where we can upload an avatar of the user. User profile page with file upload form for avatar image
  • Make basic php web shell named payload.php with the given code:
    <?php echo file_get_contents('/home/carlos/secret'); ?>
  • Now, Upload this payload. File upload dialog showing payload.php file selected for upload
  • You will notice that the request was rejected as only jpg & png files are allowed to upload. Upload rejection message showing only image file extensions are permitted
  • However, it is mentioned that there is a race condition where our uploaded file is stored on server for some time before validating it.
  • We will use this little time of validation to execute our payload.
  • Now, first go to account page and open the current uploaded avatar in new tab.
  • Currently it will give 404 Not Found error.
  • Now, Open the HTTP History in Burpsuite and send both the POST /my-account/avatar and GET /files/avatars/payload.php requests to Repeater tab. Burp Suite Repeater showing grouped POST and GET requests for race condition exploitation
  • Now, Group both the tabs and set the send type to parallel.

🧑‍💼Step 3: Access the Secret

  • Now, send the group request multiple times and in one of responses you will get the secret of carlos. Burp Repeater response showing successful execution of payload.php during race condition window
  • Now, Copy the secret and submit it to complete the lab. Lab solved confirmation message after submitting correctly extracted secret
  • And Finally, the Lab is solved.

🧠 Conclusion

  • This lab exploited a race condition where the server stores uploaded files before validating them, creating a time window where executable code exists on disk. By sending parallel requests, the payload was executed before validation rejected it.
  • The impact is critical — attackers can execute arbitrary code by exploiting timing gaps in file validation, defeating synchronous validation approaches.
  • Fix: validate files before storing them, use atomic operations (reject then delete), implement strict timeouts, and store uploads outside the webroot with no execute permissions.