章节大纲

      • 许多编译器(如 gcc)实现了名为 StackGuard 的安全机制来防止缓冲区溢出。在该保护存在的情况下,缓冲区溢出攻击将不会起作用。 在前面的任务中我们在编译程序时关闭了 StackGuard 保护机制。在本任务中我们将开启它并观察会发生什么。

        首先重复任务 3 的攻击不开启 StackGuard,确认攻击仍然成功。记住要先关闭地址随机化,因为在前一个任务中你已经将其打开了。 然后通过重新编译易受攻击的 stack.c 程序而不使用 -fno-stack-protector 标志来开启 StackGuard 保护。 在 gcc 版本 4.3.3 及以上中,StackGuard 默认启用。发起攻击并报告和解释你的观察结果。

      • 操作系统过去是允许可执行栈的,但现在情况已经改变:在 Ubuntu 操作系统中,程序(和共享库)的二进制映像必须声明它们是否需要可执行栈,即它们需要在程序头中设置一个标记字段。内核或动态链接器使用此标记来决定是否让运行的程序的栈可执行或不可执行。此标记由 gcc 自动完成,默认情况下使栈不可执行。我们可以在编译中使用 "-z noexecstack" 标志专门使其不可执行。 在我们之前的任务中,我们使用 "-z execstack" 使栈可执行。

        在此任务中,我们将使栈不可执行。我们将在 shellcode 文件夹中进行这个实验。 call_shellcode 程序会在堆栈上放置 shellcode 的副本,然后从栈上执行代码。 请重新编译 call_shellcode.c 生成 a32.out 和 a64.out,但不使用 "-z execstack" 选项。运行它们,并描述和解释你的观察。

        需要注意的是,不可执行栈仅使得在栈上运行 shellcode 不可能,但这并不能完全防止缓冲区溢出攻击,因为还有其他方式来运行恶意代码。例如 return-to-libc 攻击。我们为此设计了一个单独的实验。具体请参见 Return-to-Libc 攻击实验。