FLARE On Challenge ソリューション: パート 1/2

news

7 月、FireEye Labs Advanced Reverse Engineering (FLARE) チームは最初のFLARE On Challengeを作成し、コミュニティにリリースしました。総勢7,140名が参加して技を披露し、226名が完走しました。チャレンジを完了した全員に、成功を記念してチャレンジ コインが贈られました。

 

念願のチャレンジコイン

完走できなかった方のスキルアップに役立つチャレンジソリューションを公開しています。各課題を完了するにはさまざまな方法があるため、人々がどのような解決策を考案するかを待ちました.次の解決策がオンラインで投稿されていることがわかりました。これらも参照して、後の課題をさまざまな方法で解決する方法を確認することをお勧めします。

 

 

A Walkthrough for FLARE RE Challenges
The FireEye Labs Advanced Reverse Engineering (FLARE) challenge was causing a bit of a buzz when it was announced and la...
https://www.codeandsec.com/Detailed-Solutions-to-FireEye-FLARE-Challenge

このブログ シリーズの最初の号では、最初の 5 つの課題に焦点を当てます。より簡単な解決策から始めることで、これまで逆転したことがない人にも利益がもたらされることを願っています.以下は、最初の 5 つの課題を解決する方法をまとめたもので、これまで見たことがないかのように書かれています。各チャレンジの目標は、次のチャレンジのロックを解除できる電子メール アドレスの形式のキーを見つけることです。チャレンジのアーカイブは、チャレンジ Web サイトに投稿されています。

第 2 部では、チャレンジ 6 を解決する 2 つの異なる興味深い方法を紹介します。

チャレンジ 1: ボブ・ドージ

最初の課題はかなり簡単に始まります。バイナリを CFF Explorer (または同等の PE ツール) にドロップすると、PE 32 ビット .NET アセンブリを扱っていることが通知されるため、x86 Windows VM で実行して何が起こるかを確認できます。デコード ボタンには 2 つの機能があるようです。Bob Ross を Bob Doge に変換する機能と、トップ ラベルを印刷できない文字列に変換する機能です。バイナリを ILSpy (または同等の .NET 逆コンパイラ) にドロップして、このデコード ボタンが何をしているのかを把握します。逆コンパイルされたコードは、図 1 の上部に示されています。

 

 

図 1: ILSpy でボタン コードをデコード (上) し、Python で再実装 (下)

このボタンは画像を Bob Doge に変更し、リソース文字列を 2 回エンコードして、結果にラベル テキストを設定します。操作されているリソースを保存すると、それをいじることができます。図 1 の右側の Python コードは、何を扱っているかを理解するのに役立つデコード ボタンの再実装です。この Python コードを実行すると、次のように出力され、チャレンジ 1 の解決策が「テキスト 1」として出力されます。

 

図 2: チャレンジ 1 の結果

チャレンジ 2: Javascrap

次の課題 (一部のプレイヤーの悩みの種) は、Windows PE ファイルではありません。代わりに、ウェブサイト www.flare-on.com のバージョンがあります。このバージョンのウェブサイトには何か特別なものがあるに違いありません。そこで、 home.htmlのページソースを見てみます。このバージョンをライブ チャレンジ Web サイトと比較すると、特に 1 つの行が際立っています。

<?php include “img/flare-on.png” ?>

 

PNG 画像が PHP スクリプトとして読み込まれるのはなぜですか?この画像を画像ビューアーで開くとバナーが出てくるので間違いなく画像です。画像が PHP スクリプトとして読み込まれていることがわかっているため、画像ファイル内でphpを検索すると、次のものが見つかります。

19C0 AE 42 60 82 3C 3F 70 68 70 20 24 74 65 72 6D 73 .B`.<?php $terms

19D0 3D 61 72 72 61 79 28 22 4D 22 2C 20 22 5A 22 2C =array(“M”, “Z”,

19E0 20 22 5D 22 2C 20 22 70 22 2C 20 22 5C 5C 22 2C “]”、”p”、””、

19F0 20 22 77 22 2C 20 22 66 22 2C 20 22 31 22 2C 20 “w”, “f”, “1”,

1A00 22 76 22 2C 20 22 3C 22 2C 20 22 61 22 2C 20 22 “v”、”<“、”a”、”

1A10 51 22 2C 20 22 7A 22 2C 20 22 20 22 2C 20 22 73 Q”、”z”、” “、”s

 

これを画像から引き出すと、次のようになります。

<?php

$terms=array(“M”, “Z”, “]”, “p”, “”, “w”, “f”, “1”, “v”,…

$order=array(59, 71, 73, 13, 35, 10, 20, 81, 76, 10, 28, 63, 12,…

$do_me=””;

for($i=0;$i<count($order);$i++)

{

$do_me=$do_me.$terms[$order[$i]];

}

eval($do_me);

?>

 

したがって、文字の配列と、評価される文字列を作成するために使用される文字の配列へのインデックスの配列があります。そのevalechoの呼び出しに置き換えると、ディスプレイに次の文字列が表示されます。

$_= ‘aWYoaXNzZXQoJF9QT1NUWyJcOTdcNDlcNDlcNjhceDRGXDg0XDExNlx4Njh…

$__=’JGNvZGU9YmFzZTY0X2RlY29kZSgkXyk7ZXZhbCgkY29kZSk7′;

$___=”x621x735x36x5f4x653x6f4x65″;

eval($___($__));

 

これにより、より多くの難読化が明らかになります。同じトリックをもう一度適用すると、次のコード行になります。

$code=base64_decode($_);

eval($コード);

 

このことから、$_ 文字列を base64 でデコードする必要があると判断し、見よ、キーを取得しました。

If(isset($_POST[x4F6x68x74x74x44x4Fx54…

{

eval(base64_decode($_POST[“x31x4Fx5464x616…

}

 

これは、16 進数と序数を組み合わせて作成された文字列です。この変換用の簡単なデコーダーを作成すると、 a11DOTthatDOTjava5crapATflareDASHonDOTcomが得られます。次に、「DOT」、「AT」、および「DASH」を対応する文字に置き換えて、キーa11.that.java5crap@flare-on.comを取得します。

チャレンジ 3: シェロロロロール

課題 3 は x86 PE ファイルです。バイナリを IDA Pro にドロップして、何が表示されるかを確認します。

eaxを押す

__getmainargs を呼び出す

esp、14h を追加

mov eax, [ebp+var_24]

eaxを押す

mov eax, [ebp+var_20]

eaxを押す

mov eax, [ebp+var_1C]

eaxを押す

sub_401000 を呼び出す

esp、0Chを追加

mov [ebp+コード], eax

mov eax, [ebp+コード]

eaxを押す

コール出口

 

関数sub_401000は、それより前に呼び出された他のすべての関数に関連付けられたシンボルがあるため、私たちにとって興味深いように見えます。0x401000 はコード セクションの始まりであり、通常はユーザーが作成したコードの始まりが存在します。

EBPをプッシュ

mov ebp、esp

サブ esp、204h

いいえ

mov eax, 0E8h

mov [ebp+var_201], al

移動 eax, 0

mov [ebp+var_200], アル

移動 eax, 0

mov [ebp+var_1FF], al

移動 eax, 0

mov [ebp+var_1FE], al

移動 eax, 0

mov [ebp+var_1FD], al

mov eax, 8Bh

 

ざっと見てみると、1 バイトが 1 つずつスタックに移動されていることがわかります。スタックに移動されるすべてのバイトを通過すると、次のようになります。

lea eax、[ebp+var_201]

eaxに電話する

移動 eax, 0

ジャンプ $+5

 

バイナリは、スタックに移動した最初のバイトの位置を呼び出しているため、シェルコードのバッファを処理する必要があります。この時点で、静的解析は動的解析よりもはるかに手間がかかるため、これをデバッガーにドロップします。

上記の呼び出し eaxにブレークポイントを設定し、シェルコードを呼び出す前にコードを実行してプログラムをキャッチします。これで、図 3 に示すように、スタック メモリをファイルにダンプし、IDA Pro で分析できます。以下の分析はすべてデバッガーで実行できますが、IDA Pro での手順を示すことにしました。

 

図 3: 0×66 デコード ループ

図 3 は、各バイトを 0x66 で XOR することにより、 jmp命令の後のすべてをデコードするループを示しています。スクリプトを実行してデバッガーに再度ダンプするのではなく、デコードを行うスクリプトを作成することにしました。

idaapiをインポート

場所 = 0x1DA0

範囲内の i の場合 (0x1DF):

idaapi.patch_byte(loc+i, idaapi.get_byte(loc+i) ^ 0x66)

 

このスクリプトを実行すると、次のデコードされた文字列が得られます。

00001DA0 aAndSoItBegins db ‘それで始まります’,0

 

同じくデコードされた追加のコードで、別のデコード ループを示しています。

00001DB0 プッシュ「す」

00001DB5 プッシュ「ruas」

00001DBA プッシュ「apon」

00001DBF mov ebx, esp

00001DC1 コール $+5

00001DC6 mov esi, [esp]

00001DC9 esi、2Dh を追加します。 「-」

00001DCC mov ecx、esi

00001DCE 追加 ecx、18Ch

00001DD4 mov eax, ebx

00001DD6 追加 eax、0Ah

00001DD9

00001DD9 loc_1DD9:

00001DD9 cmp eax、ebx

00001DDB jnz ショート loc_1DE2

00001DDD mov ebx, esp

00001DDF 追加 ebx、4

00001DE2

00001DE2 loc_1DE2:

00001DE2 cmp esi、ecx

00001DE4 jz ショート loc_1DEE

00001DE6 mov dl, [ebx]

00001DE8 xor [esi], dl

00001DEA inc ebx

00001DEB inc esi

00001DEC jmp ショート loc_1DD9

 

今回はエンコーディングがマルチバイト XOR であるため、別のスクリプトを記述します。

idaapiをインポート

ロク = 0x1DF3

キー = 「ノパサウルス」

範囲内の i の場合 (0x18C):

idaapi.patch_byte(loc+i,idaapi.get_byte(loc+i)^ord(キー[i%len(キー)]))

 

このようなスクリプトは、マルウェアをリバースしてプログラムが使用する文字列をデコードするときに必要になることがよくあります。このスクリプトが実行された後、デコードされた別の文字列があるため、さらに進んでいるように見えます。

00001DF3 aGetReadyToGetN db ‘get ready to get nop’,27h,’ed so very hard in the paint で

 

これに続いて、図 4 に示すようなコードが追加されました。

 

図 4: GlOb デコード ループ

なんという驚き: 別のデコード ループ。ここまでで、これらのスクリプトをかなりうまく書けるようになったので、別のスクリプトを次に示します。

idaapiをインポート

ロク = 0x1E47

キー = 「bOlG」

範囲内の i の場合 (0x138):

idaapi.patch_byte(loc+i,idaapi.get_byte(loc+i)^ord(キー[i%len(キー)]))

 

これを実行すると、さらにコードを確認できます。これは、「ああ、もうすぐ終わりますか?!? 」のキーを使用した最後のデコード手順です。今回のスクリプトは次のようになります。

idaapiをインポート

場所 = 0x1EA9

key = 「ああ、もうすぐ終わりますか?!?」

範囲内の i の場合 (0xD6):

idaapi.patch_byte(loc+i,idaapi.get_byte(loc+i)^ord(キー[i%len(キー)]))

 

そして、次の鍵があります。

00001EA9 aSuch_5h3110101 デシベル’ such.5h311010101@flare-on.com

 

デバッガーでバイナリ全体をステップ実行することで、同じ結論に達することができました。しかし、IDA Pro のスクリプト作成を少し楽しみたかったのです。

チャレンジ 4: スプロイタスティック

課題 4 では、PDF を調べる必要があります。図 5 に示すように、Adobe Reader 9.0 など、非常に悪用可能な、パッチが適用されていないバージョンの Adobe Reader でこれを開くとどうなるか見てみましょう。

 

図 5: 悪意のある PDF

悪意のある PDF がメッセージ ボックスを開いたように見えるため、 MessageBoxAMessageBoxWにブレークポイントを設定しました。図 6 は、このブレークポイントがヒットしたときのスタック上の引数を示しています。

 

図 6: MessageBoxA の引数

スタックにある文字列から、 MessageBoxAを正しく呼び出していることがわかります。したがって、この呼び出しを行ったアドレスまでさかのぼると、次のシェルコード ブロックが見つかります。

00000000 E8 00 00 00 00 8B 14 24 81 72 0B 16 A3 FB 32 68 …….$.r….2h

00000010 79 CE BE 32 81 72 17 AE 45 CF 48 68 C1 2B E1 2B y..2.r..E.Hh.+.+

00000020 81 72 23 10 36 9F D2 68 71 44 FA FF 81 72 2F F7 .r#.6..hqD…r/.

00000030 A9 A9 0C 68 84 E9 CF 60 81 72 3B BE 93 A9 43 68 …h…`.r;…Ch

00000040 D2 A3 98 37 81 72 47 82 8A 62 3B 68 EF A4 11 4B …7.rG..b;h…K

00000050 81 72 53 D6 47 C0 CC 68 BE 69 A4 FF 81 72 5F A3 .rS.G..hi..r_.

00000060 CA 54 31 68 D4 AB 65 52 8B CC 57 53 51 57 8B F1 .T1h..eR..WSQW..

00000070 89 F7 83 C7 1E 39 FE 7D 0B 81 36 42 45 45 46 83 …..9.}..6BEEF.

00000080 C6 04 EB F1 FF D0 68 65 73 73 01 8B DF 88 5C 24 ……ヘス….$

00000090 03 68 50 72 6F 63 68 45 78 69 74 54 FF 74 24 40 .hProchExitT.t$@

 

これを IDA で調べると、次のことがわかります。

00000359 コール $+5

0000035E mov edx, [esp]

00000361 xor dword ptr [edx+0Bh], 32FBA316h

00000368 プッシュ 32BECE79h

0000036D xor dword ptr [edx+17h], 48CF45AEh

00000374 プッシュ 2BE12BC1h

00000379 xor dword ptr [edx+23h], 0D29F3610h

00000380 プッシュ 0FFFA4471h

00000385 xor dword ptr [edx+2Fh], 0CA9A9F7h

0000038C プッシュ 60CFE984h

00000391 xor dword ptr [edx+3Bh], 43A993BEh

00000398 プッシュ 3798A3D2h

0000039D xor dword ptr [edx+47h], 3B628A82h

000003A4 プッシュ 4B11A4EFh

000003A9 xor dword ptr [edx+53h], 0CCC047D6h

000003B0 プッシュ 0FFA469BEh

000003B5 xor dword ptr [edx+5Fh], 3154CAA3h

000003BC プッシュ 5265ABD4h

000003C1 mov ecx, esp

000003C3 プッシュ ed

000003C4 プッシュ ebx

000003C5 プッシュ ecx

000003C6 プッシュ編集

 

したがって、何らかの方法でスタック上にエンコードされている文字列があるようです。このコードが既に実行された後にブレークポイントがヒットしたため、戻ってデバッガーにこのコードを再度実行させ、スタック上で何が明らかになったかを確認できます。

 

図 7: キーを明らかにするためのブレークポイント

そして、ESP によって参照されている図 7 にあります。これで次の鍵が見つかりました。

チャレンジ 5: 5get_it

課題 5 は Windows PE DLL であるため、これを IDA Pro にドロップし、関数を飛び回って、何か興味深いものが飛び出すかどうかを確認しました。少し跳ね返った後、 0×10001240で始まるこの巨大な関数に出くわしました。この関数は引数を取らず、巨大なスタック文字列を構築しているように見えます。引数を取らないので、デバッガーで関数のエントリに eip を設定して実行してみました。これにより、図 8 に示す画像が表示されます。

 

図 8: チャレンジ 5 メッセージ ボックス

興味深いですが、キーが含まれていないようです。この関数への相互参照を確認すると、図 9 に示す関数にたどり着きます。

 

図 9: メッセージ ボックス関数を呼び出すサブルーチン

それ自体では多くのことはわかりません。この関数は、グローバル変数をチェックしてMessageBoxを開くかどうかを決定し、文字「m」が返されることがわかります。この関数への相互参照は、グラフが図 10 に示されている関数を示しています。

 

図 10: if ステートメント制御関数

この関数は巨大で、何らかの if/else ステートメントが含まれています。その上部に、次のコードが表示されます。

10009ECD movsx edx、[ebp+var_4]

10009ED1 cmp edx, 0DEh

10009ED7 jg loc_1000A3A4

10009EDD movsx eax, [ebp+var_4]

10009EE1 プッシュ eax

10009EE2 コール ds:GetAsyncKeyState

10009EE8 movsx ecx、斧

10009EEB cmp ecx、0FFFF8001h

10009EF1 jnz loc_1000A39F

 

GetAsyncKeyStateに基づく if/else ステートメントは、キーロガーを扱っているように聞こえます。 「m」キーを押すと、特定のグローバル変数が設定され、後でプログラムがメッセージ ボックスをポップアップ表示するようです。では、このグローバル変数dword_100194FCとは何であり、それを設定するものは何でしょうか?これに対する相互参照を図 11 に示します。

 

図 11: dword_100184FC への相互参照

グローバル変数はゼロに初期化され、その後、他の関数がそれを 1 に設定します。これを設定する関数はsub_10009B60で、図 12 に示されています。

 

図 12: 「o」キーストローク機能

これは、「o」キーのキーストロークを処理する関数のようです。最後の条件は、 dword_100194F8が設定されているかどうかを確認し、設定されている場合はdword_100194FCを 1 に設定します。これらのグローバル変数は順番に並んでいるため、ここから勘で遊んでグローバル変数のメモリ アドレスを調べ、次のように名前を付け始めます。

 

これを開始すると、パターンが現れ始めます。

 

パターン「dotcom」が出現するので、残りのグローバル変数 (キー ストロークに基づいてステート マシンを制御する一連のグローバル変数) に対してこれを行うことができることに気付き、最終的なキーl0gging.Ur.5tr0ke5を取得します。 @flare-on.com。

 

参照: https://www.mandiant.com/resources/blog/the-flare-on-challen

Comments

Copied title and URL