Single-endpoint race conditions | September 8, 2023
Table of Contents
Welcome to my another writeup! In this Portswigger Labs lab, you’ll learn: Single-endpoint race conditions! Without further ado, let’s dive in.
- Overall difficulty for me (From 1-10 stars): ★★☆☆☆☆☆☆☆☆
This lab’s email change feature contains a race condition that enables you to associate an arbitrary email address with your account.
Someone with the address
firstname.lastname@example.org has a pending invite to be an administrator for the site, but they have not yet created an account. Therefore, any user who successfully claims this address will automatically inherit admin privileges.
To solve the lab:
- Identify a race condition that lets you claim an arbitrary email address.
- Change your email address to
- Access the admin panel.
- Delete the user
You can log in to your own account with the following credentials:
You also have access to an email client, where you can view all emails sent to
Solving this lab requires Burp Suite 2023.9 or higher.
In here, we can purchase some items.
Login as user
In the profile page, we can update our own email address.
Try to update it:
Burp Suite HTTP history:
When we clicked the “Update email” button, it’ll send a POST request to
/my-account/change-email, with parameter
After that, it’ll show a message that telling us go to our email to confirm the change of e-mail.
- Confirm link endpoint:
Click on it:
Refresh our profile page:
In the confirm link endpoint (
/confirm-email), it has 2 GET parameters -
Hmm… What if I can retrieve
email@example.com’s confirm email token via race condition, more specially, it’s single-endpoint race condition…
Sending parallel requests with different values to a single endpoint can sometimes trigger powerful race conditions.
Consider a password reset mechanism that stores the user ID and reset token in the user’s session.
In this scenario, sending two parallel password reset requests from the same session, but with two different usernames, could potentially cause the following collision:
Note the final state when all operations are complete:
session['reset-user'] = victim
session['reset-token'] = 1234
The session now contains the victim’s user ID, but the valid reset token is sent to the attacker.
For this attack to work, the different operations performed by each process must occur in just the right order. It would likely require multiple attempts, or a bit of luck, to achieve the desired outcome.
Email address confirmations, or any email-based operations, are generally a good target for single-endpoint race conditions. Emails are often sent in a background thread after the server issues the HTTP response to the client, making race conditions more likely.
Since we don’t have control over the
firstname.lastname@example.org email address, we could try to exploit single-endpoint race condition to read/overwrite
carlos’s email confirm token.
Now, what if there’s no session cookie in the
/my-account/change-email POST endpoint?
As you can see, it redirected us to the login page. Which means the change email function is tied to our session.
Next, we can try to change email address to
email@example.com and the test one in the normal way:
As expected, we can only read the test one confirm email.
Now, what if I send those requests in parallel?
Oh! We won the race! Let’s click the confirm email link!
Then refresh our profile page:
Nice! We now have administrator privilege!
Let’s delete user
What we’ve learned:
- Single-endpoint race conditions