Flare-On Challenge 9 WriteUp

リバースエンジニアリング専門のCTF Flare-On Challenge。今年で9回目の開催で、自分は4回目の参戦である。

今年は自己最多、第4問まで解くことができた。

1問目〜4問目の解法及び5問目の試行錯誤をまとめておく。

主催者公式のWrite Up はこちら

01 Flaredle

flare-on.com/flaredle/ で実行されているプログラムを解析する問題。

ソースコードとして以下の4つのファイルが渡された。

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2022-09-14 01:42:33 ....A         2826         4192  index.html
2022-09-14 01:24:18 ....A         5803               script.js
2022-09-14 01:39:50 ....A          885               style.css
2022-09-13 22:33:29 ....A         4613               words.js
------------------- ----- ------------ ------------  ------------------------
2022-09-14 01:42:33              14127         4192  4 files

このうちindex.htmlは単なるUIで、プログラムの核となるコードはindex.htmlが読み込んでいるscript.jsに記述されている。

<script
src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<script src="script.js" type="module"></script>
</body>
</html>

script.jsを眺めたところ、109行目に気になるコードを見つけた。

    if (guessString === rightGuessString) {
		let flag = rightGuessString + '@flare-on.com';
		toastr.options.timeOut = 0;
		toastr.options.onclick = function() {alert(flag);}
        toastr.success('You guessed right! The flag is ' + flag);

        guessesRemaining = 0
        return

guessStringrightGuessStringが一致した場合、フラグをトーストメッセージで表示する模様。

script.jsの冒頭にrightGuessStringが定義されていた。

import { WORDS } from "./words.js";

const NUMBER_OF_GUESSES = 6;
const WORD_LENGTH = 21;
const CORRECT_GUESS = 57;
let guessesRemaining = NUMBER_OF_GUESSES;
let currentGuess = [];
let nextLetter = 0;
let rightGuessString = WORDS[CORRECT_GUESS];

words.js から読み込まれた値がrightGuessStringに格納される模様。

words.jsはワードのリストだった。

export const WORDS = ['acetylphenylhydrazine',
	'aerobacteriologically',
	'alkylbenzenesulfonate',
	'aminoacetophenetidine',
	'anatomicopathological',
	'anemometrographically',
	'anthropoclimatologist',
	'anthropomorphological',
	'anticonstitutionalism',
	'anticonstitutionalist',
	'antienvironmentalists',

---------- <snipped> --------------------

ここまで判明したところで、script.jsにブレークポインをセットしてrightGuessStringの中身を見ることができればフラグを取れるのでは?と当たりをつける。

http://flare-on.com/flaredle/にアクセスし、ChromeのDeveloper toolsを起動してscript.jsの109行目 (if (guessString === rightGuessString) {)にブレークポイントをセットし、試しにwords.jsの一番最初のワードのacetylphenylhydrazineを入力してみた。

rightGuessf####o##s##labou##atsという文字が格納されているのが分かる。どうやらフラグ文字列の断片の模様。

words.jsからワードを順番に入力してrightGuessの中のデータを観察してみたところ、4回目の入力を終えた時点でfl#r#onis#llabou#catsというフラグ文字列を入手できた。

この時点で、フラグがflareonisallaboutcats (flareon is all about cats)であることが分かった。

02 Pixel Poker

32ビットのEXEファイルを解析する問題。

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2022-09-13 03:03:57 .....          143          144  readme.txt
2022-09-10 02:47:24 ....A      2930688      2887328  PixelPoker.exe
------------------- ----- ------------ ------------  ------------------------
2022-09-13 03:03:57            2930831      2887472  2 files
$ cat readme.txt 
Welcome to PixelPoker ^_^, the pixel game that's sweeping the nation!

Your goal is simple: find the correct pixel and click it

Good luck!

正しいピクセルを見つけてクリックしろとのこと。早速PixelPoker.exeを起動してみる。

カーソルを移動させるとウィンドウ上部にカーソルの座標が表示され、ピクセルをクリックすると#1/10という風にカウントが更新される。

10回以内に正しいピクセルをクリックしないとプログラムは終了してしまう。

マウスをクリックした時の処理を調べれば何か分かるのではと思い、ファイルをIDAで開いてアセンブリを眺めたところ、どうやらサブルーチン0x4015D0にてカーソルの座標を取得しているらしいことが分かった。このサブルーチンはアドレス0x4014B8と0x40156Eでcallされる。

しかし、プログラムをデバッグしたところ、プログラムを普通に実行すると常にアドレス0x40156Eのcall命令が呼び出されて、アドレス0x4014B8のcall命令は呼び出されないことが分かった。

プログラムをデバッグして、アドレス0x4014B8のcall命令に処理を飛ばせば何か変化が現れるのではと思いアセンブリを眺めたところ、アドレス0x4014B8のcall命令を呼び出すには以下の二つのジャンプ命令のチェックをクリアする必要があることが分かった。

二つのジャンプ命令の直前のcmp命令にブレークポイントをセットして、ediとebxの値がedxの値と等しくなるように値を書き換えてプログラムを実行したところ、アドレス0x4014B8のcall命令に処理が移り、フラグを取得できた。

03 Magic 8 Ball

32ビットのEXEファイルを解析する問題。

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2022-10-01 02:26:56 D....            0            0  assets
2022-08-12 07:08:58 ....A        18574       365088  assets/ball_paint.png
2022-07-25 20:19:44 ....A       190044               assets/DroidSans.ttf
2011-02-02 12:00:00 ....A        11560               assets/LICENSE.txt
2013-02-27 12:00:00 ....A       556216               assets/NotoSans_Regular.ttf
2013-02-27 12:00:00 .....         4449               assets/OFL.txt
2011-02-02 12:00:00 ....A       129796               assets/OpenSans_regular.ttf
2019-06-30 09:52:48 ....A       224256      1597504  libjpeg-9.dll
2019-06-30 09:52:48 ....A       198656               libpng16-16.dll
2019-06-30 09:52:48 ....A       428544               libtiff-5.dll
2019-06-30 09:52:48 ....A       415744               libwebp-7.dll
2022-10-01 00:55:20 ....A        20992               Magic8Ball.exe
2022-04-25 23:12:08 ....A      2041856               SDL2.dll
2019-06-30 09:52:48 ....A       117248               SDL2_image.dll
2022-01-11 23:22:34 ....A      1467904               SDL2_ttf.dll
2019-06-30 09:52:48 ....A       103424               zlib1.dll
------------------- ----- ------------ ------------  ------------------------
2022-10-01 02:26:56            5929263      1962592  15 files, 1 folders

色々ファイルがあるが、ひとまずMagic8Ball.exeに絞って解析してみた。

Magic8Ball.exeはASLRが有効化されているので、デバッグの際はあらかじめASLRを無効化しておく。

Magic8Ball.exeを起動してみた。

何か質問を入力するように言われる。また方向キーを押すことで矢印のアイコンを揺らすことができるらしい。

試しに適当に質問を入力すると回答が返ってきた。

これらの回答はプログラムにハードコードされていた。一見してフラグに関する回答は無さそうだった。

アセンブリを眺めていると、gimme flag pls? という文字列を見つけた。

試しにgimme flag pls? という質問を入力してみたがフラグは現れなかった。

引き続きアセンブリを眺めるとアドレス0x40225Bにて気になるcmp命令を発見した。

プログラムを普通に実行するとcmp命令直後のジャンプ命令によって常にアドレス0x402261のmov命令に処理が飛ぶことが分かった。

試しにcmp命令にブレークポイントをセットしてesi+14hの値をいじって0x402261のmov命令をスキップすると、プログラムの画面に変化が現れた。

この状態でgimme flag pls?と入力してみたがフラグは現れなかった

デバッグの結果、esi+14h付近にはユーザーの入力バッファが格納されていることが分かった。以下はesi+14hのメモリのダンプ画面である。質問した内容が格納されているのが分かる。

フラグを取得するにはまだ何かしらのチェックを突破する必要があるようである。

アセンブリを眺め続けていると、アドレス0x40276Aに何やら気になるstrncmpを発見した。解析の結果、このstrncmpはユーザーの入力した質問とLLURULDULという文字列を比較していることが分かった。

さらに解析を進めたところ、LLURULDULは方向キーの組み合わせを表していることが分かった。

  • L (Left) : 左方向キー ←
  • R (Right) : 右方向キー →
  • U (Up) : 上方向キー ↑
  • D (Down) : 下方向キー ↓

つまりLLURULDUL←←↑→↑←↓↑←の順番で方向キーを押せという意味である。

以下は上記の順番で方向キーを押した時のesi+14hのメモリのダンプ画面である。

LLURULDULという値が格納されているのが分かる。

strncmpの結果、2つの文字列が等しかった場合、アドレス0x402777へと処理が移る。何やら気になるサブルーチンが2つcallされている。strncmpではgimme flag pls?LLURULDULという異なる文字列が比較されるので、アドレス0x402777以降の処理へ飛ぶにはtest命令の結果をいじる必要がある。

ここまで判明したところで、以下の手順でプログラムを実行してみた。

  1. あらかじめアドレス0x40225Bのcmp命令にブレークポイントをセットし、ブレークポイントに到達したら、esi+14hの値をいじって直後のmov命令をスキップさせる。
  2. gimme flag pls?と入力してEnter。
  3. 続いて、←←↑→↑←↓↑← の順番で方向キーを押してEnter。
  4. あらかじめアドレス0x402773のtest命令にブレークポイントをセットし、ブレークポイントに到達したら、eaxの値を0x00に書き換えてアドレス0x402777以降の処理へジャンプさせる。

上記の手順でプログラムを実行したところ、フラグが現れた。

04 darn_mice

32ビットのEXEファイルを解析する問題。

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2022-09-15 04:55:57 ....A       103424        49888  darn_mice.exe
------------------- ----- ------------ ------------  ------------------------
2022-09-15 04:55:57             103424        49888  1 files

darn_mice.exeはASLRが有効化されているので、デバッグの際はあらかじめASLRを無効化しておく。

darn_mice.exeはコマンドライン・プログラムのため、ターミナルから起動する必要がある。

試しに適当な引数と共に実行してみたら、On your plate, you see four olives. You leave the room, and a mouse EATS one! というメッセージと共にプログラムが終了した。

IDAとデバッガを駆使してプログラムを解析したところ、以下のことが判明した。

  • フラグを取得するにはプログラムの引数にパスワードを渡さなければいけない。正しいパスワードを渡すと何らかの復号処理が走り、フラグが表示される。
  • パスワードのサイズは35バイト。パスワードが35バイトよりも大きいとNo, nevermind.というメッセージと共にプログラムが終了する。

以下のコードは引数に渡されたパスワードが35バイトよりも大きいか確認している。

パスワードが正しかった場合、最終的に以下のコードに処理が飛び、フラグが表示される。

サブルーチン 0x401280の中では、BCryptOpenAlgorithmProviderやBCryptDeriveKeyPBKDF2などの暗号に関する関数が呼び出されている。また引数に暗号化されたフラグ、ユーザーの入力したパスワード、そしてソルトとしてsaltyという文字列が渡されている。よってサブルーチン 0x401280はフラグの復号を行う関数と思われる。

引き続き解析を続けると、プログラムの冒頭に何やら気になるmov命令を発見した。

変数に0x505E5EA34F5B515E5E97A38090A38090A38090A38090A38090A38090A38090A2A36B7Fというデータが1バイトずつ格納されている。この変数の動きを追ってみると以下のコードに辿り着いた。

上記のコードは

  1. VirtualAllocでメモリ領域を確保する。
  2. ユーザーの入力したパスワードと先述した不審な変数のデータを1バイトずつadd する。(key[0] + password[0]、key[1] + password[1]、 ...)
  3. 2.でaddされた値をVirtualAllocで確保されたメモリ領域に格納して、そのメモリ領域をcallする。

VirtualAllocやアドレス0x40115Cのcall命令にブレークポイントをセットしてデバッグすれば、何か手がかりが掴めそうである。

早速ブレークポイントをセットし、パスワードとして適当な文字を渡してみたが特に進展はなかった。(ちなみにx32dbgでプログラムを引数つきでデバッグしたい場合は、FileメニューからChange Command Lineを選択して引数を指定する)

一旦デバッガから離れ、ダメもとで先述したソルト文字のsaltyを引数に渡してプログラムを実行してみたが、やはりダメだった。

諦めきれずsaltyという文字を色々いじってプログラムに渡し続けていると、パスワードにsの1文字だけを指定するとプログラムに変化が現れることに気づいた。

何やらランダムなデータが吐き出されている。

再びデバッガに戻って引数にsの1文字を指定してプログラムを実行してみた。

アドレス0x40115Cのcall命令にブレークポイントが達したら、F7でステップイン実行してみた。

以下はステップイン実行後の画面である。ret命令が呼び出されているのが分かる。

一体、このret命令はどこから来たのか?もう一度、VirtualAlloc以下のコードの動きを思い出してみる。

  1. VirtualAllocでメモリ領域を確保する。
  2. ユーザーの入力したパスワードと先述した不審な変数のデータを1バイトずつadd する。(key[0] + password[0]、key[1] + password[1]、 ...)
  3. 2.でaddされた値をVirtualAllocで確保されたメモリ領域に格納して、そのメモリ領域をcallする。

つまり、パスワードとして入力した0x73 (s)と不審な変数の先頭1バイトの値0x50がaddされて0xC3になり、callされたのである。

>>> hex(0x73 + 0x50)
'0xc3'

0xC3はret命令を表すオペコードである。つまりアドレス0x40115Cのcall命令は単にretを呼び出しているだけである。ret命令はcallの完了後に次の命令へとプログラムの実行を戻すための命令なので、アドレス0x40115Cのcall命令が実行されると、callの次のpush命令へと処理が移る。

以上より、パスワードは以下の条件を満たす文字列ということになる。

password[n] + key[n] = 0xC3

このうち、keyの値はハードコードされている。0xC3からkeyの値を引けば、パスワードの値を求めることができる。

以下のスクリプトを実行してパスワードを取得した。

import binascii

unhexed = binascii.unhexlify('505E5EA34F5B515E5E97A38090A38090A38090A38090A38090A38090A38090A2A36B7F')
keys = bytearray(unhexed)
password = ''

for i in range(len(keys)):
	password += chr(0xc3 - keys[i])
	
print(password)
$ python3 password-identifier.py 
see three, C3 C3 C3 C3 C3 C3 C3! XD

パスワードにsee three, C3 C3 C3 C3 C3 C3 C3! XDを指定してプログラムを実行してみたところ、フラグを取得できた。

05 T8

32ビットのEXEファイルを解析する問題。解析対象のファイルによって生成されたネットワーク通信のPCAPも一緒に渡される。

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2022-06-15 00:17:59 ....A         3904         1600  traffic.pcapng
2022-08-23 00:14:02 ....A       341504       129104  t8.exe
------------------- ----- ------------ ------------  ------------------------
2022-08-23 00:14:02             345408       130704  2 files

※ t8.exeはASLRが有効化されているので、デバッグの際はあらかじめASLRを無効化しておく。
t8.exeのコーディングにはC++が用いられていると思われる。

traffic.pcapngには以下のHTTPのPOST通信がキャプチャされていた。

POST / HTTP/1.1
Connection: Keep-Alive
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; 11950)
Content-Length: 24
Host: flare-on.com

y.d.N.8.B.X.q.1.6.R.E.=.

HTTP/1.0 200 OK
Server: Apache On 9 
Date: Tue, 14 Jun 2022 16:14:36 GMT

TdQdBRa1nxGU06dbB27E7SQ7TJ2+cd7zstLXRQcLbmh2nTvDm1p5IfT/Cu0JxShk6tHQBRWwPlo9zA1dISfslkLgGDs41WK12ibWIflqLE4Yq3OYIEnLNjwVHrjL2U4Lu3ms+HQc4nfMWXPgcOHb4fhokk93/AJd5GTuC5z+4YsmgRh1Z90yinLBKB+fmGUyagT6gon/KHmJdvAOQ8nAnl8K/0XG+8zYQbZRwgY6tHvvpfyn9OXCyuct5/cOi8KWgALvVHQWafrp8qB/JtT+t5zmnezQlp3zPL4sj2CJfcUTK5copbZCyHexVD4jJN+LezJEtrDXP1DJNg==
POST / HTTP/1.1
Connection: Keep-Alive
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; CLR)
Content-Length: 16
Host: flare-on.com

V.Y.B.U.p.Z.d.G.

HTTP/1.0 200 OK
Server: Apache On 9 
Date: Tue, 14 Jun 2022 16:14:36 GMT

F1KFlZbNGuKQxrTD/ORwudM8S8kKiL5F906YlR8TKd8XrKPeDYZ0HouiBamyQf9/Ns7u3C2UEMLoCA0B8EuZp1FpwnedVjPSdZFjkieYqWzKA7up+LYe9B4dmAUM2lYkmBSqPJYT6nEg27n3X656MMOxNIHt0HsOD0d+

POSTのボディ部分とサーバーからのレスポンスはBase64エンコードの他にも何らかの暗号化が噛ませてあるようで、Base64デコードしただけでは意味のあるデータに復号されない。

t8.exeをIDAで眺めたところ、どうやらサブルーチン0x404680がmain関数である模様。

main関数の冒頭に以下の処理を発見した。

上記の処理はプログラムを長時間スリープさせる。またサブルーチン0x404570も何らかの遅延行為を行う。動的解析する際は上記の処理をNOPするなりして回避する必要がある。

PCAPにキャプチャされていたflare-on.comというホスト名はXOR暗号化された状態でt8.exeにハードコードされていた。以下の処理は鍵0x11を用いてホスト名flare-on.comをXOR復号している。

以下の処理は鍵0x45を用いてPOSTという文字列をXOR復号する。HTTP通信のPOSTメソッドを復号するための処理である。

以下のサブルーチン0x4025B0は4〜5桁のランダムな数字を生成する。生成された数字は後にFO9という文字列と連結される。(例: FO912961

さらに解析を進めると、以下の気になるサブルーチンを発見した。

サブルーチン0x405450はプログラムが以降の処理で使用する仮想関数を決定するための関数と思われる。

仮想関数の一覧はアドレス0x44B918にて確認できる。

アドレス0x4048DAのcall命令では仮想関数0x4037A0がcallされる。

仮想関数0x4037A0は先述したFO9<ランダムな数字>を引数に受け取り、ハッシュ値を計算する。

以下のデバッグ画面より、FO99594という値を受け取って、63e0e0fe7385013bf2350a066e44cbcfというハッシュ値を返しているのが分かる。

ただし、このハッシュ値がどのように計算されているのかは分からなかった。ハッシュの長さ的にMD5ハッシュ値だと思うのだが、FO99594のMD5ハッシュ値は87935a9c0eead3daf35a662ffce0fdc5であって、63e0e0fe7385013bf2350a066e44cbcfではない。

$ echo -n FO99594 | md5
87935a9c0eead3daf35a662ffce0fdc5

引き続き解析を進める。以下の処理は鍵0x78を用いてahoyという文字列をXOR復号する。

このahoyという文字列は後にサブルーチン0x4025B0で生成されたランダムな数字と連結される。(例: 2961ahoy

ホスト flare-on.com との通信は以下のcall命令によって実行される。

上記のcall命令はサブルーチン0x403D70を呼び出す。

サブルーチン0x403D70の働きは以下の通り。

  • サーバーに送信するデータにBase64エンコードを施す。何のデータをエンコードしているのかは厳密には分からなかった。
  • HTTPのPOST通信のボディ部分にエンコードしたデータを乗せてflare-on.comへと送信する。
  • flare-on.comからの応答データを受け取る。

flare-on.comからの応答データは以下のcall命令によって処理される。

上記のcall命令はサブルーチン0x403CE0を呼び出す。このサブルーチンはflare-on.comから応答されたデータをBase64デコードする。(実際のデコード処理は内部でcallされているサブルーチン0x401D90が行う。)

上の画像はflare-on.comから応答されたデータをサブルーチン0x401D90が処理している様子である。(本当にflare-on.comと通信している訳ではなく、FakeNet-NGで通信をエミュレートしている。\Python27\Lib\site-packages\fakenet\defaultFiles\FakeNet.html を編集してflare-on.comへHTTP通信が発生すると任意のデータを返すように設定した。)

冒頭でも述べたように、サーバーからのレスポンスはBase64エンコードの他にも何らかの暗号化が噛ませてあるようで、Base64デコードしただけでは意味のあるデータに復号されない。

flare-on.comへのHTTP POST通信は合計2回発生する。

2回目のHTTP POST通信が完了すると、以下の処理へ飛ぶ。

上記の処理は恐らく。。

  • flare-on.com からの応答データを復号する。(アドレス 0x403B42)
  • 復号されたコードを展開するためのメモリ領域をVirtualAllocで確保する。(アドレス 0x403B57)
  • 復号されたコードをcallする。(アドレス 0x403B79)

デバッガを駆使して、traffic.pcapngにキャプチャされていたものと同一のHTTP POSTのデータを送信し、FakeNet-NGを駆使してPCAPにキャプチャされていたものと同一の応答データを返すようにしてプログラムを実行してみたが、フラグ取得に関する手がかりは見つからなかった。

以下はレジスタの値を書き換えてtraffic.pcapngと同一のHTTPのリクエストとレスポンスを生成した際のデバッグ画面である。

以下は2度目のHTTPレスポンスが完了した後のデバッグの様子である。z@flare-on.com という文字列がecxレジスタにロードされた後、push命令によってスタックに積まれ、アドレス 0x403B42のcall命令の引数として渡されている。このcall命令はサブルーチン 0x4043F0を呼び出す。何の処理を行うためのサブルーチンかは分からなかった。またz@flare-on.com@以前の1文字はzで固定されている訳ではなく、変化する。

以下はサブルーチン 0x4043F0が実行された後のデバッグの様子である。eaxレジスタにpLTというデータが格納されているが、何のデータかは分からなかった。このpLTというデータも固定ではなく、変化する。

以下はVirtualAllocの後のcall命令 call esi をステップ・イン実行した際の様子である。恐らくflare-on.comからの応答データが正しく復号されると、VirtualAllocで確保されたメモリ領域に何らかのコードが展開されると思われるのだが、2つ目の画像からも分かる通り、有効なアセンブリ命令になっていない。

この辺で解析のアイディアが尽きてしまった。

追記

公式のWrite UPによると、HTTPのPOSTリクエストおよびサーバーのレスポンスはRC4暗号化された上でBase64エンコードされている。RC4の復号鍵はFO9<ランダムな数字>のMD5ハッシュ値である。

ただし、注意点としてFO9<ランダムな数字>はUTF-16LE形式に変換されているので、(この文字コードの変換はサブルーチン 0x403770にて行われる)、手動でMD5ハッシュ値を計算する場合はUTF-16LE形式に変換してから計算する必要がある。

FO9<ランダムな数字>のランダムな数字は1回目のHTTPのPOSTリクエストを送信する際にユーザーエージェントの末尾に付与される。以下はtraffic.pcapngにキャプチャされていたユーザーエージェントの情報である。末尾に11950という数字が確認できる。

User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; 11950)

このことから、RC4復号鍵はFO911950のMD5ハッシュ値であることが判明した。ただし、先述したようにFO911950はUTF-16LE形式に変換されているので、ハッシュを計算する際は文字コードの変換を忘れずに行う必要がある。

以下は、UTF-16LE形式への変換をせずにMD5ハッシュ値を計算した場合のハッシュ値である。

$ echo -n FO911950 | md5
767bf5280dbbe0b7b9e9d10fc9629506

以下は、UTF-16LE形式への変換後に、MD5ハッシュ値を計算した場合のハッシュ値である。

>>> import hashlib
>>> rc4key = hashlib.md5('FO911950'.encode('utf-16le'))
>>> print(rc4key.hexdigest())
a5c6993299429aa7b900211d4a279848

この場合、正しいハッシュ値はa5c6993299429aa7b900211d4a279848である。

以上を踏まえて、以下の手順でデバッグを実施したところフラグを取得できた。 (FakeNet-NGでクライアント・サーバー通信をエミュレートしている前提)

サブルーチン 0x4025B0 (ランダムな数字を生成するためのサブルーチン)のcall直後にブレークポイントをセットし、eaxの値を11950に上書きする。

デバッガを実行する。2回目のHTTPの通信が完了すると、スタック上にフラグが確認できた。

ユーザーエージェントの数字と文字コードの件に気づいていれば解けた。。。。かも。。?

Leave a Reply

Your email address will not be published. Required fields are marked *