缓冲区溢出 C

Buffer Overflow C

我已经在网上搜索了几个小时,但仍然无法弄清楚以下代码的漏洞是什么。我必须产生缓冲区溢出,但我做不到。如果我的有效负载大于 28,我会在第 5 行执行函数 fread 之前进入 if 语句并 return false。

有人能告诉我如何绕过这个检查来触发溢出吗?

package looks like this
+------------+------------+------------+
|tag = 1 byte|len = 1 byte|payload[len]|
+------------+------------+------------+
0. bool processNextPackage(void){
1.   char buf[32];
2.   if(!fread(buf, 2, 1, stdin){
3.     return false;
4.   }
5.   if(buf[1] > sizeof(buf)-3 || !fread(buf + 2, buf[1], 1, stdin)){
6.     return false;
7.   }
8.   buf[sizeof(buf) - 1] = '[=11=]'
9.   return false;
10.}

我们假设 char 在这里是 signed char(这是最常见的,但并非所有编译器都这样做)

唯一可能的漏洞是尝试传递比允许的最大长度更大的长度。在这里,我们有一个字节可以做到这一点。

这个条件是可以被攻击的条件:

if(buf[1] > sizeof(buf)-3 || !fread(buf + 2, buf[1], 1, stdin))

如果 buf[1] 太大,短路运算符会阻止进入 fread(并从文件中读取太多字节)。

但如果该值在 0x80 .. 0xff 范围内,则 buf[1] 为负数 因为(可能)有符号 char。那是出乎意料的。

但它仍然没有通过测试,因为比较负数和无符号数 sizeof(buf)-3 总是使负值最大。

旁白:buf[sizeof(buf) - 1] = '[=21=]':看起来我们为了 printf 显示目的而终止字符串。如果缓冲区太大,则不会这样做(因为我们之前 return),并且在打印未终止的字符串时代码可能会崩溃。因此在读取之前必须将缓冲区设置为全零。

但除此之外,代码没有任何漏洞。

但是,如果是这样写的:

int sz = sizeof(buf)-3;
if(buf[1] > sz || !fread(buf + 2, buf[1], 1, stdin))

将存在一个漏洞,因为将负值与有符号进行比较会传递给 fread,并且当调用 fread 时,负值会作为 size 传递,但是 fread 期望无符号:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

所以该值有可能被转换为正(并且太大)值:将 0xFF 放入 buf[1],它变成 -1 作为有符号字符,但传递给 fread 它变成一个正值,大于缓冲区。

因此,由于该值非常大,它会读取文件的每个字节:您可以在其中注入恶意代码。

所以要确保没有人以这种方式重写代码:

  • buf 变量使用 unsigned char 以避免奇怪的 integer/unsigned 整数比较效果。
  • 将缓冲区初始化为全零以避免在非 nul 终止缓冲区上使用 printf 时发生崩溃。