Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
SQLインジェクション
自己紹介
 セキュリティエンジニアやってます。
 脆弱性診断業務を担当しており、専門はWebセキュリティです。
 趣味で脆弱性の検証したり、最近はCTFイベントなどに参加して
たりします。
TwitterID: tigerszk
本題に入るその前に
脆弱性診断って?
FW Webサーバ
診断環境 診断対象システム
Webアプリ
NW機器
診断対象のシステムに対して、疑似攻撃を試行し、対象システム
の挙動から脆弱性の存在有無を調査します。
※ちなみにこれはブラックボックス型と呼ばれる手法で、他に設計書、仕様書、コンフィグ
ファイル、ソースコードなどを精査することで、脆弱性を検出するホワイトボックス型と呼ば
れる手法もあったりします。
Internet
疑似攻撃
×
×
診断員
診断の種類
OS
ミドルウェア
Webコンテンツ Webアプリケーション診断
ネットワーク診断
(プラットフォーム診断)
Webシステム
なお、対象にする領域によって実施する診断の種類が違ったりします。
今回はWebアプリケーション診断についてお話します。
30秒でわかるWebアプリケーション診断
通常のWebサーバとの通信
<html>
<body>
<form action=“register” method=“POST”>
氏名:vultest<BR>
メールアドレス:vultest@example.jp<BR>
性別:男<BR>
(以下略)
</html>
POST /confirm.php HTTP/1.1
Host: example.jp
(以下略)
Cookie: PHPSESSID=xxxxxxxxxx
name=vultest&mail=vultest%40example.jp&gender=1
HTTP Response
HTTP Request
色々いじってみてどういう応答があるか確認
POST /confirm.php HTTP/1.1
Host: example.jp
(以下略)
Cookie: PHPSESSID=xxxxxxxxxx
name=vultest&mail=vultest%40example.jp”>xss&gender=1
<html>
<body>
<form action=“register” method=“POST”>
氏名:vultest<BR>
メールアドレス:vultest@example.jp”>xss<BR>
性別:男<BR>
(以下略)
</html>
HTTP Response
HTTP Request
じゃあパラメータ値で
こんなの送ったらどう
なるの?
おお!出力時に「”」,「>」が
エスケープされてないね。
XSSあるんじゃね?
基本的にはこれを様々なパターンでひたすら繰り
返し行う苦行です。
以上。
※厳密いえばもっと他にも色々な作業があります。
ツールとかも使います
当たり前ですが、全部手動でやっていたら死亡するので、ある程度
自動的に検査可能な項目はツールやスクリプトなどを利用してます。
ただ、ツールを使う場合にはちょっとしたコツが必要だったりします。
【Webアプリケーション診断における診断の大前提】
正確に診断を実施するためには値改変前のリクエストについては、ちゃんと正常遷
移するリクエストである必要があります。
【サイトの特性や機能に合わせたツールのチューニングが必要】
診断時には通信内容などを解析して、検査時に正常遷移時のリクエストを再現できるように
色々設定や工夫をしてやる必要があります。
チューニングが必要となる機能の例:
登録データの削除処理、重複登録不可の画面、全画面でトークンの値をチェックしている、etc…
※これについての詳しい話は長くなるのでまた別の機会にでも、、、
必須アイテム
手動での診断作業や通信解析時にはローカル
Proxyを非常に良く利用します。
HTTP Response
HTTP Request
HTTP Response
HTTP Request
ローカルProxy
ブラウザからの通信をローカルProxyを経由させることで下記が可能
です。診断だけじゃなく問題の切り分けとかにも非常に便利です。
通信内容の詳細を確認可能
通信内容を編集して送信することも可能
お勧めのローカルProxyツール
Burp Suite
http://portswigger.net/burp/
OWASP ZAP
https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project
Fiddler
http://www.telerik.com/fiddler
※ちなみにこれらのツールはMan In the Middle(中間者攻撃)的な方法で
HTTPSの通信にも対応しています。
診断する時の注意点
セキュリティ診断を円滑に実施するためには担当者に対して以下の
ような注意事項の説明など、事前調整を入念に行う必要があります。
(※これ超重要)
調整事項の例
 診断による影響についてちゃんと担当者に事前に説明する。
Webアプリケーション診断は検査対象のWebサーバに通信を行い実際にアプリケーションを動作させて
行います。そのため以下のような事象が発生する可能性があります。
• DBへの大量のダミーデータの書き込み
• 大量のメール送信
• アプリケーションの作りによっては、本来意図しない動作の発生
…etc
上記のようなことが、発生する可能性があるため、担当者の方には事前にテスト環境での診断
実施&診断前のデータバックアップなどをお願いしています。
 ホスティング環境やクラウド環境を利用している場合には、あらかじめインフラ提供者側に対して
診断実施をしてよいかの確認をしてもらう。(絶対勝手にやらない)
 IDSやIPSなどで監視している場合には、診断時の通信を非監視にしてもらうようにお願いする。
はい!ここからが本題
「とある診断員」のお話が始まります
こんな条件の診断だった
昔々、ある所にまだ駆け出しのとある診断員がいました。
その診断員はある時以下のような条件のWebサイトを診断しました。
 診断対象は本番環境だった。
※もちろんとある診断員は事前に注意点を入念に説明し、テストサイトで
の実施を勧めたが、「そんなもんねえから本番でやって」と一蹴された。
 パッケージ利用とかではなく、自作のECサイトだった。
 いわゆるLAMP環境で開発されたアプリだった。
(CENTOS,Apache,PHP,Mysql)
かなり前に作られていたこともあり、どうやらあまり(というか全然)セキュリティ
を考慮して作られていないサイトのようでした。
診断途中の段階で既にかなり多数の脆弱性が見つかっており、かわいそうな
診断員はヒイヒイ言いながら診断をしていました。
突然アカウントが利用できなくなった
とある診断員は一生懸命頑張って診断していましたが、ある日突然、診断に
使っていたアカウントでログインできなくなりました。
診断員:
「あれ?アカウントロックでもされたのかな?でもログイン処理とかまだ診断して
ないけど、、、」
真面目な診断員はすぐに担当者に連絡しました
診断員:
「テスト用のアカウントでなんかログインできなくなったようなので、確認してもら
えないですか?ロックされてしまったかもしれないです。」
担当者:
「了解しました。確認します。」
すると暫くした後、担当者から連絡がきました。
その時事件は起きた(いや起こってた)
担当者:
「か、、、確認したんですが、パ、、、パスワードが、、、
診断員:
「( ゜Д゜)」
全ユーザのパスワードが初期化されてます!!」
\(^o^)/
そりゃ当然こんな感じになるよね
周りの人は目を合わせてくれない、、、
その時、不思議にも周りの人たちの心の声が聞こえた。
「あいつはもう駄目だ。今近寄ったら巻き込まれる。」
こんな感じの扱いだった
最終的には
かくして孤独な戦いが始まった
とある診断員は、危うく全ユーザの強制パスワード定期変更執行者となってし
まうとこでしたが、幸いなことに担当者側で、診断事前にDBのバックアップは
取得していたので、取り急ぎ切戻しを行い最悪の事態は回避しました。
その後の調査で、パスワードがリセットされた時間帯に、他メンテナンス作業が
なかったことや、アクセスログなどの状況から本件の原因が診断にあることは
どうやら間違いなさそうでした。
診断作業は一時中断され、作業の再開と原因究明のために、速攻でテスト環
境が構築されました。
そんなに早くできるなら最初からテスト環境で、、、
かくして、とある診断員の自分が引き起こしたインシデント調査が始まりました。
実は正直大体見当はついていた
とある診断員は、その日ちょうどパスワードリマインダ機
能をツールで診断していました。しかも診断結果の精査
前だったが、とある脆弱性を検知していました。
とあるパスワードリマインダの仕様
1. ユーザのメールアドレス(アカウントID)と登録された誕生日を入力して値を照合する。
2. その後値が正しければ、入力されたメールアドレス宛にリセットされたパスワード文字列
が送信される。
※このリマインダの仕様自体に色々ツッコミ所もあるかと思いますが、まあそれはこの際、
置いといてください。
← こんな感じ
おそらく原因は、、、
この事象のトリガーとなった原因はこの機能にある
「SQLインジェクション」
の脆弱性なんだろうなとあらかじめ想定していました。
SQLインジェクションって?
例えばこんなWebアプリあったとします
 会員制ECサイトの商品検索ページ的なもの
 値段や名前を条件として検索が可能
 条件にマッチした商品名を画面に表示するだけの機能
通常のアプリの処理の流れ
Webサイト側の内部処理
パラメータ値などが含まれた問い合わせを
Webサイトに要求する
価格が100円の商品を検索
http://exmple.jp?cost = 100
Webアプリケーション データベース
受信したパラメータ値からSQL文(データベースへの命令
文)が組み立てられデータベースに命令を送信
SELECT name FROM goods WHERE cost = 100 ;
データベース内でSQL文が実行された結果
が返る
SQL文の実行結果を元にアプリケーション側で生成されたHTTPレスポン
スの内容がサーバからの応答として返る
「価格が100円の商品は下記です。缶コーヒー、ガム、アメ」と表示する
HTML
<html><body>…..
サイト利用者
HTTP通信
HTTP Request
HTTP Response
SQL命令
①
②
③
下記は検索ボタンを押してから検索結果がブラウザに表示される
までの処理の流れのイメージです。
④
name
缶コーヒー
ガム
アメ
SQLインジェクション攻撃
Webサイト側の内部処理
ユーザ情報を削除するようなSQL文を構成するような文字列を
パラメータ値に入力して送信する
http://exmple.jp?cost=100; DELETE FROM users
脆弱な
Webアプリケーション データベース
受信した値からパラメータ値からSQL文が組み立てられデータ
ベースに命令を送信される。
この時、パラメータ値として入力した文字列の一部がそのまま
SQL文として解釈され実行される。
これにより本来意図しない命令がデータベースで実行されてし
まう。
SELECT name FROM goods WHERE cost = 100 ;
DELETE FROM users ;
攻撃者
HTTP通信
HTTP Request
HTTP Response
発生しうる脅威
 データベースに蓄積された非公開情報閲覧、改ざん、消去
 認証回避による不正ログイン
 ストアドプロシージャ等を利用したOSコマンドの実行
ユーザ情報
を削除
SQL命令
脆弱な作りのWebアプリケーションの場合、SQL文の断片を含んだ不正なHTTPリクエストを
送信されることによって、外部からデータベースを操作されてしまう。
どうやって直せばよいの?
Webアプリケーション開発時に脆弱性を作りこまないよう
なコーディングをする必要があります。
SQLインジェクションの根本的対策
1. SQL文の実行方式にPrepared Statement(準備済みの命令文)を利用する。
2. SQL文の特殊記号となりうる入力値が存在しないか確認し、存在した場合
はエラーとするか適切なエスケープ処理を施す。(特殊文字はDBMSごとに異
なるのでそれぞれの環境に合わせた対策が必要。)
※詳細については徳丸本や「安全なSQLの呼び出し方」を参照するのが良いと思
います。
SQLインジェクションの見つけ方の例-その1-
SQL文の断片を送信して、レスポンスにSQLエラー(DBMS等が
出力するエラーメッセージ)が出力されるか確かめたりする。
SELECT * FROM member WHERE name = 'tanaka';
 通常時
送信値:tanaka
構成されるSQL文
検索結果:1件
田中
SELECT * FROM member WHERE name =''';
 検査時
送信値:'
構成されるSQL文 SQL error
SQLインジェクションの見つけ方の例-その2-
送信した値ごとの応答結果の差分を見て判定したりもする。
SELECT * FROM member WHERE name = 'tanaka' AND 'a' = 'a';
 条件式が真
送信値:tanaka' AND 'a' = 'a
構成されるSQL文
検索結果:1件
田中
SELECT * FROM member WHERE name = 'tanaka' AND 'a' = 'b';
 条件式が偽
送信値:tanaka' AND 'a' = 'b
構成されるSQL文
検索結果:0件
なし
SELECT * FROM member WHERE name = 'tanaka' BND 'a' = 'a';
 文法として逸脱しているもの
送信値:tanaka' BND 'a' = 'b
構成されるSQL文 エラー
送信すると危険な文字列がある
SQLインジェクションの脆弱性があった場合、挿入する文字列に
よっては、本来実行を意図しているSQL文の意味が変わってしま
い大変なことになる場合があります。
※先日楽しく拝見させていただいたabendさんのスライドから画像を拝借してきましたw
これから書こうとしていることと全く同じことについてスライド内で言及されてます。
フリーでできるセキュリティWeb編(SQLMapを楽しもう)」
http://www.slideshare.net/abend_cve_9999_0001/websqlm
例えばor条件だと
UPDATE member SET password = 'xxxx' WHERE id = 1;
 本来の意図する処理
受け渡す値:1
UPDATE member SET password = 'xxxx' WHERE id = 1 OR 1 = 1;
カラム名「id」が1の値となっているレコードのみ、カラム名
「password」の値をxxxxに更新する
 or条件のSQL文の断片を渡した場合
受け渡す値:1 OR 1 = 1
全てのレコードのカラム名「password」の値をxxxxに更新するこ
とになってしまう!
複文もヤバい場合がある
UPDATE member SET password = 'xxxx' WHERE flag = 1 AND id = 1;
 本来の意図する処理
受け渡す値:1
カラム名「flag」が1の値かつカラム名「id」が1の値となっているレ
コードのみ、カラム名「password」の値をxxxxに更新する
 複文となるSQL文の断片を渡した場合
受け渡す値: 1; SELECT 1;--
カラム名「flag」が1の値となっている全てのレコードのカラム名
「password」の値をxxxxに更新することになってしまう!
UPDATE member SET password = 'xxxx' WHERE flag = 1; SELECT 1;-- AND id = 1;
でも、、、そういうのは送信していないはず
SQLインジェクションに限ったことではないですが、
通常セキュリティ診断時に送信されるシグネチャ
(検査文字列)は、なるべく検査対象に影響を与
えないようにするものを利用するように配慮して
いたつもりでした。
とある診断員はその時自分が利用していたツー
ルでは、当然さっきのような危険と思われるSQL
文のシグネチャなどは送信していない認識でした。
では何故こんなことが起きた?
なんとかログから答えを割り出した
その後、とある診断員は診断時のHTTP通信のログ(※)
などを頼りに、色々頑張って該当の時間帯にトリガーと
なったと想定される文字列を割り出しました。
※ちなみにこういう時のために普段から診断時のログは必ず全部取得するよ
うにしてます。
それは「 '+' 」という値だった。
やっぱりSQLインジェクションの診断が原因
メールアドレスを入力するパラメータに以下のような値
を追加した場合に、他ユーザのパスワードがすべてリ
セットされる事象が再現しました!
送信したパラメータ:aaa@vultest.com'+' や aaa@vulte'+'st.com など
ちなみにこの文字列の本来の用途
SQLインジェクションのシグネチャの一つで、SQL文における文字
列連結演算子を送信して応答結果から脆弱性があるかどうかを
判断するためのもの。ツールには「 '+' 」や「 '||' 」などの文字列を
送信するシグネチャが存在した。
ちなみに文字列連結演算子はDBMSごとに異なります。
|| Oracle, DB2, Postgre等
+ SQL Server, Sybase等
スペース、CONCAT() MySQL
SELECT * FROM member WHERE name = 'tan'+'aka';
 SQLインジェクションが存在する場合
送信値: tan'+'aka
構成されるSQL文
検索結果:1件
田中
挿入した文字列連結演算子がSQL文にて評価されている場合に脆弱性として検出
この事件の真相(推測)
まずはこちらをご覧ください
MySQLでSQL文を実行しています。
上記のSQL文を実行した場合には、vultestテーブルの内容が全部表示されています。
このようなSQL文の場合には当然ですが、vultestテーブル中のカラム名「id」の値が
aaa@vultest.comと等しい1レコードが返ります。
MySQLではこう解釈される
問題となっている「'+'」を含んだSELECT文をMySQLで実行するとなんと全件のレコードが
返ってきてしまいます!
WHERE句の中身をわかりやすく表示してみると、'aaa@vultest.com'+''の結果が0となって
います。
理由はMySQLの「暗黙の型変換」
MySQLの文字列連結演算子はスペースやCONCAT()関数です。MySQLでは「+」記号は、
数値の和算として解釈されます。
MySQLは数値が要求される文脈に文字列があった場合は数値(浮動小数点数)に暗黙
の型変換されます。数値として正しくない文字列の場合は 0 になるそうです。
そのため下記のように判定されたと判断しています。
この結果WHERE句についてはid = 0となりますが、idカラムは文字列なので、また暗黙の
型変換が行われてから比較されます。その結果、idカラムの値が数値に変換できない文
字列の場合は0に変換されるため条件が真となり、全件のレコードが該当してしまうと思
われます。
※以下の徳丸さんのブログに「暗黙の型変換」についてのわかりやすい解説があり参考
にさせていただきました。
「SQLインジェクションゴルフ - なんと3文字で認証回避が可能に」
http://blog.tokumaru.org/2013/06/sql-injection-golf-3-letters-bypass-login-authentication.html
「SQLの暗黙の型変換はワナがいっぱい」
http://www.tokumaru.org/d/20090924.html
'aaa@vultest.com'+'' ⇒ 0 + 0 ⇒ 0
アプリ側で生成されるSQL文について
リマインダ機能で生成されるSQL文について下記のような推測をしました。
1. 入力値(メールアドレスと誕生日)の照合とパスワードの更新はそれぞれ別のSQL文だった
のではないか。
2. SELECT文でなんらかの結果が返ってきた場合に、UPDATE文を実行するような感じだった
のではないか。
3. UPDATE文のWHEHE句はSELECT文の実行結果を利用したわけではなく、リマインダで入力
したメールアドレスのパラメータ値が使われたのではないか。
SELECT * FROM member WHERE id = 'test@vultest.com' AND birthday = 1999523;
UPDATE vultest SET password = 'リセットするパスワード値' WHERE id = 'test@vultest.com';
 実行されるのはこんなSQL文だったのではないだろうか?
例えばリマインダ機能で下記のような値を入力した場合
メールドレス:test@vultest.com 誕生日:1999年5月23日
メールアドレスと誕生日の値が一致するユーザがいるか検索
該当するメールアドレスのユーザのパスワードを初期化
そうであればこうなる
SELECT * FROM member WHERE id = 'test@vultest.com'+'' AND birthday = 1999523;
UPDATE member SET password = 'リセットするパスワード値' WHERE id = 'test@vultest.com'+'';
下記値をリマインダ機能で入力した場合
メールドレス:test@vultest.com'+' 誕生日:1999年5月23日
カラム名「birthday」の値 が1999523に該当するユーザのレコードが検索結果として返る
結果、全ユーザのパスワードが初期化される
 メールアドレスと誕生日の値が一致するユーザがいるか検索
 該当するメールアドレスのユーザのパスワードを初期化
※試しに同様の動きをするWebアプリを作ってみましたが、見事に再現されましたw
ちなみにこっちも注意
MySQLの場合には「'+'」だけではなく「'||'」も気をつけなくてはなら
ない。
MySQLでは「||」は論理和として解釈されてしまい、なおかつ同様
に暗黙の型変換が行われるためこちらもMySQLを対象とした診
断では危険なので使わないほうが良い。
※
実はこの二つのシグネチャの危険性については下記のブログで随分前に指摘されていたの
にとある診断員はこの件が起こった後に気づきました。。。(読んでたのにorz...)SQLイン
ジェクションの検出方法についてすごく詳細な記載があるので興味がある方は必見です!
T.Teradaの日記 自作検査ツール - SQLインジェクション編
http://d.hatena.ne.jp/teracc/20090531
また、またまたabentさんの「Webアプリって奥が深いんです。」でMySQL での「||」の危険性に
ついて詳しく検証されていますので詳しくはそちらを参照ください。
「Webアプリって奥が深いんです。」
http://www.slideshare.net/abend_cve_9999_0001/web-22186183
まとめ
MySQLの暗黙の型変換は怖い
セキュリティ診断に限ることではないけどやっぱり事前
の調整って重要だよね!
そもそもSQLインジェクションの脆弱性がなければこん
な悲劇は起こらなかったわけなのでちゃんと対策しま
しょう。
とある診断員の戦いはその後も続く

More Related Content

とある診断員とSQLインジェクション

Editor's Notes

  1. 7
  2. 8
  3. ENT