不应该发生的缓冲区溢出 (?)
buffer overflow that shouldnt happen (?)
我有以下程序
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 int check_authentication(char *password){
6 char password_buffer[16];
7 int auth_flag =0;
8
9
10 strcpy(password_buffer, password);
11
12 if(strcmp(password_buffer, "brillig" ) == 0 )
13 auth_flag = 1;
14 if(strcmp(password_buffer, "outgrabe") == 0)
15 auth_flag = 1;
16
17 return auth_flag;
18 }
19
20 int main(int argc, char *argv[]){
21 if (argc<2){
22 printf("Usage: %s <password>n", argv[0]);
23 exit(0);
24 }
25
26 if(check_authentication(argv[1])){
27 printf("n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=n");
28 printf(" Access Granted.n");
29 printf("n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=n");
30 }
31 else {
32 printf("n Access Denied. n");
33 }
34 }
我正在运行它,通过 gdb 提供 30 字节的 As...并且我正在设置以下断点
(gdb) break 9
Breakpoint 1 at 0x80484c1: file auth_overflow2.c, line 9.
(gdb) break 16
Breakpoint 2 at 0x804850f: file auth_overflow2.c, line 16.
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
目前为止,一切都好。一切都按预期进行,甚至直到下一个断点
Breakpoint 1, check_authentication (password=0xbffff6d2 'A' <repeats 30 times>)
at auth_overflow2.c:10
10 strcpy(password_buffer, password);
(gdb) x/s password_buffer
0xbffff484: "364237374267240205 04b250364377277245", <incomplete sequence 352267>
(gdb) x/x &auth_flag
0xbffff494: 0x00
现在我们看到以下信息:
变量auth_flag位于地址0xbffff494中,变量缓冲区位于地址0xbffff484中。由于 var auth_flag 的地址大于缓冲区的地址,并且堆栈向较低的地址增长,这意味着缓冲区变量中的附加(缓冲区溢出)字节不会覆盖auth_flag。右?
但是gdb有不同的看法...
(gdb) cont
Continuing.
Breakpoint 2, check_authentication (
password=0xbf004141 <Address 0xbf004141 out of bounds>)
at auth_overflow2.c:17
17 return auth_flag;
(gdb) x/s password_buffer
0xbffff484: 'A' <repeats 30 times>
(gdb) x/x &auth_flag
0xbffff494: 0x41
和。。。
(gdb) x/16xw &auth_flag
0xbffff494: 0x41414141 0x41414141 0x41414141 0xbf004141
0xbffff4a4: 0x00000000 0xbffff528 0xb7e8bbd6 0x00000002
0xbffff4b4: 0xbffff554 0xbffff560 0xb7fe1858 0xbffff510
0xbffff4c4: 0xffffffff 0xb7ffeff4 0x080482bc 0x00000001
我们看到auth_flag被这些0x41 (=A) 覆盖,尽管这个变量在堆栈中的位置较低。为什么会这样?
堆栈增长方向与超出缓冲区时额外字节的去向无关。来自strcpy
的溢出总是会进入更高的地址(除非溢出到你绕到地址 0,这不太可能)
对象存储在从较低地址到较高地址的内存中。由于您无法保证参数密码引用的字符串的长度小于 16,因此您的代码无效。事实上,本地缓冲区password_buffer中没有任何需要。该函数可以按以下方式编写
_Bool check_authentication( const char *password )
{
return ( strcmp( password, "brillig" ) == 0 || strcmp( password, "outgrabe" ) == 0 );
}
代替返回类型_Bool,您可以在函数实现中使用 int 类型。在任何情况下,都将返回 1 或 0。
可以自由地对变量堆栈进行重新排序,因此在这种情况下,它总是在 int 变量之前是 char 数组。这使得程序容易受到基于堆栈的缓冲区溢出的影响。
为了更改以下内容:
(gdb) x/s password_buffer
0xbffff484: 'A' <repeats 30 times>
(gdb) x/x &auth_flag
0xbffff494: 0x41
预期答案如下:
(gdb) x/s password_buffer
0xbffff494: 'A' <repeats 30 times>
(gdb) x/x &auth_flag
0xbffff484: 0x00
我们只需在编译过程中添加一个-fstack-protector-all
参数,结果将符合预期。反之亦然,也许您可以使用 -O0
或 -fno-stack-protector
.
答案来自: https://stackoverflow.com/a/21215205/3205268
如果你读取的字节超过15个字节,你会得到它。 strcpy 将查找字符串的末尾。 您可以使用像 strncpy 这样的东西来只复制有限数量的字符。
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 为什么我在leetcode上收到AddressSanitizer:地址0x602000000058上的堆缓冲区溢出错误
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 使用 strcat 获取缓冲区溢出错误
- LeetCode 1:两和 - 地址清理器:堆缓冲区溢出地址
- 使用向量的缓冲区溢出
- 重新增长阵列时出错:写入时缓冲区溢出
- Leetcode 1366:堆缓冲区溢出
- 缓冲区溢出 - 数组索引越界(严重)
- C++二维矢量导致缓冲区溢出
- 缓冲区溢出怎么会成为黑客的攻击
- 如何防止缓冲区溢出
- 应该如何读取堆缓冲区溢出错误消息?
- 自动截断和 null 终止缓冲区溢出中的字符串缓冲区
- 如果用户输入两个或多个由空格分隔的字符串C++如何防止缓冲区溢出?
- MSVC C6029 警告:缓冲区可能溢出,使用未经检查的值.检查缓冲区大小时,警告不会消失
- 我正在尝试使用回溯来解决 N queen 问题,但在编译时它会给出运行时错误(动态堆栈缓冲区溢出)
- 我不能溢出缓冲区
- 包含溢出缓冲区的堆栈分配变量,也称为缓冲区
- STL矢量溢出缓冲区