我试图了解非常基本的基于堆栈的缓冲区溢出
我正在x86_64 Macbook Pro上运行Debian wheezy。

我有以下不安全程序:

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

CanNeverExecute()
{
        printf("I can never execute\n");
        exit(0);
}

GetInput()
{
        char buffer[512];

        gets(buffer);
        puts(buffer);
}

main()
{
        GetInput();

        return 0;
}


我用-z execstack-fno-stack-protector进行了编译以进行测试。

我已经能够通过gdb启动程序,获取CanNeverExecute函数的地址,而该函数从未调用,并溢出缓冲区以用该地址替换返回地址。我打印了“我永远也不会执行”,到目前为止,一切都很好。

现在,我正在尝试通过在堆栈中引入shellcode来利用此缓冲区溢出。我目前正在直接尝试进入gdb:中断GetInput函数,通过gdb设置缓冲区值,并使用jump命令跳转到缓冲区地址。获取功能后,我刚好有一个断点,我用512个a字符作为输入运行了程序。在gdb中,我这样做了:

(gdb) p buffer
 = 'a' <repeats 512 times>


读取输入没有任何问题,我的缓冲区是512 a
然后尝试修改其值。如果执行此操作:

(gdb) set var buffer=""


并尝试打印缓冲区,其长度现在为511!为什么会出现?

(gdb) p buffer
 = '
Too many array elements
0' <repeats 511 times>et:


当我尝试将其设置回512 a时,我得到:

q4312078q

我可以将其设置为511 a,实际上是LAS字节不起作用...怎么来,有一个简单的解释吗?

#1 楼

GDB保护您溢出char数组。

(gdb) p &buffer
 = (char (*)[512]) 0x7fffffffdfe0


要绕过此安全性,您可以直接写内存:作为更大的一个,然后设置您的东西:

(gdb) set 0x7fffffffe1e0=0x41414141


评论


谢谢,但是我不是想用513 A而是只用512写……还是最后一个字符必须是\ x00?

–NoéMalzieu
2013年6月9日在16:22

哦,抱歉,这是一个错字。是的,当然,最后一个字符必须是一个空字节,而且GDB尝试为您追加它。给定数组定义,这就是为什么编写511“ a”而不是512的原因。

– dna
2013年6月9日在16:28

好,多谢!最后一个问题:这是否意味着在C中,如果我创建char buffer [512] ;,那么我也只能填充511个char?

–NoéMalzieu
2013年6月9日在16:34

您可以随意用512个字符填充512个字符。但是在GDB中,当使用命令set buffer =“ A”时,您将用字符串填充它,从而使用最终的空字节终止符。

– dna
2013年6月9日在16:47

完全有道理

–NoéMalzieu
2013年6月9日17:05