[This lab](https://portswigger.net/web-security/authentication/password-based/lab-username-enumeration-via-response-timing) demonstrates a real-world authentication weakness involving **response timing differences**. The login mechanism leaks information about whether a username is valid based on **how long the server takes to respond**. Additionally, the app includes **IP-based rate limiting**, which can be bypassed using the `X-Forwarded-For` header.
The attack combines three techniques:
1. **Timing-based enumeration**
2. **Brute-force protection bypass**
3. **Credential brute-force**
##### Step-by-Step Exploitation
---
#### 🧪 Phase 1: Setup + Confirm Behavior
1. **Log in with invalid credentials**
- Go to `/login`, submit:
```
username=invaliduser
password=invalidpass
```
2. **Send the request to Burp Repeater**
3. **Add header to bypass IP blocks:**
```
X-Forwarded-For: 127.0.0.1
```
4. **Try your own valid credentials (wiener:peter) with a long password**
- Observe **increased response time** vs invalid usernames
![[CleanShot 2025-05-07 at 12.59.19.png]]
---
#### 🎯 Phase 2: Username Enumeration via Timing
1. **Send request to Burp Intruder**
2. **Set attack type:** `Pitchfork`
3. **Add two payload positions:**
- One on `X-Forwarded-For: §IP§`
- One on `username=§user§`
4. **Payloads setup:**
- **Position 1 (IP spoof):**
- Payload type: Numbers (1 to 100, step 1)
- This bypasses the rate limit
- **Position 2 (Usernames):**
- Add the **candidate username list** provided by the lab
5. **Set password to a long string (~100 characters)** to amplify timing difference
6. **Start the attack**
7. **After attack completes:**
- Go to `Columns → Show: Response Received`, `Response Completed`
- Sort by **response time**
- Identify which username consistently takes **longer to respond**
✅ That’s your valid username
![[CleanShot 2025-05-07 at 13.04.39.png]]
---
#### 🔓 Phase 3: Password Brute-Force
1. **Create a new Intruder attack on the same login request**
2. **Use `Pitchfork` again**
3. **Payload positions:**
- `X-Forwarded-For: §IP§`
- `password=§pass§`
- Set discovered user
4. **Payloads setup:**
- **Position 1:** Numbers 1–100 (IP spoof again)
- **Position 2:** Paste candidate password list
![[CleanShot 2025-05-07 at 13.07.06.png]]
5. **Start the attack**
6. **In results:**
- Look for response with `302 Found` or length/status difference
✅ That’s the correct password
![[CleanShot 2025-05-07 at 13.06.53.png]]
---
#### 🔐 Phase 4: Log In and Solve the Lab
- Go to `/login`
- Log in as:
```
Username: [discovered-username]
Password: [discovered-password]
```
- Access `/my-account` to solve the lab.
---
##### Why It Works
- The app uses **timing behavior** (e.g., password hashing or user lookup) that varies for valid vs. invalid usernames.
- IP rate limiting is done using actual IPs, but the app **trusts `X-Forwarded-For`** headers — allowing spoofing.
- This allows attackers to perform **unrestricted brute-force** using fake IPs.
---
##### Real-World Takeaways
- Timing attacks can leak valid usernames even when error messages are generic
- IP-based rate limits can be bypassed if the app trusts unvalidated headers
- Side channels like response time, status code, and content length are **powerful tools** for breaking auth