缓冲区溢出解释

ped*_*tos 3 c buffer overflow

我制作了这个简单的密码验证程序,我试图溢出缓冲区数组以将 auth 变量更改为 1,我设法做到了这一点,除了我只能将 auth 变量更改为字符 1 而不是十进制 1,如何我可以做吗?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]){

char buffer[16];
int auth=0;
strcpy(buffer, argv[1]);

if(strcmp(buffer,"password")==0)
    auth=1;
else
    auth=0;

if(auth)
    printf("Granted");



 return 0;

}
Run Code Online (Sandbox Code Playgroud)

thu*_*zas 5

以下信息来自我的 Ubuntu-14.04 系统上的运行,使用 gcc 版本 4.8.4 作为编译器,使用 gdb 版本 7.7.1 作为调试器

首先,缓冲区溢出是由于 strcpy 函数而发生的,如果溢出buf导致它覆盖 的内存位置auth,但下面的 if-else 块将覆盖您的更改。

其次,您可以通过查看调试器中的堆栈来了解发生了什么。auth我通过初始化对您的代码进行了轻微修改0xbbbbbbbb(这样我就可以在这里找到 auth 位于堆栈上)。

在 main 上设置断点并单步执行函数,我们可以检查各个寄存器的值:

   (gdb) info reg
   rax            0x0   0
   rbx            0x0   0
   rcx            0x0   0
   rdx            0x7fffffffdf30    140737488346928
   rsi            0x7fffffffdf18    140737488346904
   rdi            0x2   2
   rbp            0x7fffffffde30    0x7fffffffde30
   rsp            0x7fffffffddf0    0x7fffffffddf0
         [... some lines removed ...]
   rip            0x400652  0x400652 <main+37>
   eflags         0x246 [ PF ZF IF ]
   cs             0x33  51
   ss             0x2b  43
   ds             0x0   0
   es             0x0   0
   fs             0x0   0
   gs             0x0   0
Run Code Online (Sandbox Code Playgroud)

从这里我们可以看到堆栈从 延伸0x7fffffffddf00x7fffffffde30。现在在调用 strcpy 之前停止,我们可以看一下堆栈:

(gdb) x/76xb $rsp
0x7fffffffddf0: 0x18    0xdf    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffddf8: 0x1d    0x07    0x40    0x00    0x02    0x00    0x00    0x00
0x7fffffffde00: 0x30    0xde    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffde08: 0x00    0x00    0x00    0x00    0xbb    0xbb    0xbb    0xbb
0x7fffffffde10: 0xd0    0x06    0x40    0x00    0x00    0x00    0x00    0x00
0x7fffffffde18: 0x40    0x05    0x40    0x00    0x00    0x00    0x00    0x00
0x7fffffffde20: 0x10    0xdf    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffde28: 0x00    0x2b    0x25    0x07    0xdd    0x7a    0xc0    0x6d
0x7fffffffde30: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffde38: 0x45    0x6f    0xa3    0xf7
Run Code Online (Sandbox Code Playgroud)

看这个,我们可以看到它auth位于内存地址0x7fffffffde0c

我设置为命令行参数passwordAAAAAAAA111,现在我们可以单步执行 strcpy 调用并再次查看内存:

(gdb) x/76xb $rsp
0x7fffffffddf0: 0x18    0xdf    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffddf8: 0x1d    0x07    0x40    0x00    0x02    0x00    0x00    0x00
0x7fffffffde00: 0x30    0xde    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffde08: 0x00    0x00    0x00    0x00    0xbb    0xbb    0xbb    0xbb
0x7fffffffde10: 0x70    0x61    0x73    0x73    0x77    0x6f    0x72    0x64
0x7fffffffde18: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0x7fffffffde20: 0x31    0x31    0x31    0x31    0x00    0x7f    0x00    0x00
0x7fffffffde28: 0x00    0x2b    0x25    0x07    0xdd    0x7a    0xc0    0x6d
0x7fffffffde30: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffde38: 0x45    0x6f    0xa3    0xf7
Run Code Online (Sandbox Code Playgroud)

(gdb)

由此,我们可以看到 的值auth还没有被触及(注意从 0x7fffffffde0c 开始的四个 0xbb 仍然在内存中)。我们现在还可以看到密码存储在内存中的位置,它从 开始0x7fffffffde10。我使用的四个“A”是四个 0x41 所在的位置,我使用的四个“1”是四个 0x31 所在的位置

因此,在我的系统上,我看不到可以溢出到auth变量中的方法。

最后,您最初提出的问题,请记住命令行参数被视为字符数组,因此AAAA1在命令行上传递某些行将导致数组 [0x41 0x41 0x41 0x41 0x31] 被传递到您的程序。您希望程序接收的实际上是 [0x41 0x41 0x41 0x41 0x01 0x00 0x00 0x00] (假设 32 位、小端架构)。您将面临两个问题,1. 0x01 是不可打印的字符 2. 0x00 作为空终止符将在第一个空处停止字符串输入。

对于问题 2,您无能为力,只需简单输入即可;然而,正如其他人所建议的,围绕问题 1 的解决方案是创建一个驱动程序,以您想要的方式构建输入缓冲区,然后将其传递给程序。