缓冲区溢出 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
时发生崩溃。
我已经在网上搜索了几个小时,但仍然无法弄清楚以下代码的漏洞是什么。我必须产生缓冲区溢出,但我做不到。如果我的有效负载大于 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
时发生崩溃。