[Exploit the reset](https://portswigger.net/web-security/race-conditions/lab-race-conditions-exploiting-time-sensitive-vulnerabilities) flow so that **wiener** and **carlos** get the **same password-reset token**. Use the token you receive to reset **carlos**.
Then log in as **carlos**, open **Admin**, delete **carlos**.
---
## Threat model (mental model in one minute)
* Reset link: `/forgot-password` → email with `?username=<user>&token=<digest>`.
* Token is a **fixed-length digest** derived from **time-dependent state** (e.g., timestamp) + possibly other static inputs.
* Backend is **per-session locked** (e.g., PHP): one request at a time **per session**, but **not across sessions**.
* If two **different sessions** trigger reset **at the same instant**, both users are assigned **identical token** (timestamp dominates digest; username likely excluded).
* You see the email for **wiener**. You **swap `username=wiener` → `username=carlos`** in the URL and redeem the same token to reset **carlos**.
## Step-by-step
### 1) Establish baseline
1. Log in as `wiener:peter`.
2. Trigger **Forgot password** for `wiener`.
3. Observe email: `.../reset?username=wiener&token=<hex>`
4. Send `POST /forgot-password` to **Repeater**. Send it **several times** → tokens differ each time → digest has changing input (likely time).
### 2) Show per-session lock (requests serialized)
1. Duplicate the `POST /forgot-password` tab. Group the two tabs.
2. **Send in parallel** a few times (same session cookie).
3. Note responses still spaced out; tokens differ. ⇒ The app serializes **per session**.
### 3) Bypass session lock (use a new session)
1. Send `GET /forgot-password` **without** cookies in Repeater.
2. From the response, copy the **new session cookie** (and **CSRF** if present).
3. Replace cookie (+ CSRF) **in one** of your two `POST /forgot-password` tabs.
* Result: you now control **two independent sessions**:
* **Tab A**: Session A (original), body: `username=wiener`.
* **Tab B**: Session B (new), body: `username=wiener`.
4. **Send in parallel** multiple times. Response times now often **match** or are very close.
### 4) Confirm timestamp-based collision
1. Watch the inbox for pairs when the two responses matched in time.
2. You should eventually see **two emails** with **the same `token`** (for `wiener`).
* This proves **timestamp** (or equivalent) is the dominant entropy in the digest.
### 5) Execute the takeover
1. In **one** of the two tabs, change body to `username=carlos` (keep the two different sessions):
* **Tab A** (Session A): `username=wiener`
* **Tab B** (Session B): `username=carlos`
2. **Send in parallel** repeatedly until the pair lands in the same tick (you’ll only see **one** fresh email—inbox for wiener—because you don’t see carlos’ mailbox).
* That single email implies **both users got the same token**.
3. Open the latest email you got for **wiener**. Copy the reset URL and **edit the query**:
* Change `username=wiener` → `username=carlos`
* Keep `token=<unchanged>`
4. Visit the edited URL. You should land on **Reset Password** for **carlos**.
5. Set a new password for **carlos**.
6. Log in as **carlos** → open **Admin** → delete **carlos**. Done.
---
## Repeater specifics (make it bulletproof)
### Request templates (adjust to your lab)
**GET (to mint a fresh session & CSRF)**
```http
GET /forgot-password HTTP/2
Host: LAB.HOST
Accept: text/html
```
*(Response sets `Set-Cookie: session=...` and shows a CSRF token if used.)*
**POST (trigger reset)**
```http
POST /forgot-password HTTP/2
Host: LAB.HOST
Cookie: session=SESSION_VALUE
Content-Type: application/x-www-form-urlencoded
Accept: */*
csrf=CSRF_VALUE&username=wiener
```
* Duplicate to create **two tabs**. Replace cookie/CSRF **in ONE tab** with values from the **cookie-less GET** response so you truly have **two sessions**.
* When attacking, switch one `username` to **carlos**.
### Parallel send tips
* Use **Send group → Parallel**.
* Run **several times**; the match is probabilistic (depends on server tick/clock granularity).
* If you see two different emails each time, re-mint the second session cookie (new `GET /forgot-password` without cookies) and try again.
---
## Troubleshooting (fast)
| Symptom | Likely cause | Fix |
| ---------------------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------- |
| Two parallel posts still look serialized | You reused the same session | Ensure **different session cookies** (and CSRF) across the two tabs |
| Always two different tokens | Requests not landing in same time tick | Fire parallel repeatedly; reduce local jitter; warm the connection once with a `GET /` |
| CSRF errors | Mixed/expired tokens | Refresh both forms; pair **each session’s** CSRF with its cookie |
| Edited URL gives “invalid token” | Typo or URL encoding | Copy full token exactly; change only `username=` |
| Reset page still shows wiener | You didn’t edit the URL param | Ensure `username=carlos` in the query string |