2013年6月25日火曜日

SQLインジェクションゴルフ - なんと3文字で認証回避が可能に

昨日のエントリ「SQLインジェクションゴルフ - 認証回避の攻撃文字列はどこまで短くできるか?」にて、認証回避の攻撃文字列が5文字にできる(「'OR'1」)ことを示しましたが、@masa141421356さんと、やまざきさん(お二人とも拙著のレビュアーです)から、idとpwdにまたがった攻撃例を示していただきました。やまざきさんの例は、MySQL限定ながら、なんと3文字です。これはすごい。

@masa141421356さんの攻撃例

@masa141421356さんのツイートを引用します。
ここで「長さ0の文字列がNULL扱いされ」るDBというのはOracleを指します。出題ではMySQLとPostgreSQLを対象としていてどちらも「長さ0の文字列がNULL扱い」しないので、5文字パターンでいけます。すなわち、idに「'OR」、pwdに「>'」です。この場合のSQL文は下記となります。

SELECT * FROM users WHERE id =''OR' AND pwd = '>''

このままだと分かりにくいので、WHERE句の式を以下にわかりやすく示します。

id =''  OR  ' AND pwd = ' > ''

これは、列idが空文字列(長さ0の文字列)か、文字列「 AND pwd = 」が空文字列よりも大きい場合となりますので、後者が必ず真で、WHERE句は常に成立することになります。
第1のパラメータでリテラルを終端して、途中の式を文字列リテラルの中に入れてしまっていますね。これはXSSではよくやる方法ですが、SQLインジェクションに応用した例は珍しい気がします。

やまざきさんの攻撃例

次に、@ymzkei5さんのツイートです。
idに「'」、pwdに「|'」の計3文字です。この場合のSQL文は下記となります。

SELECT * FROM users WHERE id =''' AND pwd = '|''

WHERE句を分かりやすく表示すると以下の通りです。

id =''' AND pwd = ' | ''

青地の中は、「' AND pwd = 」ですね。これと '' (空文字列)とで、| (ビット単位の論理和)の演算をしています。この結果は 0 になります。
mysql> select ''' AND pwd = '|'';
+--------------------+
| ''' AND pwd = '|'' |
+--------------------+
|                  0 |
+--------------------+
1 row in set, 2 warnings (0.00 sec)
なぜ0になるかというと、MySQLは数値が要求される文脈に文字列があった場合は数値(浮動小数点数)に暗黙の型変換され、数値として正しくない文字列の場合は 0 になるからです。すなわち、| の左右のオペランドは、どちらも 0 になります。

この結果、先のSQL文は、「SELECT * FROM users WHERE id=0」と同じです。これを実行してみましょう。
mysql> SELECT * FROM users WHERE id=0;
+--------+--------+
| id     | pwd    |
+--------+--------+
| tanaka | a2f9hy |
| yamada | sn6s3n |
+--------+--------+
2 rows in set, 2 warnings (0.00 sec)
つまり、'tanaka'=0と解釈されているわけですが、MySQLの場合(他のDBもですが)、文字列と数値の比較の場合、暗黙に文字列を数値に変換してから比較します。そして、MySQLに限り、数値に変換できない文字列は 0 に変換するからです。この結果、'tanaka' = 0 は真になります。
やまざきさんの解は、MySQLの「暗黙の型変換」の仕様を巧妙に利用したものと言えます。

まとめ

昨日紹介したSQLインジェクションゴルフの解答例として、@masa141421356さんとやまざきさんの解答を紹介しました。どちらの解も、SQL文の一部を文字列リテラルに閉じ込めるという技を披露してくださっていて、興味深いものです。特に、やまざきさんの3文字解には脱帽です。
同時に、あらためてSQLの暗黙の型変換は危険だなとも思いました。暗黙の型変換の危険性については、以前の拙稿「SQLの暗黙の型変換はワナがいっぱい」を参照下さい。

0 件のコメント:

コメントを投稿

フォロワー