SECCON CTF 2022 writeup

Reversing問題を3問取り組んで、1問のみ解けました。残りは、最後の最後が分からず断念したものが1問、時間切れが1問でした。

babycmp

フラグを引数に入力するため、argv[1]に入力文字が含まれます。ファイルはx86-64のELFなので、sizeof(char*) = 8であり、呼び出し規約より第2引数はRSIレジスタです。 main関数で[rsi+8]と(mov rbp,rsiより同等な)[rbp+8]に注目すると、1文字ずつWelcome to SECCON 2022とXORしていました。main+DB以降、XORした文字列と変数の値とを比較していたため、それをXORしたところフラグが出ました。

 1a = [0x04, 0x20, 0x2F, 0x20, 0x20, 0x23, 0x1E, 0x59, 0x44, 0x1A, 
 2    0x7F, 0x35, 0x75, 0x36, 0x2D, 0x2B, 0x11, 0x17, 0x5A, 0x03, 
 3    0x6D, 0x50, 0x36, 0x07, 0x15, 0x3C, 0x09, 0x01, 0x04, 0x47, 
 4    0x2B, 0x36, 0x41, 0x0A, 0x38]
 5
 6out = ""
 7for n, s in enumerate(a):
 8    out += chr(ord(("Welcome to SECCON 2022"*2)[n]) ^ s)
 9
10print(out)

SECCON{y0u_f0und_7h3_baby_flag_YaY}

eguite

テキストボックスにFlagを入力してCHECKボタンをクリックすると正解か否かを表示してくれるファイルが2つ渡されます。(片方はPE、もう片方はELFで動きは同じとのことです)
IDAで見ると大量のマングル名が出ますが、GUIでマングル付きということはデマングル後が「onClick」か「on_click」のサブルーチンがあるだろうと推測して探してみると、eguite::Crackme::onclickを発見しました。

中身を見てみると、はじめにSECCON{}、そして括弧の中身の13文字目、20文字目、27文字目に-が含まれているかをチェックしていました。 その後ろに、from_str_radixで文字列を16進数の数値として扱う箇所があり、その結果をlea命令とxor命令で演算した結果がハードコードされた数値と一致しているかを確認していました。

-で区切られる数値を左からa, b, c, d(すなわちSECCON{a-b-c-d})とした場合、式は次のとおりです。

b + a = 0x8B228BF35F6A
c + b = 0xE78241
d + c = 0xFA4C1A9F
a + d = 0x8B238557F7C8
c XOR b XOR d = 0xF9686F4D

これが解けずに諦めました。

eldercmp

__detect_debuggerにおいて、sigaction0x0B(SIGSEGV)のシグナルをtrampolineというサブルーチンに変更しています。 arch_prctlARCH_SET_CPUIDを無効にするため、mainにあるcpuid命令でSIGSEGVが発生し、trampolineに移ります。

その後、heartというサブルーチンに移り、hltなどの命令でSIGSEGVを呼んでtrampolineに移る作業を繰り返しています。 この時に例外を発生した命令を参照しているようで、ソフトウェアブレークポイントによる0xccが含まれているとexitするようです。 そうでない場合、trampolineはSIGSEGVを発生した次の命令にジャンプするため、結局のところheartの中身を見ればエンコード方法がわかります。 なお、XORされていて分かりにくいですが、heart+9C8Correct!をputsする基本ブロックです。

エンコード方法を基に、エンコード後がheart+91Bのハードコードされた値になるような入力を求めれば良さそうです。

が、デコードする方法を考えているうちに時間切れでした。

Powered by Hugo & Kiss.