如何关闭gcc编译器优化以启用缓冲区溢出

84

我正在处理一道作业问题,需要禁用编译器优化保护才能使其正常工作。我正在使用 Ubuntu Linux 上的 gcc 4.4.1,但无法确定正确的参数。我意识到这取决于架构 - 我的机器运行在32位英特尔处理器上。

谢谢。

6个回答

127

这是一个很好的问题。为了解决这个问题,你还需要禁用ASLR,否则g()的地址将无法预测。

禁用ASLR:

sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space'

禁用 canaries:

gcc overflow.c -o overflow -fno-stack-protector

在取消canaries和ASLR之后,这将是一种直截了当的攻击方式,就像Smashing the Stack for Fun and Profit中描述的那样。
以下是Ubuntu使用的安全功能列表: https://wiki.ubuntu.com/Security/Features 您不必担心NX位,因为g()的地址始终在内存的可执行区域内,因为它位于TEXT内存段内。 NX位仅在您尝试在堆栈或堆上执行shellcode时才会起作用,但这不是此任务所需的,因为它使用Return-Oriented Programming(ROP或ROP Chain)来打败NX位提供的保护,这通常用于。
现在去破坏那个EIP

5
谢谢,我会这样做的 :)哦 - 我如何重新启用保护来清理我的机器?.. 我猜是sudo echo 1 > /proc/sys/kernel/randomize_va_space - sa125
18
值得一提的是,在我的系统中,randomize_va_space 的默认值为 2 而不是 1,因此如果您打算重新启用它,最好事先检查一下。 - Rushyo
4
实际上,由于g()函数是主二进制文件的一部分,所以其地址很可能不会被ASLR随机化。只有在使用-PIE编译二进制文件时,它才会被随机化。 - Robert Larsen
1
现代Linux发行版默认配置GCC以构建PIE可执行文件。您可以使用gcc overflow.c -fno-stack-protector -fno-pie -no-pie来创建传统的ELF可执行文件,而不是共享对象。这样您就不必为非栈段禁用ASLR,无论是系统范围还是针对此可执行文件,这是GDB做的事情。完全不需要系统范围内禁用。@RobertLarsen(和未来的读者)。 - Peter Cordes
@PeterCordes 是的,在2021年现代系统中是这样的。当我六年前写下我的答案时,PIE不是默认设置。 ROP不需要完整的函数。可以将小段的机器代码链接在一起,以实现更多或更少的任何功能。我知道你可能已经知道了这一点。 - Robert Larsen
显示剩余3条评论

37

嗯,到目前为止所有的答案都是错误的,Rook的答案是正确的。

输入:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

接下来是:

gcc -fno-stack-protector -z execstack -o bug bug.c

禁用ASLR、SSP/Propolice和Ubuntu的NoneXec(它被放置在9.10中,并且相当容易通过mprotect(2)技术来解决,以将页面映射为可执行和jmp),应该会有所帮助,但是这些“安全功能”绝不是万无一失的。如果没有`-z execstack`标志,页面具有非可执行堆栈标记。


5
你没有读那个人的链接。如果你读了,你就会知道他试图执行编译进二进制文件中的函数g()。这是一个函数的地址。当你试图在堆栈上执行shellcode时,NX位就会发挥作用,而他的攻击要简单得多。 - rook
1
我同意其他人都是完全错误的,很明显我们是唯一利用了缓冲区溢出的两个人。然而,我仍然认为我的答案更正确。 - rook
哦,刚看到这个链接——我以为它只是另一个普通的链接,你是对的。我道歉。 - user1831086
1
我知道这是一个旧帖子,但你不能在 > < 中使用sudo,因为它不允许。命令应该是: echo 0 | sudo tee /proc/sys/kernel/randomize_va_space - Boogy

29

在新的发行版中(截至2016年),PIE似乎已经默认启用,因此在编译时需要显式地禁用它。

以下是一些常见本地缓冲区溢出练习中有用的命令摘要:

禁用canary:

gcc vuln.c -o vuln_disable_canary -fno-stack-protector

禁用 DEP:

gcc vuln.c -o vuln_disable_dep -z execstack

禁用PIE:

gcc vuln.c -o vuln_disable_pie -no-pie

禁用上述列出的所有保护机制(警告:仅供本地测试使用):

gcc vuln.c -o vuln_disable_all -fno-stack-protector -z execstack -no-pie

对于32位机器,您还需要添加-m32参数。


在64位机器上构建32位代码时需要使用-m32。此外,您可以使用-fno-pie让编译器生成不涉及PIE的汇编代码,也可以使用-no-pie来防止将该机器码链接到PIE中。对于32位模式,-fno-pie将显着简化汇编代码,删除像call __x86.get_pc_thunk.bx这样的垃圾。对于64位模式,主要允许使用mov-immediate而不是RIP相对LEA用于静态地址,并且更有效地索引静态数组。 - Peter Cordes

8

尝试使用-fno-stack-protector标志。


6
您不需要禁用ASLR来进行缓冲区溢出!尽管启用了ASLR(kernel_randomize_va_space = 2),但除非编译的可执行文件是PIE,否则它将不会生效。因此,除非您使用-fPIC -pie标志编译文件,否则ASLR将不会生效。
我认为只需使用-fno-stack-protector禁用堆栈保护就足够了。如果您想检查ASLR是否起作用(必须设置位置无关代码),请使用:
hardening-check executable_name

2
我不会引用整个页面,但是优化手册的全部内容可以在此处找到:http://gcc.gnu.org/onlinedocs/gcc-4.4.3/gcc/Optimize-Options.html#Optimize-Options 从听起来的意思来看,您至少需要 -O0 (默认值) 以及以下选项:

-fmudflap -fmudflapth -fmudflapir

对于支持它的前端(C 和 C++),使用范围/有效性测试仪器化所有风险指针/数组解引用操作、一些标准库字符串/堆函数和一些其他相关结构。这样仪器化的模块应该免疫缓冲区溢出、无效的堆使用以及一些其他类的 C/C++ 编程错误。该仪器依赖于一个单独的运行时库(libmudflap),如果在链接时给出了 -fmudflap,则会将其链接到程序中。仪器化程序的运行时行为由 MUDFLAP_OPTIONS 环境变量控制。有关其选项,请参见 env MUDFLAP_OPTIONS=-help a.out。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接