Writeup: Beginners CTF 2019 [Reversing][warmup] Seccompare

問題ファイルの分析

与えられたファイルを解凍すると「seccompare」 というファイルが出てくる。 このファイルを fileコマンドで確認する。

$ file seccompare
seccompare: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=4a607c82ea263205071c80295afe633412cda6f7, not stripped

出力結果から、ELF形式の実行ファイルであることがわかる。

gdbで処理の流れを確認する

まずは、gdm を使ってファイルを読み込ませる。

$ gdb ./seccompare

disasコマンドを使用して main処理の流れを確認する。

(gdb) disas main
Dump of assembler code for function main:
   0x00000000004005e7 <+0>:	push   %rbp
   0x00000000004005e8 <+1>:	mov    %rsp,%rbp
   0x00000000004005eb <+4>:	sub    $0x40,%rsp
   0x00000000004005ef <+8>:	mov    %edi,-0x34(%rbp)
   0x00000000004005f2 <+11>:	mov    %rsi,-0x40(%rbp)
   0x00000000004005f6 <+15>:	mov    %fs:0x28,%rax
   0x00000000004005ff <+24>:	mov    %rax,-0x8(%rbp)
   0x0000000000400603 <+28>:	xor    %eax,%eax
   0x0000000000400605 <+30>:	cmpl   $0x1,-0x34(%rbp)
   0x0000000000400609 <+34>:	jg     0x400630 <main+73>
   0x000000000040060b <+36>:	mov    -0x40(%rbp),%rax
   0x000000000040060f <+40>:	mov    (%rax),%rax
   0x0000000000400612 <+43>:	mov    %rax,%rsi
   0x0000000000400615 <+46>:	lea    0x168(%rip),%rdi        # 0x400784
   0x000000000040061c <+53>:	mov    $0x0,%eax
   0x0000000000400621 <+58>:	callq  0x4004e0 <printf@plt>
   0x0000000000400626 <+63>:	mov    $0x1,%eax
   0x000000000040062b <+68>:	jmpq   0x4006e1 <main+250>
   0x0000000000400630 <+73>:	movb   $0x63,-0x30(%rbp)
   0x0000000000400634 <+77>:	movb   $0x74,-0x2f(%rbp)
   0x0000000000400638 <+81>:	movb   $0x66,-0x2e(%rbp)
   0x000000000040063c <+85>:	movb   $0x34,-0x2d(%rbp)
   0x0000000000400640 <+89>:	movb   $0x62,-0x2c(%rbp)
   0x0000000000400644 <+93>:	movb   $0x7b,-0x2b(%rbp)
   0x0000000000400648 <+97>:	movb   $0x35,-0x2a(%rbp)
   0x000000000040064c <+101>:	movb   $0x74,-0x29(%rbp)
   0x0000000000400650 <+105>:	movb   $0x72,-0x28(%rbp)
   0x0000000000400654 <+109>:	movb   $0x31,-0x27(%rbp)
   0x0000000000400658 <+113>:	movb   $0x6e,-0x26(%rbp)
   0x000000000040065c <+117>:	movb   $0x67,-0x25(%rbp)
   0x0000000000400660 <+121>:	movb   $0x73,-0x24(%rbp)
   0x0000000000400664 <+125>:	movb   $0x5f,-0x23(%rbp)
   0x0000000000400668 <+129>:	movb   $0x31,-0x22(%rbp)
   0x000000000040066c <+133>:	movb   $0x73,-0x21(%rbp)
   0x0000000000400670 <+137>:	movb   $0x5f,-0x20(%rbp)
   0x0000000000400674 <+141>:	movb   $0x6e,-0x1f(%rbp)
   0x0000000000400678 <+145>:	movb   $0x30,-0x1e(%rbp)
   0x000000000040067c <+149>:	movb   $0x74,-0x1d(%rbp)
   0x0000000000400680 <+153>:	movb   $0x5f,-0x1c(%rbp)
   0x0000000000400684 <+157>:	movb   $0x65,-0x1b(%rbp)
   0x0000000000400688 <+161>:	movb   $0x6e,-0x1a(%rbp)
   0x000000000040068c <+165>:	movb   $0x30,-0x19(%rbp)
   0x0000000000400690 <+169>:	movb   $0x75,-0x18(%rbp)
   0x0000000000400694 <+173>:	movb   $0x67,-0x17(%rbp)
   0x0000000000400698 <+177>:	movb   $0x68,-0x16(%rbp)
   0x000000000040069c <+181>:	movb   $0x7d,-0x15(%rbp)
   0x00000000004006a0 <+185>:	movb   $0x0,-0x14(%rbp)
   0x00000000004006a4 <+189>:	mov    -0x40(%rbp),%rax
   0x00000000004006a8 <+193>:	add    $0x8,%rax
   0x00000000004006ac <+197>:	mov    (%rax),%rdx
   0x00000000004006af <+200>:	lea    -0x30(%rbp),%rax
   0x00000000004006b3 <+204>:	mov    %rdx,%rsi
   0x00000000004006b6 <+207>:	mov    %rax,%rdi
   0x00000000004006b9 <+210>:	callq  0x4004f0 <strcmp@plt>
   0x00000000004006be <+215>:	test   %eax,%eax
   0x00000000004006c0 <+217>:	jne    0x4006d0 <main+233>
   0x00000000004006c2 <+219>:	lea    0xcb(%rip),%rdi        # 0x400794
   0x00000000004006c9 <+226>:	callq  0x4004c0 <puts@plt>
   0x00000000004006ce <+231>:	jmp    0x4006dc <main+245>
   0x00000000004006d0 <+233>:	lea    0xc5(%rip),%rdi        # 0x40079c
   0x00000000004006d7 <+240>:	callq  0x4004c0 <puts@plt>
   0x00000000004006dc <+245>:	mov    $0x0,%eax
   0x00000000004006e1 <+250>:	mov    -0x8(%rbp),%rcx
   0x00000000004006e5 <+254>:	xor    %fs:0x28,%rcx
   0x00000000004006ee <+263>:	je     0x4006f5 <main+270>
   0x00000000004006f0 <+265>:	callq  0x4004d0 <__stack_chk_fail@plt>
   0x00000000004006f5 <+270>:	leaveq 
   0x00000000004006f6 <+271>:	retq   
End of assembler dump.

0x4005e7〜0x40062b で初期処理と、起動時の引数がなかったときの usage表示をする処理。
0x400630〜 flag をメモリ内に生成して 0x4006b9 で strcmp して合否の判断をしている模様。

実際に実行させて flag を得るまで

とりあえず、strcmp をしている 0x4006b9 にブレークポイントを置く。
アドレス指定なので、アドレスの前にアスタリスクをつける。

(gdb) break *0x4006b9
Breakpoint 1 at 0x4006b9

次に、実行をさせるが usage が表示されないようにダミーの引数(“hoge”)を与えておく。

(gdb) r hoge
Starting program: /home/nekotaro/ctf/seccompare/seccompare hoge

Breakpoint 1, 0x00000000004006b9 in main ()
(gdb)

ブレークポイントで無事停止。
必須ではないが、disas すると「=>」 の矢印マークがついて、ブレークポイントで止まっている場所を確認できる。

(gdb) disas main
Dump of assembler code for function main:
   0x00000000004005e7 <+0>:	push   %rbp
   0x00000000004005e8 <+1>:	mov    %rsp,%rbp
   0x00000000004005eb <+4>:	sub    $0x40,%rsp
  (中略)
   0x00000000004006b6 <+207>:	mov    %rax,%rdi
=> 0x00000000004006b9 <+210>:	callq  0x4004f0 <strcmp@plt>
   0x00000000004006be <+215>:	test   %eax,%eax

strcmpに渡そうとしている第1引数と第2引数を確認する。
第1引数は rdi の先に、第2引数は rsi の先にある。

(gdb) x/s $rdi
0x7fffffffdf70:	"ctf4b{5tr1ngs_1s_n0t_en0ugh}"
(gdb) x/s $rsi
0x7fffffffe3d9:	"hoge"

ということで、無事 flag の「ctf4b{5tr1ngs_1s_n0t_en0ugh}」を得ることができた。

ちなみに、余談だがx64のSystem V では、関数(ここれはstrcmp)に渡す引数の対応付はは下記の通り。(第7引数以降はスタックに積まれる)

引数レジスタ
第1引数rdi
第2引数rsi
第3引数rdx
第4引数rcx
第5引数r8
第6引数r9

確認

最後に実際に動作を確認してみる。

$ ./seccompare ctf4b{5tr1ngs_1s_n0t_en0ugh}
correct

無事 correct が表示されたので、flagの提出をしておしまい。

カテゴリーCTF

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です