> For the complete documentation index, see [llms.txt](https://ganesha-hk.gitbook.io/cybersecurity-writeups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ganesha-hk.gitbook.io/cybersecurity-writeups/port-swigger-authentication-labs/lab-3.md).

# lab-3

## Username Enumeration via Response Timing

**Difficulty:** Practitioner

### Lab Description

This lab is vulnerable to username enumeration based on response timing differences. It also implements IP-based brute-force protection, which can be bypassed by manipulating HTTP headers.

**Credentials:** `wiener:peter`\
**Wordlists:** [Candidate usernames](https://portswigger.net/web-security/authentication/auth-lab-usernames) · [Candidate passwords](https://portswigger.net/web-security/authentication/auth-lab-passwords)

**Objective:** Enumerate a valid username, brute-force their password, then access the account page.

### Solution

**Step 1 — Understand the timing oracle**

Log in as `wiener` and capture the login request. Send it to Repeater and make a few observations:

* With the correct credentials (`wiener:peter`), the response returns in roughly 290ms.
* Change the password to a 30-character string — the response time jumps significantly (600ms or more).

This happens because the server only performs password hash comparison when the username is valid. A longer password string takes more time to hash, so a slow response indicates a correct username. Invalid usernames are rejected immediately without any hashing, making all failed responses fast and uniform.

**Step 2 — Bypass IP-based brute-force protection**

The lab blocks requests after too many attempts from the same IP. This can be bypassed by adding an `X-Forwarded-For` header with a spoofed IP value — and rotating that value with each request so the server always sees a "new" IP.

**Step 3 — Enumerate the username**

Send the login request to Intruder and configure a **Pitchfork** attack with two payload positions:

* **Position 1:** The value of `X-Forwarded-For: §1§` — use a number list from `1` to `101`
* **Position 2:** The username field — use the candidate username wordlist

Set the password to a fixed 30-character string (e.g. `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`) to maximize the timing difference for valid usernames.

Start the attack. When finished, add the **Response received** and **Response completed** columns to the results view and sort by them. The username that causes a noticeably higher response time is the valid one.

**Step 4 — Brute-force the password**

Send the login request to Intruder again, this time keeping the discovered username fixed and configuring another **Pitchfork** attack:

* **Position 1:** `X-Forwarded-For: §1§` — numbers `1` to `101`
* **Position 2:** The password field — use the candidate password wordlist

Start the attack and sort by status code. A `302` redirect identifies the correct password.

### Conclusion

When error messages are identical for valid and invalid usernames, response timing can still leak information. A long password maximises the timing difference for valid accounts because the server runs a slow hashing algorithm only when the username is found. Combining this with `X-Forwarded-For` header rotation bypassed the IP-level rate limiting entirely.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ganesha-hk.gitbook.io/cybersecurity-writeups/port-swigger-authentication-labs/lab-3.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
