缓冲区溢出说明

时间:2016-09-14 12:55:07

标签: 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;

}

2 个答案:

答案 0 :(得分:4)

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

首先,由于strcpy函数发生缓冲区溢出,如果溢出buf以便它覆盖auth的内存位置,但是以下if-else块将覆盖你的变化。

其次,您可以通过查看调试器中的堆栈来查看发生的情况。我通过初始化auth0xbbbbbbbb对您的代码做了一些修改(我在这里可以找到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

从中我们可以看到堆栈从0x7fffffffddf0延伸到0x7fffffffde30。现在在调用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

考虑到这一点,我们可以看到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

(gdb)

由此,我们可以看到auth的值没有被触及(注意从存储器开始于0x7fffffffde0c的四个0xbb仍在内存中)。此外,我们现在可以看到密码存储在内存中的位置,它从0x7fffffffde10开始。我使用的四个A是四个0x41的位置,而我使用的四个&#39;是四个0x31的位置

所以,在我的系统上,我没有看到你能够溢出到auth变量的方法。

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

只需输入一个简单的输入就可以解决问题2;然而,正如其他人提出的解决问题1的解决方案是创建一个驱动程序,以您想要的方式构建输入缓冲区,然后将其传递给程序。

答案 1 :(得分:1)

在Windows(相应的Linux)上,创建一个bat(resp shell)文件,如下所示:

a 0123456789ABCDEFG

(a是您的可执行文件的名称)

enter image description here

然后,使用十六进制编辑器对其进行编辑,并将最后G更改为01十六进制值,保存。

如果(我说是的话),你可以确保你的整数值的地址在char缓冲区之后(我不能使用我的gcc,因为编译器使用基于实现的顺序找到它的变量),运行这个脚本,你会看到在第一个参数结束时传递了\ 001 char。

注意:由于参数是以null结尾的,因此根本无法传递0(null)字符,因此如果要注入一些数据或代码,则必须不使用零字符。