8月 012014
 
シェアする

wordpress

いやーまいりました。

朝自分のブログを確認したらアクセスができない。Internal Server Errorになってました。

契約しているのは月約1000円で借りているDTI提供のServersMan@VPSのスタンダードプラン。とりあえずDTIのコンパネからサーバーの再起動を行ってサーバーは復旧した。しかしまたすぐにアクセスができなくなった

サーバーの調査を行って分かったことそれは…

WordPressの「xmlrpc.php」を用いたブルートフォースアタック

ブルーとフォースがともにあらんことを。 じゃない。そんなんじゃない!
総当たり攻撃と呼ばれる手法で、大量のユーザー名とパスワードのペアを使い、ラッキーで認証を通過しようとする攻撃方法です。このような攻撃があるので、辞書に存在する文字列でのユーザーやパスワード、さらには12345などの簡単なものの利用は大変危険なインターネットの世界なのです。Wikipedia:総当たり攻撃

今回はこのブルートフォースアタックのために、サーバーへ接続できる接続数をうわまってしまい、通常のアクセスができなくなっていたという状況です。簡単にたとえると、卵1パック20円のセールを行ったスーパーに、隣町のおばちゃんたちが押し寄せたため、いつもスーパーを利用している普通の買い物客がお店に入れなかったり、会計の列が長くて待てずに帰っちゃったりするようなことです。いやぁ何とも恐ろしい。。。。 え?

xmlrpc.phpってなんなの

このファイルは、WordPressの一部でして、このファイルはWordPressへの操作を行うことができるファイルです。
もちろんユーザー認証を通過しないと操作ができないものなのです。

たとえばWordPressのスマートフォン用のアプリなど、このxmlrpc.phpを通して記事の投稿やアクセス解析情報などを取得しています。今回はこのファイルへのユーザー認証がアタックされていました。以前からwp-adminへのアクセスはBasic認証でブロックしていますが、それではもう防げない不正アクセスが存在するようです。

ここでユーザー認証を通過したらどのような操作が行えるようになるのかは、ちょっとわかりませんが、とにかくブロックしておきたいですね。

対策方法:xmlrpc.phpへのアクセスをブロックする

私はnginxで運用しておりますので、以下の設定を追加することでアクセスをすべてのアクセスをブロックするのはすごく簡単です。

server {
~
    if ($request_filename ~* xmlrpc.php) {
        return 403;
    }
~
}

こうすれば、xmlrpc.phpへのアクセスはブロックできる。
くれぐれも、php-fpmなどにphpファイルを渡す前(location設定の前が理想)に、この設定を行ってアクセスを拒否してくださいね。

私の場合、スマホアプリからアプリ経由でアクセスしたりするので、この設定をしてしまうとアプリからのアクセスができなくなってしまいます。また、Jetpack.comとの連携もあるので、接続時のユーザーエージェントを条件に許可するようにしてみました。

nginxでユーザーエージェントを元に接続を許可する方法

次の3つの条件にマッチした場合に403エラーコードを返すように設定してみた

  1. ユーザーエージェントに「wp-android」か「Jetpack」を含む場合
  2. リクエストされているファイルが「xmlrpc.php」の場合
  3. リクエストメゾッドが「POST」の場合
Server {
~
    # $wp という変数を作ってそれを「A」にする
    set $wp A;

    # ユーザーエージェントに「wp-android」か「Jetpack」を含む場合
    # 上記で設定した $wp という変数を「a」にする
    if ($http_user_agent ~* (wp-android|Jetpack) ) {
        set $wp a;
    }

    # リクエストされているファイルが「xmlrpc.php」の場合
    # $wp の値を この時点での$wp + B にする(例:$wpがAの場合、$wpは「AB」になる)
    if ($request_filename ~* xmlrpc.php) {
        set $wp "${wp}B";
    }

    # リクエストメゾッドが「POST」の場合
    # $wp の値を この時点で$wp + C にする(例:$wpがABの場合、$wpは「ABC」になる)
    if ($request_method = POST) {
        set $wp "${wp}C";
    }

    # $wp の値が「ABC」の場合
    # 403エラーを返す
    if ($wp = "ABC"){
        return 403;
    }
~
}

これでひとまず大半のアクセスは制御することができるようになりました。

あとは、時々ログを確認して「200」でアクセス完了してしまっているものに関してその接続元IPアドレスを確認しておかしいものがないかを見ることにします。

経緯

最初は、以下の記述をfunctions.phpに追加して、403になったものはiptablesでその接続元をブロックするようにと考えて対応しました。

function my_login_failed_403() {
    status_header( 403 );
}
add_action( 'wp_login_failed', 'my_login_failed_403' );

引用元:Fail2ban + WordPress + Nginx

上記設定によりxmlrpc.phpにアクセスして認証を通過できなかった場合には、nginxのログに403エラーが記録されます。これでもいいのですが、私のVPSではiptablesで制限できる数(256)を余裕で超える数からのアタックだったので、最終的にはiptablesでブロックしきれなくなってしまいました(涙)。ということで、今回はnginxで403エラーで跳ね返しちゃえという手段をとりました。

以下おまけ


ブルートフォースアタックのパケットを見てみた

# tcpdump -s 0 -A 'tcp dst port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354)'
10:26:04.707999 IP 190.209.62.46.63406 > trippyboy.com.http: P 3618241418:3618241730(312) ack 2432426290 win 64240
E..`rS@.o.?...>........P.......2P.......POST /xmlrpc.php HTTP/1.1
Connection: Close
Content-Length: 217
Host: blog.trippyboy.com
<?xml version="1.0" encoding="iso-8859-1"?>
<methodCall>
 <methodName>wp.getUsersBlogs</methodName>
 <params>
 <param><value>blog</value></param>
 <param><value>bluesman</value></param>
 </params>
</methodCall>

参考:POSTされてくる内容をtcpdumpで見る方法
Use tcpdump to analyse HTTP POST data

curlコマンドを使ってブルートフォースアタックを再現してみた

間違っている場合

[root@vps1 ~]# curl -D - "https://blog.trippyboy.com/xmlrpc.php" -d '<methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value><string>username</string></value></param><param><value><string>password</string></value></param></params>
</methodCall>'
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 01 Aug 2014 06:42:53 GMT
Content-Type: text/xml; charset=UTF-8
Content-Length: 441
Connection: keep-alive

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <fault>
    <value>
      <struct>
        <member>
          <name>faultCode</name>
          <value><int>403</int></value>
        </member>
        <member>
          <name>faultString</name>
          <value><string>ユーザー名またはパスワードが正しくありません。</string></value>
        </member>
      </struct>
    </value>
  </fault>
</methodResponse>
[root@vps1 ~]#

正しい場合(結果のみ)

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param>
      <value>
        <array><data>
        <value><struct>
          <member><name>isAdmin</name><value><boolean>1</boolean></value></member>
          <member><name>url</name><value><string>https://blog.trippyboy.com/</string></value></member>
          <member><name>blogid</name><value><string>1</string></value></member>
          <member><name>blogName</name><value><string>TrippyBoyの愉快な日々</string></value></member>
          <member><name>xmlrpc</name><value><string>https://blog.trippyboy.com/xmlrpc.php</string></value></member>
        </struct></value>
        </data></array>
      </value>
    </param>
  </params>
</methodResponse>

 接続元によってアクセスが制限されている場合(結果のみ)

TTP/1.1 403 Forbidden
Server: nginx
Date: Fri, 01 Aug 2014 08:23:28 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 162
Connection: keep-alive

<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

ちなみに、curlコマンドは「-A “useragent”」のオプションでユーザーエージェントを指定することができますので、ユーザーエージェントでの制限が正しく動作するのかを試すときには利用してみてください。

以上

このエントリーをはてなブックマークに追加

  5 コメント

  1. おはようございます。お久しぶりです!!
    最近、製作のまとめ役と対人関係で色々トラブル中でした。
    性格がワンマンなうえ社長に現場責任者に任命されてるのかパワハラまがいなことを多数。サーバーにも口出しが多い。
    また、ひとつのサーバーにwordpressをめちゃくちゃつくるのでサーバーもめちゃくちゃに・・・。まっとう運用ができないため、
    nginxやpleskのサーバーの乗り換えに手を出しました。仕事とはこういう側面があるので我慢してましたが、
    サーバー用の回線(他にも回線があるにもかかわらず)をとられたため頭に来て社長に報告。おとなしくなりました。
    デザイン側はやりやすくなったんじゃないのかな?

    俺の方は仕事が違うのであんまり関わることはありませんが、同じデザインは大変だったんじゃないかな?
    wordpressのメンテナンスやサーバー側の設定は俺しかできないのに俺との間にトラブルを起こすのは賢明とはおもえませんなw

  2. おはようございます!
    お久しぶりです。
    トラブルはいろいろと面倒で嫌ですね〜。サーバー用の回線を利用するとは、何たる不届き者!!もう少し配慮してもらいたいですね(^_^;)
    そういう無配慮感もパワハラのようなものですよねっ 少しはありがたく思ってる姿勢を見せてほしいものですw あ、言い過ぎですか?笑

  3. こんにちは
    まとめ役となんか製作の人がもめたらしくまとめやくが俺のことを給料泥棒といってるみたいです。
    給料泥棒が回線使うより、自分が使うほうが会社のためになるとかそんな論理で奪ったんでしょうね。
    こういうのは水掛け論になるだけなんであんまりいいたくありませんが、

    >少しはありがたく思ってる姿勢を見せてほしいものですw あ、言い過ぎですか?笑
    24時間いつでも利用できるというのが当たり前なんですけど、その当たり前の環境を実現するために
    インフラ系SEの我々は苦労してる。そういうのを少しでも理解してほしいものです。

    昼間サーバーへのアクセスなんかありません。みんな働いてますからね。夜あるんです。
    その夜にちゃんとサイト表示ができるか定期的にmrtgとかみてるのですけどね。
    当然、無給です。自分で好きでやってるんで、文句を言われる筋合いでもないし文句もいいません。

    俺の方はなるべく関わらないようにやっていくしかありませんね。

  4. 初めまして。

    大変お勉強になりました!探していたものとは違いましたが思わず記事を読み切ってしまいましたw
    面白かったです!

  5. kyapiyさん
    コメントありがとうございます!\(^o^)/
    おまけに最後まで読んでくださったとは、嬉しいです!

コメント大歓迎!質問も受け付けておりますヽ(*´∀`)ノ