2

在我正在阅读的书中,软件驱魔,有这个缓冲区溢出的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 4

void victim(char *str)
{
        char buffer[BUFFER_SIZE];
        strcpy(buffer,str);
        return;
}

void redirected()
{
        printf("\tYou've been redirected!\n");
        exit(0);
        return;
}

void main()
{
        char buffer[]=
        {
                '1','2','3','4',
                '5','6','7','8',
                '\x0','\x0','\x0','\x0','\x0'
        };
        void *fptr;
        unsigned long *lptr;

        printf("buffer = %s\n", buffer);
        fptr = redirected;
        lptr = (unsigned long*)(&buffer[8]);
        *lptr = (unsigned long)fptr;

        printf("main()\n");
        victim(buffer);
        printf("main()\n");
        return;
}

我可以通过指定使用 Visual Studio 2010 在 Windows 中使用它

  • 基本运行时检查 -> 未初始化的变量
  • 缓冲区安全检查 -> 否

使用这些编译选项,我在运行时会得到这种行为:

buffer = 12345678
main()
        You've been redirected!

我的问题是关于无法在 Linux 上运行的代码。有什么明确的原因吗?

关于我尝试过的一些信息:

我尝试使用 32 位 Ubuntu 12.04(从此处下载)运行它,使用以下选项:

[09/01/2014 11:46] root@ubuntu:/home/seed# sysctl -w kernel.randomize_va_space=0
kernel.randomize_va_space = 0

得到:

[09/01/2014 12:03] seed@ubuntu:~$ gcc -fno-stack-protector -z execstack -o overflow overflow.c 
[09/01/2014 12:03] seed@ubuntu:~$ ./overflow
buffer = 12345678
main()
main()
Segmentation fault (core dumped)

在 64 位 CentOS 6.0 中,具有以下选项:

[root]# sysctl -w kernel.randomize_va_space=0
kernel.randomize_va_space = 0
[root]# sysctl -w kernel.exec-shield=0
kernel.exec-shield = 0

得到:

[root]# gcc -fno-stack-protector -z execstack -o overflow overflow.c 
[root]# ./overflow
buffer = 12345678
main()
main()
[root]#

Linux 环境中是否有一些根本不同的东西,这会导致示例无法正常工作,或者我在这里遗漏了一些简单的东西?

注意:我已经完成了相关问题,例如this onethis one,但找不到任何对此有帮助的东西。我不认为这是以前问题的重复,即使它们有很多。

4

2 回答 2

4

您的示例溢出了堆栈,这是一个小型且可预测的内存布局,试图修改函数的返回地址,void victim()然后该地址将指向void redirected()而不是返回到main().

它适用于视觉。但是 GCC 是一个不同的编译器,可以使用一些不同的堆栈分配规则,导致漏洞利用失败。C 不强制执行严格的“堆栈内存布局”,因此编译器可以做出不同的选择。

查看此假设的一个好方法是使用 MinGW(又名 GCC for Windows)测试您的代码,证明行为差异与操作系统没有严格的关系。

于 2014-09-02T16:21:02.107 回答
0
#define BUFFER_SIZE 4

void victim(char *str)
{
        char buffer[BUFFER_SIZE];
        strcpy(buffer,str);
        return;
}

如果启用优化,这里还有另一个潜在问题。buffer是 12 个字节,它被称为victim(buffer). 然后,在 中victim,您尝试将 12 字节复制到 4 字节缓冲区中strcpy

FORTIFY_SOURCES 应该导致程序在调用strcpy. 如果编译器可以推断出目标缓冲区大小(在这种情况下应该如此),那么编译器将替换strcpy为包含目标缓冲区大小的“更安全”版本。如果要复制的字节超过目标缓冲区大小,则“更安全”strcpy将调用abort().

要关闭 FORTIFY_SOURCES,然后使用-U_FORTIFY_SOURCE或进行编译-D_FORTIFY_SOURCE=0

于 2014-09-13T00:18:46.923 回答