解析メモ

マルウェア解析してみたり解析に役に立ちそうと思ったことをメモする場所。このサイトはGoogle Analyticsを利用しています。

MacnicaCTF 2019 を CLI だけで解いてみた Writeup

f:id:k1z3:20190705232909p:plain

昨日はマクニカネットワークス主催のCTFに参加してきました。うまく解けない問題もいくつかあり悔しかったので、リベンジもかねて Writeup を書きました。
ただ、問題の解説自体は午後のセッションで聞いてきたので、そのまま Writeup を作っても面白くないかと思います。なので、極力 CLI を使って Kali だけで解析をしてみよう、というのがこの記事の趣旨です。

デジタルフォレンジックマルウェア解析の問題

1. 悪意部品 (暗号)

f:id:k1z3:20190705211251p:plain

当日は JPCERT の記事中には 20h (32bytes) と書いてあるものの 20 bytes で問題ファイルが作成されていました。 1 位の方が for 文ぶん回して説いたと言っていたので、そのコードも参考にしつつ。

f:id:k1z3:20190709230349p:plain
f:id:k1z3:20190709230419p:plain
(略)
f:id:k1z3:20190709230508p:plain

ずっと文字列で 16 進の値を読み込んではまっていました。 上記コードには出ていませんが、16進文字列 ("abcdef") を hex の値にするには binascii.unhexlify("abcdef") で良いことにやっと辿り着けた。。。

import binascii

hexstr='abcdef'
hexdata=binascii.unhexlify(hexstr)

print hexdata
>>> 0xabcdef

2. 標的攻撃 I (フォレンジック)

f:id:k1z3:20190705211318p:plain vmdk のディスクイメージファイルから削除されたファイルを抽出してそのファイルの MD5 ハッシュ値を求める問題です。GUI を使った場合は FTK Imager を使えばすぐにできると思います。CLI で実施するために、vmdk のマウントや qemu などいろいろ試して以下の手順で出来ました。

  1. qemu-nbd で扱える形式に変換
  2. vmdk イメージを NBD (Network Block Device) としてアタッチできるように modprobe でロードする
  3. qemu-nbd で nbd にディスクファイルをアタッチする
  4. ntfsundelete で削除済みファイルを探す
  5. ntfsundelete で削除済みファイルを抽出する
  6. md5 を求める

vmdk 変換

※ 今回受け取った vmdk ファイルは VMDK4 形式で、qemu-utils の qemu-img でも Windows の VBoxManager.exe でも変換できなく、以下の Windows EXE の qemu-img.exe を使って変換しています。

f:id:k1z3:20190705214705p:plain

(情報元) virtualbox - How to convert VMDK to VDI/VHD - Unix & Linux Stack Exchange

cloudbase.it

変換は vhdx, vdi, raw を試しました。raw はファイルサイズが大きくなるので、一番ファイルサイズが小さな vdi が扱いやすいと思います。

# qemu-img.exe convert diskimage.vmdk -O vdi newimage.vdi

qemu 関連準備

qemu-nbd でディスクイメージをデバイスとして認識させることを目指します。まず最初に modprobe で nbd をロードし、そこに qemu-nbd でディスクイメージ(変換後)を割り当てます。

# modprove nbd max_part=16
# qemu-nbd -r -c /dev/nbd0 newimage.vdi

この後、割り当てられた /dev/nbd0p1 の mount を試しましたが、ファイルは一部しか見れませんし、削除済みファイルを探すこともできません。

削除済みファイルの検索

削除済みファイルの検索は ntfsundelete というツールを使います。このツールは Linux に標準でついているようなので、例えば Live CD などでフォレンジックを行う際にも活用できるテクニックだと思います。

# ntfsundelete /dev/nbd0p1
Inode    Flags  %age     Date    Time       Size  Filename
-----------------------------------------------------------------------
(省略)
22       F..!     0%  1970-01-01 09:00         0  <none>
23       F..!     0%  1970-01-01 09:00         0  <none>
40       FN..   100%  2019-07-03 21:15      2560  a.EXE
44       F..!     0%  1970-01-01 09:00         0  <none>
45       F..!     0%  1970-01-01 09:00         0  <none>
(省略)
Files with potentially recoverable content: 1

削除済みのファイル (a.EXE) が見つかりました。

削除済みファイルの抽出

同じく ntfsundelete コマンドのオプションを指定することで抽出できます。まず inode 番号を指定し、delete フラグが立っているファイルなのでそのフラグを外し、指定サイズでファイル出力する、という流れを取ります。-T オプションをつけないとディスクのブロックサイズ (4096byte) で出力されるので注意が必要です。

# ntfsundelete -u -i 40 -o a.EXE -T /dev/nbd0p1
Inode    Flags  %age  Date            Size  Filename
---------------------------------------------------------------
40       FN..     0%  2019-07-03 21:15      2560  a.EXE

Undeleted 'a.EXE' successfully to a.EXE.2.

MD5 算出

md5sum ですぐですね。

# md5sum a.EXE

3. 標的攻撃 II (マルウェア)

f:id:k1z3:20190705211643p:plain マルウェアを実行したときに追加されるユーザをこたえる問題です。GUI を使う場合は仮想環境で実行したあとに net user コマンドでも実行すればわかります。

CLI の場合でも strings にかけることで net use コマンドでユーザを追加しているコードが平文で出てくるのですぐにわかります。ただ、マルウェアの作りが複雑な場合はこれでは求められないこともあると思うので、本来はデバッガなど使っていく案件かと思われます。

f:id:k1z3:20190705212334p:plain

4. 標的攻撃 III (マルウェア)

f:id:k1z3:20190705212411p:plain マルウェアを作った攻撃者グループを答える問題です。Google 検索で追加されたユーザ名を検索すれば一目でわかると思います。これは GUI 使わせてください。

f:id:k1z3:20190705212554p:plain

5. 標的攻撃 IV (マルウェア)

f:id:k1z3:20190705212627p:plain 追加されたユーザはログイン画面に表示されない設定となっています。レジストリにどんな値を設定すればいいのかを答える問題です。マルウェアを strings にかけた時に出てくる平文のコードの中にレジストリを操作しているものがあり、これのうちの一つが正解となります。

f:id:k1z3:20190705213040p:plain

answers.microsoft.com

Google 検索してもドストライクな答えがすぐに見つかると思います。

6. 情報漏洩 I (マルウェア)

f:id:k1z3:20190705213204p:plain マルウェアと称されたバッチファイルを解析して、ツール名を答える問題です。難読化されたファイルだったので、ツール名を答えろ=難読化ツール名を答えろ、と解釈してしまい、時間以内に解けませんでした。

f:id:k1z3:20190705213631p:plain

こんな感じに % がたくさんあって読めたものではありません。
バッチファイルの変数は %xxx% の形式で扱われることと、値を代入していない変数は意味がないことに気づければ %xxx% を消す、という作業をするだけで答えが見えてきます。 文字列を置換して消すのは sed コマンドが便利です。今回は最小一致させないといけないので、[^%]+ ... % 以外( [^] ) の連続 (+) を使っています。

f:id:k1z3:20190705213938p:plain

7. 情報漏洩 II (その他)

f:id:k1z3:20190705214240p:plain バッチファイルは ftp でサーバに XLS ファイルを送信するスクリプトが書かれているので、それを読み解きファイルを取得してフラグを求める問題です。当日は FTP サーバに置いてあったファイルが壊れていたため、取得しても開けない状態でした。

アプローチとしては、まずバッチファイルにはコメント (REM から始まる行) 多く、処理が見えづらいので、コメント行を消します。

f:id:k1z3:20190705215135p:plain

echo で temp .txt に FTP クライアントが実行する内容を書いて実行している内容です。なので、echo の部分だけ抜き出します。

f:id:k1z3:20190705215305p:plain

見やすくなってきました。echo を消して、

f:id:k1z3:20190705215441p:plain

ファイル出力を消し、

f:id:k1z3:20190705215527p:plain

mput (multipl put) はファイルを ftp サーバに送るコマンドなので逆方向(ftp サーバからファイルをもらう)mget に置き換えます。

f:id:k1z3:20190705215659p:plain

あとはこれで出来た temp.txt を少し linuxftp クライアント用に成形して、実行させます。

(成形内容)

  • Windows の場合は、open → ユーザ名 → パスワード でログインして、以降は FTP コマンド実行。
  • Linux の場合は、open → user でログインして、以降は FTP コマンド実行。

linuxftp クライアントはコマンドファイルは -n オプションでログインプロンプトを切ったうえでファイルを喰わせれば OK とのこと。

f:id:k1z3:20190705220403p:plain

当日は xls ファイルでしたが xlsx に差し替えられていますね。

f:id:k1z3:20190705220654p:plain

バッチリ直っていました!

パケット解析の問題

8. 建屋制御 I (ネットワーク)

f:id:k1z3:20190705220902p:plain pcap ファイルから1階工場のロケーション名を答える問題です。CLI のパケット解析は Wireshark の本体?である tshark が便利です。V オプションをつければすべてのパースされた内容を平文で出力してくれるため、grep などと相性が良いです。今回はヒントとして 制御プロトコルであるBACnetにおいて、deviceオブジェクトのlocationプロパティ内に制御システムの場所情報を保持している。 とあるので、これらのキーワードを手掛かりに探します。

単純に location だけで grep しても見えてくるものがあります。

f:id:k1z3:20190705221828p:plain

UTF-8 が書かれている行がそれっぽい値のようです。

f:id:k1z3:20190705222236p:plain

9. 建屋制御 II (ネットワーク)

f:id:k1z3:20190705222323p:plain 前問のファイルを使って温度が書かれているデータを見つける問題です。ちなみに前問の文中にヒントとなる画像がありますので、これも活用していくこととなります。

f:id:k1z3:20190705222451p:plain

このヒントからだと1階工場室温モニタの「オブジェクトタイプ」が 0 ということがわかります。これが手掛かりでしょう。pcap ファイルを tshark でパースし、object を探してみると、

f:id:k1z3:20190705222714p:plain

Object Type: として色々出てきています。analog-input が 0 なので、これなのでしょう。ただ、これを grep しただけだとほかのフィールドは見えません。

f:id:k1z3:20190705222951p:plain

問題文では時間を指定していることから、tshark の解析範囲にフィルタをかけます。今回のパケットは JST の時間が出ており、問題文で指定している UTC からサマータイムを考慮して +08:00 の時差があることを考慮したフィルタです。

f:id:k1z3:20190705223703p:plain

出てきたものを less で追いながら 2 桁温度かつ小数点5位まである値 ([0-9]{2}.[0-9]{5}) を探します。「Real」と添え書きされているデータが温度っぽい事が分かってきます。

f:id:k1z3:20190705223909p:plain

これのどれかかと思います。

f:id:k1z3:20190705224001p:plain

もうちょっと絞り込んでいくなら、前問で 1階工場 になっていた IP アドレスをフィルタを増やしながら探っていき、末尾 101 か 102 の IP アドレスからのデータということを押さえておきます。

f:id:k1z3:20190705224330p:plain

で、これをtsharl の解析範囲のフィルタに当ててあげると、一つに絞られます。

f:id:k1z3:20190705224507p:plain

Web 問題

10. 暗証保護 (Web)

f:id:k1z3:20190705224643p:plain ローカルからしかアクセスできない password.php の中に書かれたフラグを表示させる問題です。表示させるためのツールとして webchek.php が置かれており、このツールはホストとパスを入れると、そことの通信結果(リクエスト/レスポンスのヘッダ)と最初の1行を表示する機能を持っています。

f:id:k1z3:20190705225052p:plain

解説より HTML Header Injection 攻撃を行い、Range ヘッダを追加することで表示する範囲を変えるテクニックを使うとのこと。このテクニックを使うと改行 (%0D%0A) を含む値をリクエストヘッダに入れることにより任意のヘッダを使ってリクエストを投げることができます。

f:id:k1z3:20190705225519p:plain

↑こう書いたときに、↓こう解釈されます(青い部分がpathで指定した内容)。最後に改行を2つ入れるのは HTTP リクエストにおいて空白行はリクエストの終了を意味するからです。

f:id:k1z3:20190705225703p:plain

また、ホスト部分を localhost にすると、webchecker.php はローカルのファイルを見に行きます。これを利用して localhost の password.php を見に行くと、

f:id:k1z3:20190705230321p:plain

期待した通り改行コードが解釈されて処理されているようです。フラグが書かれている行を見たいので、当たりをつけるために Range の値を for で変化させながら探っていきます。シェルスクリプトにおいて数値の計算は$*1 と書かないといけない (2重に括弧で囲う) ので注意が必要でした。

f:id:k1z3:20190705230602p:plain

Range が 11 からになったところで2行目が表示され始めました。

f:id:k1z3:20190705230852p:plain

そのまま見ていくと admin のパスワードが書かれた行のようなので、表示範囲を広くします(最初から広い範囲で for をぶん回しても良かったかも)。

f:id:k1z3:20190705231055p:plain

あとがき

RC4 の部分と vmdk4 の変換 (本 Writeup の場合は qemu-img.exe 使用) を何とかすれば、基本的には CLI で全部解けた事になるかと思います。検証に少し時間かけましたが、qemu や ntfsundelete およびその他の ntfs****** コマンド、tshark など、今まで使ったことのない知識を補充できたので、本 CLI で解いてみた企画は意味あったかな、と思います。
来年はベスト 10 に入れるように頑張りたいです。

*1:var1+var2