読者です 読者をやめる 読者になる 読者になる

WordPress のsecurity系plugin の Blind SQL injection 脆弱性(CVE-2015-0894) "&'<<>\ Advent Calendar 2015 (13日目)

脆弱性

この記事は脆弱性"&'<<>\ Advent Calendar 2015の13日目の記事です。

前日の記事は mage ctf writeup: CVE-2015-0893です。今日は連続してCVE-2015-0894です。

脆弱性内容

JVN#30832515: WordPress 用プラグイン All In One WP Security & Firewall における SQL インジェクションの脆弱性

WordPressのpluginをいろいろ見て回っていた時期に見つけたやつで、IPAに昨年末に届け出をし、今年の3月に修正版が出ました。Wordpressのpluginはsecurity系pluginにも脆弱性が、という話をTLで見たことがありまして実際に探したら見つけてしまいました。

実際のコードです。

$events_table = AIOWPSEC_TBL_EVENTS;
if (is_array($entries)) {
     //Delete multiple records
     $id_list = "(" . implode(",", $entries) . ")"; //Create comma separate list for DB operation
     $delete_command = "DELETE FROM " . $events_table . " WHERE id IN " . $id_list;
     $result = $wpdb->query($delete_command);

クエリ文字列を動的に組み立ているあたりで嫌な感じはするのですが、$entriesの中身がどこでエスケープされているのかはパッと見ではよくわかりません。仕方なく$entriesを追っていくとリクエストのクエリパラメータの値がそのまま入っていましたので、SQLiできました。

そしてもう一種。

$orderby = !empty($orderby) ? mysql_real_escape_string($orderby) : 'login_date';
$order = !empty($order) ? mysql_real_escape_string($order) : 'DESC';

$data = $wpdb->get_results("SELECT * FROM $login_activity_table ORDER BY $orderby $order LIMIT 5", ARRAY_A); //Get the last 50 records

orderbyとorderにつかう文字列をクエリパラメータから受け取っています。一見mysql_real_escape_stringでエスケープされているように見えますが、この関数はPHP5.5.0から非推奨な上に数種の特殊文字をエスケープしてくれるだけで、空白や()などはエスケープされません。

どちらの箇所もログインして管理者画面から操作しなければ実行されません。しかし、リクエストのクエリパラメータを受け取るため、ログイン中のユーザをうまく誘導してやれば任意のSQLを実行させることができます。 実行はできても、攻撃者は直接レスポンスを受け取れませんが、Blind SQL injection、つまりsleep関数などをうまく使ってやれば時間はかかりますがDB中のデータを抜き出すことが可能でした。

/wp-admin/admin.php?page=aiowpsec&tab=tab1&orderby=IF ( (select sleep(4) FROM wp_users where  user_pass like  concat( char(37),char(84),char(37))), id, id)

Time-based SQL Injectionは意外に実用的だった | 徳丸浩の日記

危険性について

Blind SQL Injectionであるのでなかなか時間がかかりますが、攻撃の際に被害者に対して気づかれずにDB上の情報を盗めます。設定を変えていない場合はsaltが同じようなので、パスワードのハッシュなどを抽出した後にパスワードをオフラインアタックで推測すること理論的には可能であるように見えます。

とはいえ、特定のpluginを入れているサイトの管理者に対してピンポイントに攻撃を仕掛けることになりますので、ソーシャルハックなどを組み合わせないとなかなか難しいです。ログインパスワードを総当り攻撃する方が楽なような気もしますが、アカウントロック機構やアクセス制限をすり抜けるなどの利点はあります。

余談

修正の発表後に、同じpluginに対してまた別の報告でSQL injectionが上がっていました。

あれっと思って見てみると、mysql_real_escape_stringの部分がesc_sqlに変わっていたようですが、結局十分にエスケープできていなかったようです。

plugin周りの脆弱性への対応はやはりあまり良くないのですが、最近ではWordpress 周りの脆弱性を集約するサイト(https://wpvulndb.com/)があったり、pluginのコードを静的解析して脆弱性探すサイト php-grinder もあって、以前よりもちょっと環境が整ってきているようです。(けど使わなくていいなら使いたくはない。)