(Last modified: )

SECCON Beginners CTF 2019

この記事は、2019年5月27日に旧ブログに投稿したものです。

チームsecurity_gangにABCとして参加しました。チーム全体の順位は33位(2270点)、個人の順位は115位(803点)。

[Reversing] Linear Operation (293)

基本ブロックの数が凄いのでangrを使います。IDAのグラフを見るとcorrectとwrongで基本ブロックが分かれています。 そのアドレスをもとに、http://inaz2.hatenablog.com/entry/2016/03/16/190756https://qiita.com/RKX1209/items/a514e5727119796e9fd5を参考にスクリプトを書きました。

 1import angr
 2
 3p = angr.Project('linear_operation')
 4
 5ok_addr = 0x40cf78
 6ng_addr = 0x40cf86
 7
 8state = p.factory.entry_state()
 9m = p.factory.simulation_manager(state)
10m.explore(find=(ok_addr), avoid=(ng_addr))
11
12print(m.found[0].posix.dumps(0))

ctf4b{5ymbol1c_3xecuti0n_1s_3ffect1ve_4ga1nst_l1n34r_0p3r4ti0n}

[Reversing] linkage (186)

IDAでmainから辿ってみると、is_correctというサブルーチンがあります。それを見てみると、何らかの文字数が34文字の場合、何らかの処理が行われる事がわかります。 おそらく入力値でしょう。

1.text:00000000004005FA                 call    _strlen
2.text:00000000004005FF                 cmp     rax, 22h
3.text:0000000000400603                 jz      short loc_40060C

34文字の場合に何が行われるのかを見ていくと、loc_400615の基本ブロックにおいて、convertサブルーチンが実行された後にそれと何らかの比較を行っている事がわかります。

1.text:0000000000400643                 cmp     [rbp+var_5], al
2.text:0000000000400646                 jz      short loc_40064F

そこで、gdbで0x400643にbreakpointを張り、34文字の入力値を与え実行してみます。そして、breakpointにおける$rbp-0x5$alを見てみます。

 1(gdb) b *0x400643
 2Breakpoint 1 at 0x400643
 3(gdb) r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 4Starting program: ~/leakage_80a8c3c2bd63254a033ea21093944b1e/leakage AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 5
 6Breakpoint 1, 0x0000000000400643 in is_correct ()
 7(gdb) x/s $rbp-0x5
 80x7fffffffe0eb: "c"
 9(gdb) p/x $al
10$1 = 0x41

$rbp-0x5に1文字目のflagが、$alに入力値の1文字目が代入されているようです。 IDAのグラフを見てみると、この箇所はループになっており、$rbp-0x5$alが等しくない場合はループを抜けるようになっています。ゆえに、ループされるたびに0x400643にて$rbp-0x5を見ればフラグが入手できそうです。 そこで、無理矢理ループを行うために、ゼロフラグを強制的に有効にします。gdb zfでググればその方法がヒットするので、それを繰り返し行います。

 1(gdb) ni
 20x0000000000400646 in is_correct ()
 3(gdb) set $eflags |= (1 << 6)
 4(gdb) c
 5Continuing.
 6
 7Breakpoint 1, 0x0000000000400643 in is_correct ()
 8(gdb) b *0x0000000000400646
 9Breakpoint 2 at 0x400646
10(gdb) del 1
11(gdb) x/s $rbp-0x5
120x7fffffffe0eb: "t\001"
13(gdb) set $eflags |= (1 << 6)
14(gdb) c
15Continuing.
16
17Breakpoint 2, 0x0000000000400646 in is_correct ()
18(gdb) x/s $rbp-0x5
190x7fffffffe0eb: "t\001"
20(gdb) set $eflags |= (1 << 6)
21(gdb) c
22Continuing.
23
24Breakpoint 2, 0x0000000000400646 in is_correct ()
25(gdb) x/s $rbp-0x5
260x7fffffffe0eb: "f\002"

x/sはNULL文字に到達するまで出力するため一部ゴミが含まれますが、最初の一文字以外は無視して構いません。 これを34回繰り返せばflagが入手できます。
ctf4b{le4k1ng_th3_f1ag_0ne_by_0ne}

[Misc] Dump (138)

Wiresharkを用いてTCPストリームを追跡すると、webshellを行った形跡が見つかります。 1番目のTCPストリームには何らかのデータがダンプされているようです。 そこで、そのストリームを保存し、ヘッダのエスケープ文字を復元してみます。

1>> decodeURIComponent("/webshell.php?cmd=hexdump%20%2De%20%2716%2F1%20%22%2502%2E3o%20%22%20%22%5Cn%22%27%20%2Fhome%2Fctf4b%2Fflag")
2<- "/webshell.php?cmd=hexdump -e '16/1 \"%02.3o \" \"\\n\"' /home/ctf4b/flag"

どうもこのデータは、/home/ctf4b/flagを8進数でダンプしたものらしいです。 そこで、ダンプデータのみを抽出し、それをバイナリに変換します。

1$ cat data
2037 213 010 000 012 325 251 134 000 003 354 375 007 124 023 133
3327 007 214 117 350 115 272 110 047 012 212 122 223 320 022 252
4(以下略)
1data = ""
2with open("data", "r") as f:
3    for _ in f.readlines():
4        data += _.replace("\n", " ")
5with open("output", "wb") as f:
6    f.write(bytearray(map(lambda x: int(x, 8), data.split(" ")[:-1])))

するとtar.gz形式のoutputが出力されます。それを解凍するとflagが書かれたflag.jpgが展開されます。 ctf4b{hexdump_is_very_useful}

[Crypto] So Tired (115)

解凍するとbase64のテキストファイルが展開され、それをデコードするとzlibファイルが生成され…が繰り返されます。 なのでそれを自動化します。私は2回目のzlibファイルが生産された時点でこのスクリプトを書いたため、encrypt.txtではなくzlibのファイルがsrcとなっています。

 1import zlib
 2import base64
 3
 4src = open('file', 'rb').read()
 5
 6while (True):
 7    try:
 8        decompressed = zlib.decompress(src)
 9        src = base64.b64decode(decompressed)
10    except:
11        zlib.decompress(src)
12        f = open('result', 'wb')
13        f.write(decompressed)
14        f.close()
15        break
1$ cat encrypted.txt | base64 -d > file
2$ python solve.py
3$ cat result
4ctf4b{very_l0ng_l0ng_BASE64_3nc0ding}

[Misc] containers (71)

バイナリエディタで見てみると、pngファイルのヘッダが複数現れています。 データ 抽出 pngでググると、DataCutterというWindows用のソフトウェアがヒットしたため、Wineでそれを実行してpngを抽出しました。 最後の方にあったフラグ検証のpyファイルは抽出できなかったので、手動でコピペしました。

Powered by Hugo & Kiss.