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 PRACTITIONER-level labs from the PortSwigger Web Security Academy:

3 Exploiting NoSQL injection to extract data

This lab demonstrates how attackers can use NoSQL injection to enumerate and extract sensitive data directly from the database by manipulating query parameters.

4 Exploiting NoSQL operator injection to extract unknown fields

This lab shows how attackers can use NoSQL operator injection to extract information from fields that are not displayed to the user by leveraging injection payloads to return hidden fields.

LAB 3 - Exploiting NoSQL injection to extract data

Lab Description :

image

Solution :

When I intercepted the request using Burp Suite, I observed a GET request to the following endpoint:


/user/lookup?user=wiener

I then sent this request to the Repeater tab for further testing and manipulation.

image

I opened the request in the original browser session and modified the parameter using a single quote ' in URL-encoded form %27.

This resulted in the following error message:

There was an error getting user details

This indicates that the input was not properly sanitized and caused a syntax error, suggesting a potential injection point.

image

I used the payload '+', which I URL-encoded as %27%2B%27, before injecting it into the parameter.

If we do not encode it properly, the application does not return the expected result.
Using the URL-encoded version ensures the payload is processed correctly by the server.

image

Then I used the payload ' && '1'=='2 to test for a false condition.
The application responded with:


Could not find user

This indicates that the condition was evaluated and returned false, confirming that server-side logic is being affected by our injection.

image

Then I used the payload ' && '1'=='1, which is a condition that always evaluates to true.

The application responded without an error, confirming that the injected condition was successfully interpreted and the logic was executed as expected.

image

Which is giving us valid result which mean this payload will work

image

Now, our goal is to retrieve the administrator user’s data.

To do this, I modified the input to target the administrator account while maintaining a condition that always evaluates to true:


administrator' && '1'=='1

This allows the application to process the request without an error and return the administrator’s information.

image

Then I used the following payload to determine the password length of the administrator account:


administrator' && this.password.length < 30 || 'a'=='b

This payload checks if the password length is less than 30.
If the response returns successfully, it confirms that the condition is true — helping us estimate the length of the password.

image

Finding the length of password :

To find the length of the password , we can use the following query

?user=administrator' && this.password.length < 30 || 'a'=='b

We can stop at <30 but since the query has a at the end, we provide the OR query ie(** || ‘a’==’a**). Note that we don’t end the equal statement with a ' because there is a trailing ' at the end of the query getting added automatically at the end.

The response shows the email of admin. It means the query is executed successfully & confirming that the password length is less than 30.

image

When we provide this.password.length < 6, the query fails & we get a failed response (“message”: “Could not find user”).

image image

So the length of admin’s password is 8.

image

After sending the above payload, we successfully received a response containing the administrator details.
This confirms that the condition evaluated to true.

So now, we proceed to find the exact length of the administrator’s password by adjusting the payload to test different lengths using the .length property in our injection.

image

Finding admin’s password -

Now we ned to bruteforce each position from 0-7 by bruteforcing it with a-z to find the password.

Modify the nosql query payload as follows.### Finding admin’s password -

Now we ned to bruteforce each position from 0-7 by bruteforcing it with a-z to find the password.

Modify the nosql query payload as follows.

image

Send the request to Intruder tab, Add the this.password[**$0$**] as payload 1 and this.password[$0$]='**$a$** as paylaod 2.

Payload 1 - Numbers from 1-10 Payload 2 - Characters from a-z

Click on start attack.

image

Now we have the admin’s password -

Login as admin to solve the lab.

image

LAB 4 - Exploiting NoSQL operator injection to extract unknown fields

Lab Description :

image

Solution :

The requirement of the lab is to exploit NoSQL injection vulnerabilities to extract invisible fields and log in to the account of the user carlos.

First, I logged in with an arbitrary account to capture the login request using Burp Suite Proxy.
This allows us to analyze the structure of the request and begin crafting injection payloads for further exploitation.

image

In the http history we can see the login request

image

We used the payload "password":{"$ne":"invalid"} to log in as the user wiener, and the login was successful.

This confirms that the application is vulnerable to NoSQL operator injection, allowing us to bypass authentication by injecting a condition that always evaluates to true.

image

However, when we used the same payload for the user carlos, the application responded with:


Account locked: please reset password

image

I used the following payload to test for NoSQL injection with a conditional time delay:

{
  "username": "carlos",
  "password": { "$ne": "invalid" },
  "$where": "sleep(5000)"
}

This payload checks if we can bypass authentication for the user carlos and simultaneously confirms that the $where clause is being executed by the database.

As expected, the server delayed its response by 5 seconds, confirming successful evaluation of the $where clause and presence of a NoSQL injection vulnerability.

image

Extracting available field names -

Send the above request to repeater.

  1. "$where": This is a key in a JSON object, and it seems to be used to define a condition or filter.

  2. Object.keys(this)[0]": This part of the expression is JavaScript code, not a regular expression. It’s using the Object.keys(this) function to get an array of keys of the current object (this), and then [0] is used to access the first key in that array. So, it’s essentially accessing the first key in the current object.

image

Set Attack Type - Cluster Bomb Payload 1 - Numbers from 0-20 Payload 2 - Simple list - a-z, A-Z, 0-9

Once the attack is over, sort Payload1 & Length to find the 1st key field which is id.

image

This time we got the value of 2nd key - username

image

image

Before bruteforcing the 4th field (which most probably is the password reset field), make sure to send a password reset link for carlos before performing the bruteforce for 4th field. Else you will get 500 Internal server error when you bruteforce.

image

image

Bruteforcing the password reset token in 4 field which we have identified above -

So where can we use the following fields which we identified? Possibly the forgot-password request.

Send the GET /forgot-password request to repeater. Add the parameter **?newpwdTkn=**.In the response, we get **Invalid token** as expected.

image

Now we need to extract the pwResetTkn (password reset token) field from the carlos account.

To do this, I used the following $where payload to brute-force the token character by character:

"$where": "this.pwResetTkn.match('^.{$$}$$.*')"

This method allows us to exfiltrate the full token through NoSQL injection with regex-based enumeration.

image

After the attack finish, we found a 16-character token.

image

Replace the found token into the request:


GET /forgot-password?pwResetTkn=...

and send it. We received a response containing the password change form.

image

Change password and login to user carlos. Complete lab.

image