マルウェアの動的解析を行うための Cuckoo Sandbox をセットアップしたときのメモ.
1. 動機と結論
最近運用しはじめたハニーポットにマルウェアがひっかかってきている.いずれは静的解析も含めて解析を行っていきたいと考えているが,まずはお手軽なサンドボックス解析をできる環境を整えようと思った.使用しているハニーポットの種類の問題かもしれないが意外と Linux 向けのマルウェアがかかっていること,また個人的な趣向により Linux 向けマルウェアの解析を目標とする (ゲストの VM に Linux を使用する).
実際にセットアップした感想としては,Cuckoo は Linux ゲストの対応がまだ発展途上にあり,Windows ゲストでの解析に比べまだレベルが落ちると感じた.自分が正しく理解しているならば,以下のような事項はデフォルトでは実現できない.
- 検体が fork した子プロセスの追跡
- システムコールのトレース (strace; SystemTap を使用すれば検体の親プロセスのトレースはできていそう)
- ファイル作成等アクティビティの検出
- Volatility によるメモリフォレンジック
とはいえ,実際にサンドボックス内で検体を一定時間実行させることにより発生するネットワークトラフィックの PCAP や,そのメモリダンプを取得してある程度手動ででもその解析を行うことができるのは非常に魅力的であった.
2. 環境,方針
自宅に VMware ESXi サーバがあるのでそれを利用することとする.
- ホスト OS
(Hardened) Gentoo. 通常であれば Ubuntu あたりを使用するのが楽なのだろうけど,リソースに限りがある自宅サーバで使用するという状況においては,不要なコンポーネントをできる限り排除できるという理由で Gentoo を選んだ.Gentoo であれば Qt をインストールしなくても VirtualBox が使用できる! Gentoo とは選択です (ステマ).Hardened の意味は特になくて,SELinux や grsecurity による制御は使用していない.なんとなくの選択.ホスト OS と言っても ESXi の上で動いている VM であるため,ここで Cuckoo を使用するとなると Nested VM を使用することとなる.
- 仮想化ソフトウェア
VirtualBox. 最近の Cuckoo のバージョンは仮想化ソフトウェアに依存しておらず VMware や KVM でも動作するそうだが,特にこだわりはなかったので一番実績がありデフォルトである VirtualBox を使用する.
- ゲスト OS
Ubuntu Desktop 16.04 LTS. 一番メジャーなディストリビューションを.もちろんひとつに限定する必要はないが,今回の記事ではこれだけを対象とする.
- virtualenv
Cuckoo をはじめとして,関連ツールは大きく Python に依存している.しかも Python 2.7 (Gentoo は現在デフォルトで 3.4 を使用している.もちろん 2.7 も選択できるが.Gentoo ですから). 必要なモジュールを普通にシステムにインストールするとなると Gentoo のパッケージ管理システムである Portage とだいぶ相性が悪いのと,メンテナンスがしづらくなることが考えられるので,Cuckoo 関連用に virtualenv を用意し,その中で作業を行うこととする.
Cuckoo の Web インターフェイス利用までは今回の記事では行かない.あくまでコアと考えられる部分を対象とする.
3. ホスト OS の準備
ホスト OS の上でさらに VM を走らせる必要があるために,それなりのリソースを確保する必要がある.ホスト OS はこのような構成にした.
- CPU: 2 コア
- メモリ: 4GB
- HDD: 64GB (OS, ソフトウェア用) + 1TB (データ用; マウントポイント /data)
また,ESXi で Nested VM を使用する場合,(ホスト OS の) VM の設定として Virtual Hardware-Assisted Virtualzation (VHV) を有効にする必要がある.vSphere Web Client (要 vCenter) からであれば普通に設定できるようだが,自宅ユーザが普通に使える vSphere Client にはその設定がなく,SSH コンソールから .vmx ファイルを直接編集する必要がある.ちなみに,今回ホスト OS の名前は “cactus.”
- cactus.vmx
vhv.enable = "TRUE"
この設定は vSphere Client から設定を変更するたびに消えてしまうことに注意.そのつど手動で追加してやる必要がある.
Gentoo のインストールは普通に.profile は hardened/linux/amd64 で USE フラグもそんなにいじってないが,CPU 機能の有効化 (
cpuinfo2cpuflags
の結果) と,
acl, caps, icu
は有効にした (
caps
は後に必要なになってくる.他はいつもの癖).
Cuckoo に必要なソフトウェアをドキュメント
(http://docs.cuckoosandbox.org/en/latest/installation/host/requirements/) を参考にインストールする.Portage から (システムとして) 以下をインストールした.バージョンは現時点のもので参考まで.
- app-emulation/virtualbox-5.0.20 -qt4 +headless
- app-emulation/virtualbox-extpack-oracle-5.0.20.106931
- net-analyzer/tcpdump-4.7.4
- dev-vcs/git-2.7.3-r1
- dev-python/virtualenv-13.1.2
- dev-lang/python-2.7.10-r1 +sqlite
- net-dns/dnsmasq-2.75 (オプション; 後述)
少し USE フラグの調整をする.VirtualBox はこのあと全てコマンドラインで扱うことになるので,GUI は不要.
“-qt4 +headless”
すると依存コンポーネントがかなり減る.また Python は 2.7 系も最初からインストールされていたが,
sqlite
フラグを立ててアップデート.Volatility が Python の
sqlite3
モジュールに依存するため.また,VirtualBox 関連のパッケージは
package.accept_keywords
に記載して新しいバージョン (5.x 系) を入れることにした.
ドキュメントでは Volatility のインストールも必要とされていて,標準で ebuild も提供されているが,virtualenv を使用するとシステムにインストールされたモジュール (
/usr/lib64/python2.7/site-packages
以下) が参照されないこともあり,virtualenv のほうで自前でインストールすることとする.
このあたりからドキュメントの流れには沿わずにやっていく.
ガイドにしたがって Cuckoo 用ユーザが
tcpdump
を使用できるように cabality を設定.
caps
フラグがここで効いてきている.
dr@cactus ~ $ sudo setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
dr@cactus ~ $ sudo getcap /usr/sbin/tcpdump
/usr/sbin/tcpdump = cap_net_admin,cap_net_raw+eip
Cuckoo 用ユーザを作成.通常のデーモン用ユーザのようにログインシェルを無効化して作成したいところだが,当該ユーザのシェルからやることがたくさんあるので,ほぼ普通のユーザとして作る.
dr@cactus ~ $ sudo useradd -r -m cuckoo
dr@cactus ~ $ sudo gpasswd -a cuckoo vboxusers
今後複数のユーザを行き来して作業を行う.ますは Cuckoo ユーザで virtualenv の作成.Python 2.7 を指定すること.
dr@cactus ~ $ sudo su - cuckoo
cuckoo@cactus ~ $ virtualenv --python=python2.7 ~/cuckoo
cuckoo@cactus ~ $ source ~/cuckoo/bin/activate
(cuckoo)cuckoo@cactus ~ $
4. Volatility
まずは Volatility のインストールから.pip には提供されていない (と思う) ので,GitHub レポジトリから取得し,(virtualenv に) インストール.あと関連パッケージも pip でインストール.参考:
https://github.com/volatilityfoundation/volatility/wiki/Installation
(cuckoo)cuckoo@cactus ~ $ cd volatility/
(cuckoo)cuckoo@cactus ~/volatility $ python setup.py install
(cuckoo)cuckoo@cactus ~/volatility $ pip install distorm3 pycrypto OpenPyxl ujson
PIL (Python Imaging Library) は現在は Pillow としてメンテナンスされていると理解している.libjpeg に依存していたので,それもインストール.
dr@cactus ~ $ sudo emerge -av media-libs/libjpeg-turbo
(cuckoo)cuckoo@cactus ~/volatility $ pip install Pillow
yara も書かれているのだけど,実際インストールすると Cuckoo 起動時にエラーが出るようになるのでアンインストールした.
Volatility のインストールはここでしておくが,実際には Cuckoo から利用できる解析内容は Windows 向けの内容に限られており Linux ゲストのための解析を (自動で) かけることは現時点ではできない.でも,Cuckoo 実行時にメモリダンプを取得すればあとからの解析はできてとても興味深いので…….
5. Cuckoo インストール
GitHub から取得.解析結果のレポート等はこの cuckoo ディレクトリの下に保存されることになるので,データ用のパーティションに配置する.
dr@cactus /data $ sudo git clone https://github.com/cuckoosandbox/cuckoo.git
dr@cactus /data $ sudo chown -Rv cuckoo:cuckoo cuckoo
(cuckoo)cuckoo@cactus /data/cuckoo $ pip install -r requirements.txt
ここで設定なしに実行してみようとすると,Windows モニタ用のバイナリ (使わないけど),およびシグニチャをダウンロードしてくるように言われるので従ってダウンロード.
(cuckoo)cuckoo@cactus /data/cuckoo $./utils/community.py -waf
ここまでで Cuckoo が起動するようになる.ただし,これからゲスト VM の作成や設定などが待っている.
6. ゲスト OS の準備
前述のとおり,Ubuntu Desktop 16.04 を VirtualBox で動作させることとする.少しネットワーク周りの設定がややこしい.
- “hostonly” ネットワークを使用する.必要に応じてホスト OS で NAT し,インターネットに出られるようにする.
- ホスト OS の IP アドレスアサインに DHCP は使用せず,固定アドレスを設定する.これは Cuckoo が固定の IP アドレスを対象にパケットキャプチャを行うため.
- ホスト OS で dnsmasq を動作させて,ゲスト OS が名前解決できるようにする.
NAT や DNS は,少なくともセットアップ時にはインターネット接続が使用できた便利だが,解析を行う時に有効にしたままだと,検体 (マルウェア) のトラフィックがインターネットに出ていくことになるので注意が必要.
ここから先はとにかく慣れない VirtualBox CLI で頑張る.
“hostonly” ネットワークを使用するためのホスト OS 側インターフェイスの作成:
(cuckoo)cuckoo@cactus ~ $ VBoxManage hostonlyif create
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Interface 'vboxnet0' was successfully created
cuckoo@cactus ~ $ VBoxManage hostonlyif ipconfig vboxnet0 --ip 192.168.56.1
cuckoo@cactus ~ $ ip addr show dev vboxnet0
5: vboxnet0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
link/ether 0a:00:27:00:00:00 brd ff:ff:ff:ff:ff:ff
inet 192.168.56.1/24 brd 192.168.56.255 scope global vboxnet0
valid_lft forever preferred_lft forever
NAT 設定:
dr@cactus ~ $ sudo sysctl -w net.ipv4.ip_forward=1
dr@cactus ~ $ sudo iptables -S
-P INPUT ACCEPT
-P FORWARD DROP
-P OUTPUT ACCEPT
-A FORWARD -s 192.168.56.0/24 -i vboxnet0 -o tun0 -m conntrack --ctstate NEW -j ACCEPT
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
dr@cactus ~ $ sudo iptables -S -t nat
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-A POSTROUTING -j MASQUERADE
あと必要に応じて
/etc/sysctl.conf
にも記述.
VirtualBox の DHCP サーバ機能停止:
(cuckoo)cuckoo@cactus ~ $ VBoxManage list dhcpservers
NetworkName: HostInterfaceNetworking-vboxnet0
IP: 192.168.56.100
NetworkMask: 255.255.255.0
lowerIPAddress: 192.168.56.101
upperIPAddress: 192.168.56.254
Enabled: Yes
(cuckoo)cuckoo@cactus ~ $ VBoxManage dhcpserver remove -netname HostInterfaceNetworking-vboxnet0
dnsmasq の設定と起動.DHCP 機能を切ることを忘れずに:
# /etc/dnsmasq.conf
interface=vboxnet0
no-dhcp-interface=vboxnet0
bind-interfaces
dr@cactus ~ $ rc-service dnsmasq start
続いてゲスト VM の作成.1 点ポイントとしては,VRAM の容量を増やしてやらないと VRDE で RDP 接続したときの表示がうまくいかなかった.
(cuckoo)cuckoo@cactus ~ $ VBoxManage createvm -name "ubuntu-16.04_x64" --ostype Ubuntu_64 --basefolder /data/vm --register
Virtual machine 'ubuntu-16.04_x64' is created and registered.
UUID: eb33474a-6f34-4165-8ee8-9828bf9672a8
Settings file: '/data/vm/ubuntu-16.04_x64/ubuntu-16.04_x64.vbox'
(cuckoo)cuckoo@cactus ~ $ VBoxManage modifyvm "ubuntu-16.04_x64" --memory 2048 --vram 64 --nic1 hostonly --hostonlyadapter1 vboxnet0
(cuckoo)cuckoo@cactus ~ $ VBoxManage createhd --filename /data/vm/ubuntu-16.04_x64/ubuntu-16.04_x64.vdi --size 25600
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Medium created. UUID: 3ade2e5c-6277-4a00-b5a5-09921a84a8ac
(cuckoo)cuckoo@cactus ~ $ VBoxManage storagectl "ubuntu-16.04_x64" --name sata --add sata --portcount 2 --bootable on
(cuckoo)cuckoo@cactus ~ $ VBoxManage storageattach "ubuntu-16.04_x64" --storagectl sata --port 1 --type hdd --medium /data/vm/ubuntu-16.04_x64/ubuntu-16.04_x64.vdi
(cuckoo)cuckoo@cactus ~ $ VBoxManage storageattach "ubuntu-16.04_x64" --storagectl sata --port 2 --type dvddrive --medium /home/cuckoo/ubuntu-16.04-desktop-amd64.iso
(cuckoo)cuckoo@cactus ~ $ VBoxHeadless --startvm "ubuntu-16.04_x64" --vrde on
Oracle VM VirtualBox Headless Interface 5.0.20_Gentoo
(C) 2008-2016 Oracle Corporation
All rights reserved.
VRDE server is listening on port 3389.
RDP で接続して OS インストール作業.終わったらインストールメディアの detatch.
(cuckoo)cuckoo@cactus ~ $ VBoxManage storageattach "ubuntu-16.04_x64" --storagectl sata --port 2 --medium emptydrive
ゲスト OS の中ではいくつかの設定を.
- 自動アップデート,diag 情報送信の無効化
- ネットワーク設定 (今回自分は 192.168.56.101/24, ゲートウェイと DNS は 192.168.56.1 (ホスト OS の
vboxnet0
) を設定)
- Cuckoo エージェント (
agent/agent.{py,sh}
) のダウンロード・実行.起動時に agent.sh
が実行されるように /etc/rc.local
に登録しておくと良い
- タイムゾーン (今回ホスト,ゲスト OS ともに UTC を設定した)
一通り終わったら,スナップショットを取って終了.この状態から検体が実行されることになる.
cuckoo@cactus ~ $ VBoxManage snapshot "ubuntu-16.04_x64" take "initial" --pause
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Snapshot taken. UUID: 27d7efba-187d-47fd-a3ab-caaa0a0052c5
cuckoo@cactus ~ $ VBoxManage controlvm "ubuntu-16.04_x64" poweroff
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
cuckoo@cactus ~ $ VBoxManage snapshot "ubuntu-16.04_x64" restorecurrent
Restoring snapshot 27d7efba-187d-47fd-a3ab-caaa0a0052c5
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
7. Cuckoo の設定
基本的にはドキュメントとファイルを眺めて,ということろだが必要最小限な設定について.
# conf/cuckoo.conf
[cuckoo]
version_check = off
machinery = virtualbox
memory_dump = off
max_machines_count = 1
[routing]
route = none
internet = none
[resultserver]
ip = 192.168.99.60
routing
の設定に注意.コメントを読むと
route = none
を設定しておくとトラフィックは外部に出ていかないように読めるのだが,実際には,「Cuckoo 側では特にネットワーク関連の制御を行わない」という意味である.そのため,上で行ったホスト OS での NAT の設定が残っている状態だと,検体解析時のゲスト OS (つまりマルウェアの) トラフィックはインターネットに出ていくことになる.また,
memory_dump
はデフォルトの off のままにしているが,これを on にすれば実行時のメモリダンプが生成される.ただし,フルメモリダンプになるため容量を食うので注意 (今回作成した VM だと 2GB).でも,それを Volatility で見てみるといろいろなことがわかる.
resultserver
の IP アドレスはホスト OS の IP アドレス.デフォルトでは
vboxnet0
のデフォルトアドレスが設定されているが,VM が立ち上がっていないときにリンクダウンしたりするので,その他のアドレスの指定が推奨されている.
# conf/virtualbox.conf
[virtualbox]
machines = ubuntu-16.04_x64
[ubuntu-16.04_x64]
label = ubuntu-16.04_x64
platform = linux
ip = 192.168.56.101
ここまで設定すると,ようやく解析ができるようになる.
8. 解析
cuckoo.py
を実行すると,
(cuckoo)cuckoo@cactus /data/cuckoo $ python cuckoo.py
.-----------------.
| Cuckoo Sandbox? |
| OH NOES! |\ '-.__.-'
'-----------------' \ /oo |--.--,--,--.
\_.-'._i__i__i_.'
"""""""""
Cuckoo Sandbox 2.0-dev
www.cuckoosandbox.org
Copyright (c) 2010-2015
2016-07-12 10:46:08,338 [lib.cuckoo.core.scheduler] INFO: Using "virtualbox" as machine manager
2016-07-12 10:46:11,059 [lib.cuckoo.core.scheduler] INFO: Loaded 1 machine/s
2016-07-12 10:46:11,086 [lib.cuckoo.core.scheduler] INFO: Waiting for analysis tasks.
と待ち状態になるので,別コンソールから
util/submit.py
で検体を提出:
(cuckoo)cuckoo@cactus /data/cuckoo $ ./utils/submit.py /data/malware/da8140274788214c9451d950e0f323c0c51188c5bf847bafef9f48c023e91a55
Success: File "/data/malware/da8140274788214c9451d950e0f323c0c51188c5bf847bafef9f48c023e91a55" added as task with ID 1
すると Cuckoo コンソール側ではこんな出力が出てくる:
2016-07-12 10:48:39,473 [lib.cuckoo.core.scheduler] INFO: Starting analysis of FILE "da8140274788214c9451d950e0f323c0c51188c5bf847bafef9f48c023e91a55" (task #1, options "")
2016-07-12 10:48:39,580 [lib.cuckoo.core.scheduler] INFO: Task #1: acquired machine ubuntu-16.04_x64 (label=ubuntu-16.04_x64)
2016-07-12 10:48:39,721 [modules.auxiliary.sniffer] INFO: Started sniffer with PID 22438 (interface=vboxnet0, host=192.168.56.101, pcap=/data/cuckoo/storage/analyses/1/dump.pcap)
tcpdump: listening on vboxnet0, link-type EN10MB (Ethernet), capture size 262144 bytes
2016-07-12 10:48:48,464 [lib.cuckoo.core.guest] INFO: Starting analysis on guest (id=ubuntu-16.04_x64, ip=192.168.56.101)
2016-07-12 10:49:00,126 [lib.cuckoo.core.guest] INFO: ubuntu-16.04_x64: analysis completed successfully
63 packets captured
67 packets received by filter
0 packets dropped by kernel
2016-07-12 10:49:02,226 [lib.cuckoo.common.objects] WARNING: Unable to import yara (please compile from sources)
2016-07-12 10:49:08,274 [lib.cuckoo.core.scheduler] INFO: Task #1: reports generation completed (path=/data/cuckoo/storage/analyses/1)
2016-07-12 10:49:08,305 [lib.cuckoo.core.scheduler] INFO: Task #1: analysis procedure completed
そしてレポートやログが示されたディレクトリ (
/data/cuckoo/storage/analyses/1
) に保存されている.
9. 感想
まず,上記のタイムスタンプを見てみると 12 秒間しか実行されていない.短い.これは多分,検体自身の親プロセスしか追えていなくて,親プロセスの終了とともに解析が終了しているのだと思う.実際の挙動をもっと見るために解析タイムアウト (デフォルト 120 秒) まで続ける場合には,
util/submit.py
に
--enforce-timeout
オプションが使える.また,レポート (
reports/report.json
) の内容は少し期待外れで,ネットワークアクティビティと
strings
, VirusTotal でのスキャン結果くらいしか得られていない.これは Windows 向けマルウェアを malwr.com に投げたときとはずいぶん状況が違うので,Linux ゲスト対応がまだ発展途上なのであるのだと思う.
参考までに,当該ディレクトリの
ls -lR
と
report.json
を
https://drmn.jp/blog/20160713-cuckoo/ にアップロードした.
参考
- Cuckoo
- VMware
- VirtualBox
- Volatility