SECCON Beginners CTF2021 Writeup [Reversing onlye_read, children, please_not_trace_me, be_angry]

はじめに

久しぶりにCTFに参加して、思うように解けなかったり、そもそも解き方を忘れてたりして時間かかってしまったので戒めとしてReversingのWriteupを書きます。ただしfirmwareは解けなかったので、そのWriteupはないです。。angrを思い出すのに10分かかってた。

Reversing

only_read

Ghidraで文字列を見てみると、Correctという文字列が見つかり、その近くのコードを見てみるとflagらしいものが見つかる。

f:id:kataware8136:20210523144915p:plain
only_read Ghidraの画面

ctf4b{c0n5t4nt_f0ld1ng}

children

Ghidraで文字列を見てみると、以下略。 それっぽ文字列が見つかるがhoge関数の中に見つかるが、ifの条件文なので、目に見えてるものは答えじゃないだろうなと推定。

vvv関数はデータを参照して4倍と進めては、xorしてるだけなので復号してみる。 Ghidra Scriptを使ってもよかったがそんなにたいそうなものでもないので、手動で復号

st = ['cud7f~v7\x7fl','rgw2[qt3{`','nf]w4572W8','5^wpacs6u\x00']

def decode(st):
    res = ''
    for i in range(10):
        res += chr(ord(st[i]) ^ i)
    return res

res = ''
for i in st:
    res += decode(i)
print(res)

ctf4b{p0werfu1_tr4sing_t0015_15_usefu1}

please_not_trace_me

見る限りRC4で暗号化されてるので、復号してあげればよい。keyや暗号化された文字はリファレンスをたどることで簡単に見つかる。

f:id:kataware8136:20210523150410p:plain
暗号化データの初期化部分

f:id:kataware8136:20210523150459p:plain
RC4の鍵

暗号化データは適当にバイナリエディタでファイルとして作成し、次のコードを動かすことで答えが手に入る。

def KSA(key):
    S = list(range(256))
    j = 0
    k = 0
    tmp = 0
    for i in range(256):
        tmp = j + S[i] + ord(key[i % len(key)])
        k = (j >> 0x1f) >> 0x18
        j = (tmp + k & 0xff) - k
        S[i], S[j] = S[j], S[i]
    return S

key = "nickelodeon"
S = KSA(key)

with open('encod_data','rb') as f:
    data = f.read()

res = [0] * len(data)

for i in range(len(data)):
    res[i] = data[i] ^ S[S[0] * 2]

print("".join([chr(i) for i in res]))
#ctf4b{d1d_y0u_d3crypt_rc4?}

ctf4b{d1d_y0u_d3crypt_rc4?}

be_angry

Ghidraで中身を見てみると、入力した文字列に対してSwitch文で分岐して、文字列をチェックしているように見える。

こういったケースではangrを使うと簡単にできるので、angrを使ってみる。

angrで読み込んだ後、Switchの部分にCorrectとなっているアドレスを目的のアドレス、Incorrectとなっている部分のアドレスをavoid_listとして、実行する。 IDAやGhidraで目的のアドレスをメモして起き、メイン関数からのアドレス差で指定してあげるとうまくいく。

(angr) kali@kali:~/angr$ python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import angr
>>> p=angr.Project('/home/kali/Desktop/chall')
WARNING | 2021-05-22 21:53:26,900 | cle.loader | The main binary is a position-independent executable. It is being loaded with a base address of 0x400000.                                                                  
>>> main_addr = p.loader.main_object.get_symbol('main').rebased_addr
SyntaxError: invalid syntax
>>> addr_success = main_addr + 0x139E
>>> avoid_list = (main_addr + 477,main_addr + 666,main_addr + 1964,main_addr + 1992,main_addr + 3353,main_addr + 3549,main_addr + 3706,main_addr + 3734,main_addr + 4994,main_addr + 5106,main_addr + 5417)
>>> sim = p.factory.simgr()
>>> sim.explore(find=addr_success, avoid=avoid_list)
WARNING | 2021-05-22 22:18:36,454 | angr.storage.memory_mixins.default_filler_mixin | The program is accessing memory or registers with an unspecified value. This could indicate unwanted behavior.                        
WARNING | 2021-05-22 22:18:36,454 | angr.storage.memory_mixins.default_filler_mixin | angr will cope with this by generating an unconstrained symbolic variable and continuing. You can resolve this by:                    
WARNING | 2021-05-22 22:18:36,454 | angr.storage.memory_mixins.default_filler_mixin | 1) setting a value to the initial state                                                                                               
WARNING | 2021-05-22 22:18:36,454 | angr.storage.memory_mixins.default_filler_mixin | 2) adding the state option ZERO_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to make unknown regions hold null                              
WARNING | 2021-05-22 22:18:36,454 | angr.storage.memory_mixins.default_filler_mixin | 3) adding the state option SYMBOL_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to suppress these messages.                                  
WARNING | 2021-05-22 22:18:36,454 | angr.storage.memory_mixins.default_filler_mixin | Filling register id with 8 unconstrained bytes referenced from 0x4028f9 (_1_main_flag_func_4+0x1f in chall (0x28f9))                  
WARNING | 2021-05-22 22:18:36,455 | angr.storage.memory_mixins.default_filler_mixin | Filling register ac with 8 unconstrained bytes referenced from 0x4028f9 (_1_main_flag_func_4+0x1f in chall (0x28f9))                  
<SimulationManager with 13 deadended, 1 found, 11 avoid>
>>> s = sim.found[0]
>>> s.posix.dumps(0)
b'ctf4b{3nc0d3_4r1thm3t1c}'

ctf4b{3nc0d3_4r1thm3t1c}