2016年7月26日火曜日

Linux/DDoS-Xor.A リバージング

先日の Cuckoo によるマルウェア解析の続きで,少しだけれどもリバージングにチャレンジしてみる.

1. 対象マルウェア

前回と同じく sha256: da8140274788214c9451d950e0f323c0c51188c5bf847bafef9f48c023e91a55 のファイルを対象とする.前回やったときは VirusTotal の結果はなかったけれど,今検索してみると Linux/DDoS-Xor.A などと結果が出てくる (https://www.virustotal.com/en/file/da8140274788214c9451d950e0f323c0c51188c5bf847bafef9f48c023e91a55/analysis/).

2. Cuckoo による解析の続き

前回の投稿では Linux マルウェアでは strace や子プロセスの追跡ができないと書いたが,実行のタイミングを調整することでうまく動作させることができた.(そして Pull Request デビューした: https://github.com/cuckoosandbox/cuckoo/pull/1007)

トレースありの Cuckoo レポートを https://drmn.jp/blog/20160726-reversing/2.zip にアップロードした.一応 PCAP 等含むのでパスワード “infected” をかけている.

トレースが見れると非常にはかどる.このマルウェアは何回もプロセスを作ったり消したりする動作をしていたのだけれど,たとえば外部ホストに接続しに行こうとしたプロセスのトレースは以下.

わかりづらく表記された .org のドメインの名前解決をして当該 IP アドレスに接続しているように見受けられる.ではこの接続先を strings などで探すことができないかと考えたが,できなかった.
cuckoo@cactus /data/cuckoo/storage/analyses/2 $ strings binary | grep org
C/o Keld Simonsen, Skt. Jorgens Alle 8, DK-1615 Kobenhavn V
TLS generation counter wrapped!  Please report as described in <http://www.gnu.org/software/libc/bugs.html>.
DNS に使用されるアドレスのほうは出てくる.
cuckoo@cactus /data/cuckoo/storage/analyses/2 $ strings binary | grep -F 114.114.114.114
114.114.114.114
ということで,strings だけでは得られない情報を求めてリバージングしていく.できれば動作全体の解明をしていきたいのだけれど,まだまだ始めたばかりなので…….

3. リバージング

リバージングには Radare2 を使用している.

main の逆アセンブル結果を見ていくと,最初のほうにこんなパートが出てくる.
PATH 環境変数をセットしているのは良いとして,0x0804b67f 以降,謎の文字列をセットして dec_conf が呼び出されている.これは怪しい.次に dec_conf を見てみる.
いろいろと値のコピーなどを行っているようだが,結局のところ encrypt_code が呼び出されていて,これが肝のようだ.
encrypt_code 自体は小さな関数で,さらにそこからどこかにも飛んでいない純粋な処理を行う関数のようなので,ここを丹念に見ることにする.しかし,decrypt_conf の中で encrypt_code という名前の関数が呼び出されるということは……2 回処理にかけたら元に戻るアルゴリズム? XOR 的な? という想像が働いてくる.コードの中にもちらっと見えるし.読んだ結果を以下に書き込んだ.
どうやら,この関数は文字列とその長さを引数に受けとり,その文字列と “BB2FA36AAA9541F0” (の繰り返し) の ASCII コードで 1 文字ずつ XOR をかける処理を行うもののようだ.

ということで,同等の関数を Python で書いてみた.main とのあいだには memmove している dec_conf 関数があるが,たぶん特に何も考えず,dec_conf への引数を渡してみたら良いのではないかとやってみる.
# decrypt.py
import sys

def decrypt(code):
    div = 0x10 # len(key)
    key = "BB2FA36AAA9541F0"

    result = ""
    for i in range(len(code)):
        result = result + chr(ord(code[i]) ^ ord(key[i % div]))

    return result

for code in sys.stdin:
    print(decrypt(code.rstrip()))
main で渡されていた文字列をいくつか試してみる.
cuckoo@cactus ~/work $ python decrypt.py
m ])5
/boot
m4S4nAC/n2_AD
/var/run/sftp
m.[$nFR$7nLQQGF
/lib/udev/udev
良さそう!

もともとのドメインを探して strings を全部喰わせてみる:
cuckoo@cactus ~/work $ strings /data/cuckoo/storage/analyses/2/binary | python decrypt.py | grep -a org
2.org
2.org
まだもう少しちゃんとコードを追う必要がありそうだけれども,まあまあいい線行っているのではないか.

参考

0 件のコメント:

コメントを投稿