MySQLが落ちとる
運営しているサイトの作業で、データベースを確認しようと思いAdminerで接続しようとしたところ、繋がらず。
なんかmysqld
が落ちていた。
なんだこれと思い調べてみました。
結果からお伝えすると、
- 「WordPressのxmlrpc.phpを利用したDDos攻撃による大量アクセス」
が原因でした。
以下はその時の経緯とかです。 ちなみにレンタルサーバー借りてから初めての障害。泣きそうでふた。
サーバ落とされた経緯
気づく
さっきも書いたとおり、データベースに繋がらないのが気がついた契機です。
とりあえずリソースを確認してみることに。
レンタルサーバ屋が提供しているリソースグラフをみてみるとピョコンと高くなっている部分がある。
スパイクぅぅ。
この時は日に200pvくらいのサイトしか置いてないので、こんなに負荷が高くなることはない。もちろんcronで重い処理を回してたということでもないです。
log確認
こんな時は落ち着くのが一番。まずログをみてみようということで確認。
secureログ
Dec 1 03:51:03 host-hoge sshd[9925]: fatal: Read from socket failed: Connection reset by peer
当該時間に重なるようなログは無かった。port22から進入を試みようとするログはいっぱいあったけど。
massegesログ
リソースグラフのスパイクと重なる時間にhttpdに何らかの不具合が起こったようです。
具体的にはメモリ不足が起きたらしい。そのためOOMKIller
が発動したみたいです。
Dec 1 05:08:41 host-hoge kernel: Out of memory: Kill process 5021 (httpd) score 12 or sacrifice child
OOMKiller
とは、なんらかの理由でメモリが足りなくなると予め優先順位付けされたプロセスをkill
してメモリを確保しようとするLinuxの機構DEATH。
初期設定だと、データベースなんかも優先順位が高い方(殺される順番として)でWordPressなどCMSでサイトを構成している際は、httpサーバーに大量アクセスがあると必然的にデータベースが使うメモリも増大してしまうため、殺されたようです(亡)。
httpdログ
リソースグラフのスパイクと重なる時間に大量のアクセスが
46.166.139.20 - - [01/Dec/2015:07:35:54 +0900] "POST /xmlrpc.php HTTP/1.0" 500 263 "-" "Mozilla/4.0 (compatible: MSIE 7.0; Windows NT 6.0)"
これは抜粋したものだけど、46.166.139.20
のばかやろうが秒間100以上のアクセスをしてきていました。
アクセス先はxmlrpc.php
。
wordpressのxmlrpc.php
最初にも述べたとおりxmlrpc.php
はWordPressのファイルです。
WordPressにはpinback機能がありますが、これはML-RPC API
を使用して実装されています。つまりxmlrpc.php
はAPI
です。
xmlrpc.php
にPOSTリクエスト
を送信すると、任意のサイトにpinback
を送ることができます。
なのでこの仕組みをつかってWordPressを踏み台にDDos攻撃が可能になります。
今回は踏み台にされたようです。サーバを乗っ取られなくても攻撃の片棒を担がされたことに…。
正直に言いますとxmlrpc.php
など知りませんでした。えへへ。
今度はWordPressが踏み台に、Pingback機能を悪用しDDoS攻撃
@MINOの現状では使うことはないですが、これデフォルトで有効になっているようです。
なんてことだ。
対策
xmlrpc.php
を削除する手もありますが、WordPressのバージョンアップ時にファイルが復活してしまうので、毎回消すのはあまりいい手ではありません。
簡単な方法としては.htaccess
に以下の様に記述し、ファイル単位でアクセスを弾く手があります。
<Files xmlrpc.php>
Order allow,deny
Deny from all
</Files>
しかし.htaccess
ではアクセスを受けてから弾くため、アクセス負荷は対策が難しいのが難点です。
対策の方法はいろいろあるかと思いますが、おそらくiptables
で弾くのが良いのではないかと思います。
具体的にはhashlimit
を使うのが良さそうです。
iptablesでhashlimitを使ってipごと弾く
hashlimit
はipとポートを1つのグループとして監視してくれます。
イメージとしてはip単位のアクセスをカウントして、設定した条件に抵触した場合にそのipからのアクセスを遮断するという方法です。
以下hashlimit
を用いた場合の設定例(一部抜粋)です。
iptables -N HTTP_DOS # "HTTP_DOS" という名前でチェーンを作る
iptables -A HTTP_DOS -p tcp -m multiport --dports 80 \
-m hashlimit \
--hashlimit 1/s \
--hashlimit-burst 100 \
--hashlimit-htable-expire 300000 \
--hashlimit-mode srcip \
--hashlimit-name t_HTTP_DOS \
-j RETURN
# 解説
# -m hashlimit limitではなくhashlimit を利用する
# --hashlimit 3/s 秒間3接続を上限とする
# --hashlimit-burst 5 上限を5回連続超えると制限
# --hashlimit-htable-expire 300000 管理テーブル中のレコードの有効時間(ms単位、例では30秒有効)
# --hashlimit-mode srcip 送信元アドレスでリクエスト数を管理する
# --hashlimit-name t_HTTP_DOS /proc/net/ipt_hashlimit に保存されるハッシュテーブル名
# -j RETURN 制限にかからなければ、親チェーンに戻る
# 制限を超えた接続の破棄とロギング
iptables -A HTTP_DOS -j LOG --log-prefix "http_dos_attack: "
iptables -A HTTP_DOS -j DROP
# HTTPへのパケットは "HTTP_DOS" チェーンへジャンプ
iptables -A INPUT -p tcp -m multiport --dports 80 P -j HTTP_DOS
iptables
であればアクセス自体を遮断できるので、負荷に対しても一定の有効性があります。
DDos攻撃の場合、僅かな時間に極端なアクセスが来るのが特徴です。そのためある程度の設定のチューニングは必要かと思いますが、通常使用時の自然なアクセス自体は排除される恐れはほとんどありません。
自然な使用で秒間100アクセスなんかならないですよね。なのでもしxmlrpc.php
を使っていた場合でも、アクセス制限を併用できます。
まとめ
- WordPressのxmlrpc.phpは攻撃対象になる
- iptablesのhashlimitでアクセス制限をするのがおすすめ