> For the complete documentation index, see [llms.txt](https://0xb0b.gitbook.io/writeups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://0xb0b.gitbook.io/writeups/hack-smarter-labs/2025/hunter.md).

# Hunter

{% embed url="<https://www.hacksmarter.org/courses/19723a54-6e4b-410e-b9e3-371f702e0f5c>" %}

The following post by 0xb0b is licensed under [CC BY 4.0<img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt="" data-size="line"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt="" data-size="line">](http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1)

***

## Scenario

## Objective / Scope <a href="#user-content-objective--scope" id="user-content-objective--scope"></a>

You are an operator for the **Hack Smarter Red Team**, currently conducting a black-box assessment on a client's external login portal. As part of the initial reconnaissance phase, our OSINT analysts have compiled a list of potential usernames.

You need to identify which one is a valid username for the web application.

## Recon

We use rustscan `-b 500 -a 10.1.216.45 -- -sC -sV -Pn` to enumerate all TCP ports on the target machine, piping the discovered results into Nmap which runs default NSE scripts `-sC`, service and version detection `-sV`, and treats the host as online without ICMP echo `-Pn`.

A batch size of `500` trades speed for stability, the default `1500` balances both, while much larger sizes increase throughput but risk missed responses and instability.

```
rustscan -b 500 -a 10.1.216.45 -- -sC -sV -Pn
```

<figure><img src="/files/SbroWRsPDD5rk9bsPCmZ" alt=""><figcaption></figcaption></figure>

Like in the scope defined our target has a web server running on port `80`.

<figure><img src="/files/dvKnJ4ZSJVzXy93APcPM" alt=""><figcaption></figcaption></figure>

Next, we run a Feroxbuster scan and detect a `login` and `reset` page.

{% code overflow="wrap" %}

```
feroxbuster -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-lowercase-2.3-medium.txt -u 'http://10.1.216.45'
```

{% endcode %}

<figure><img src="/files/9LBd8LkiMw8FLsmMVXEP" alt=""><figcaption></figcaption></figure>

We visit the `login` page and try to use arbitrary credentials, but we do not receive any response of success or failure to enumerate any users here.

```
http://10.1.216.45/login
```

<figure><img src="/files/pEUl55lkxkgwDaZnDVGh" alt=""><figcaption></figcaption></figure>

We capture a `login` request using BurpSuite to identify the request made for later use in FFuF.

<figure><img src="/files/s5JCK2i3kG4a1ReyPOJq" alt=""><figcaption></figcaption></figure>

Next, we move on to the `reset` password page.

```
http://10.1.216.45/reset
```

<figure><img src="/files/4wnEdwhGWSPRPU5qe1MQ" alt=""><figcaption></figcaption></figure>

Here too, we do not receive any response to enumerate a valid user.&#x20;

<figure><img src="/files/QbiXmKbfsn3Ycm3Ue6TI" alt=""><figcaption></figcaption></figure>

We capture a `reset` request using BurpSuite to identify the request made for later use in FFuF.

<figure><img src="/files/F497AyxsPVRIwxRR56uS" alt=""><figcaption></figcaption></figure>

## Username Enumeration

Maybe we have missed something, and the response might differ with a valid user, but a wrong password. We try to log in with the usernames provided from the scenario and filter by the response size, but without success.

{% code overflow="wrap" %}

```
ffuf -w usernames.txt -u http://10.1.216.45/login -X POST -H 'Content-Type: application/x-www-form-urlencoded' -d 'username=FUZZ&passowrd=asdf' -fw 453
```

{% endcode %}

<figure><img src="/files/kfWUjlgq8ceCFsvibQD6" alt=""><figcaption></figcaption></figure>

We repeat that for the reset page, but again without success.

{% code overflow="wrap" %}

```
ffuf -w usernames.txt -u http://10.1.216.45/reset -X POST -H 'Content-Type: application/x-www-form-urlencoded' -H 'username:FUZZ' -fw 468
```

{% endcode %}

<figure><img src="/files/ZAwZeL7Ml664x1GpOsqC" alt=""><figcaption></figcaption></figure>

So what could we have overlooked? Well, when a reset is performed, it is possible that additional functions are triggered for a valid user, such as sending an email, which could lead to a delay. So we could inspect the duration the request required. With 301 usernames we could find it already in this reset attempts made using FFuF.

{% code overflow="wrap" %}

```
ffuf -w usernames.txt -u http://10.1.216.45/reset -X POST -H 'Content-Type: application/x-www-form-urlencoded' -d 'username=FUZZ'
```

{% endcode %}

<figure><img src="/files/wAthZ9IP2SKykqy6hmvL" alt=""><figcaption></figcaption></figure>

We filter for request that take longer than the usual 100 - 200ms. In this case more than 500ms and are. able to spot one request that took 1000ms for the valid user.&#x20;

{% code overflow="wrap" %}

```
ffuf -w usernames.txt -u http://10.1.216.45/reset -X POST -H 'Content-Type: application/x-www-form-urlencoded' -d 'username=FUZZ' -ft '<500'
```

{% endcode %}

<figure><img src="/files/fTYqPSaAv3fXec4Fonog" alt=""><figcaption></figcaption></figure>

## Further Reading

A comprehensive guide on user enumeration on web applications can be found here:

{% embed url="<https://www.vaadata.com/blog/user-enumerations-on-web-applications/>" %}
