32位程序的ROP攻击示例
给定的程序
readelf32存在一个漏洞(想多了,这当然不是Linux里的readelf),它读取文件内容写入到一个局部变量,但没有正确地检查文件大小。
实验中假设 ASLR 已经关闭: 1
echo 0 >/proc/sys/kernel/randomize_va_space
用 IDA Pro 反编译得到如下伪代码,其中数组的名字和大小是我自己修改的:
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
嗯,一个明显的不能再明显的越界。我们要做的是,利用越界修改栈,使得程序执行我们想要的代码。本题中,我们想删除一个文件“data”,所以要做的事情有:
- 系统调用:
unlink("data") - 系统调用:
exit(0)
Linux系统调用的方式如下:
- 设置
%eax寄存器为系统调用号; - 寄存器
%ebx、%ecx、%edx、%esi和%edi依次存放需要的参数。本次实验两个系统调用均只需一个参数。即设置%ebx为需要的参数; - 执行
int $0x80.
unlink 系统调用号为 0xa,exit系统调用号为
0x1。
对于 unlink("data") 可以拆分成如下三条 Gadgets,均能在
libc 里轻松找到:
1 | pop eax ; ret |
栈中的内容依次是:
1 | libc_base_addr + 0x2470F, # pop eax ; ret |
注意,这里的 "data"
字符串恰好在libc的内存中可以找到(包含结尾的\0),那我们就不客气了,直接拿来用。如果没有怎么办?最简便的做法是,在栈里存储字符串,并用一些
MOV 和 POP 指令把这些字符写入 .data 段。参见 Ref.1
同理,可以得到 exit 系统调用应该准备的栈内容。
写了一个 Python 脚本来产生最终的 payload 文件:
1 | import struct |
之后运行程序看看效果:

可以看到,data 文件被删掉了。
References:
Helpful Links: