使用 GCC 避免堆栈粉碎攻击

举报
Tiamo_T 发表于 2022/07/20 17:24:32 2022/07/20
【摘要】 堆栈粉碎是一个奇特的术语,用于堆栈缓冲区溢出。它指的是利用代码中导致缓冲区溢出的错误的攻击。

堆栈粉碎是一个奇特的术语,用于堆栈缓冲区溢出。它指的是利用代码中导致缓冲区溢出的错误的攻击。早些时候,程序员/开发人员有责任确保他们的代码中没有缓冲区溢出的可能性,但是随着时间的推移,像 gcc 这样的编译器已经有了标志,以确保破解者不会利用缓冲区溢出问题来破坏系统或程序。

当我尝试在具有 gcc 4.6.3 版本的 Ubuntu 12.04 上重现缓冲区溢出时,我开始了解这些标志。这是我想做的事情:

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

int main(void)
{
    int len = 0;
    char str[10] = {0};

    printf("\n Enter the name \n");

    gets(str); // Used gets() to cause buffer overflow

    printf("\n len = [%d] \n", len);

    len  = strlen(str);
    printf("\n len of string entered is : [%d]\n", len);

    return 0;
}

在上面的代码中,我使用了 gets() 来接受来自用户的字符串。然后计算该字符串的长度并打印回标准输出。这里的想法是输入一个长度超过 10 个字节的字符串。由于 gets() 不检查数组边界,所以它会尝试将输入复制到 str 缓冲区中,这样就会发生缓冲区溢出。

这是我执行程序时发生的事情:

$ ./stacksmash 

 Enter the name
TheGeekStuff

 len = [0] 

 len of string entered is : [12]
*** stack smashing detected ***: ./stacksmash terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb76e4045]
/lib/i386-linux-gnu/libc.so.6(+0x103ffa)[0xb76e3ffa]
./stacksmash[0x8048548]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75f94d3]
./stacksmash[0x8048401]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:06 528260     /home/himanshu/practice/stacksmash
08049000-0804a000 r--p 00000000 08:06 528260     /home/himanshu/practice/stacksmash
0804a000-0804b000 rw-p 00001000 08:06 528260     /home/himanshu/practice/stacksmash
0973a000-0975b000 rw-p 00000000 00:00 0          [heap]
b75af000-b75cb000 r-xp 00000000 08:06 787381     /lib/i386-linux-gnu/libgcc_s.so.1
b75cb000-b75cc000 r--p 0001b000 08:06 787381     /lib/i386-linux-gnu/libgcc_s.so.1
b75cc000-b75cd000 rw-p 0001c000 08:06 787381     /lib/i386-linux-gnu/libgcc_s.so.1
b75df000-b75e0000 rw-p 00000000 00:00 0
b75e0000-b7783000 r-xp 00000000 08:06 787152     /lib/i386-linux-gnu/libc-2.15.so
b7783000-b7784000 ---p 001a3000 08:06 787152     /lib/i386-linux-gnu/libc-2.15.so
b7784000-b7786000 r--p 001a3000 08:06 787152     /lib/i386-linux-gnu/libc-2.15.so
b7786000-b7787000 rw-p 001a5000 08:06 787152     /lib/i386-linux-gnu/libc-2.15.so
b7787000-b778a000 rw-p 00000000 00:00 0
b7799000-b779e000 rw-p 00000000 00:00 0
b779e000-b779f000 r-xp 00000000 00:00 0          [vdso]
b779f000-b77bf000 r-xp 00000000 08:06 794147     /lib/i386-linux-gnu/ld-2.15.so
b77bf000-b77c0000 r--p 0001f000 08:06 794147     /lib/i386-linux-gnu/ld-2.15.so
b77c0000-b77c1000 rw-p 00020000 08:06 794147     /lib/i386-linux-gnu/ld-2.15.so
bfaec000-bfb0d000 rw-p 00000000 00:00 0          [stack]
Aborted (core dumped)

好吧,令人惊喜的是,执行环境能够以某种方式检测到在这种情况下可能发生缓冲区溢出。在输出中,您可以看到检测到堆栈粉碎。这促使我探索如何检测缓冲区溢出。

在寻找原因时,我遇到了一个 gcc 标志“-fstack-protector”。这是此标志的描述(来自手册页):

-fstack-protector


发出额外的代码来检查缓冲区溢出,例如堆栈粉碎攻击。这是通过将保护变量添加到具有易受攻击对象的函数来完成的。这包括调用 alloca 的函数,以及缓冲区大于 8 字节的函数。进入函数时初始化守卫,然后在函数退出时检查。如果保护检查失败,则会打印一条错误消息并退出程序。

注意:在 Ubuntu 6.10 和更高版本中,如果没有找到 -fno-stack-protector、-nostdlib 和 -ffreestanding,则默认情况下会为 C、C++、ObjC、ObjC++ 启用此选项。

 

所以你看到 gcc 有这个标志,它发出额外的代码来检查缓冲区溢出。现在我想到的下一个问题是我在编译时从未包含此标志,然后如何启用此功能。然后我阅读了最后两行,上面说 Ubuntu 6.10 默认启用此功能。

然后,作为下一步,我决定在编译时使用标志“-fno-stack-protector”来停用此功能,然后尝试执行我之前做的相同用例。

这是我的做法:

$ gcc -Wall -fno-stack-protector stacksmash.c -o stacksmash
$ ./stacksmash 

 Enter the name
TheGeekStuff

 len = [26214] 

 len of string entered is : [12]

因此我们看到,一旦使用此标志编译代码,然后使用相同的输入,执行环境就无法检测到实际发生的缓冲区溢出并破坏了变量“len”的值。

此外,如果您是 gcc 新手,您应该了解我们之前讨论过的最常用的gcc 编译器选项

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。