Section outline

      • 许多编译器,如 gcc,实现了一种称为 StackGuard 的安全机制,以防止缓冲区溢出。在有此防护机制的情况下,缓冲区溢出攻击将不会生效。 实验里的被攻击程序是在未启用 StackGuard 保护的情况下编译的。 在这个任务中,我们将打开它并观察会发生什么。

        请前往 server-code 文件夹,在 gcc 参数中去掉 -fno-stack-protector 选项,并重新编译 stack.c。我们仅使用 stack-L1,但与其在容器中运行该程序,我们将直接从命令行运行它。请创建一个可以导致缓冲区溢出的文件,然后向 stack-L1 传入该文件的内容。请描述并解释你的观察结果。

        $ ./stack-L1 < badfile 
      • 操作系统过去是允许可执行栈的,但现在情况已经改变:在 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 攻击实验。