在现代 Linux 中编译缓冲区溢出示例?

信息安全 缓冲区溢出 aslr 部门 海合会
2021-08-13 05:12:06

我正在尝试在 Debian i386 VM 上编译一个简单的缓冲区溢出示例。可执行文件构建正常,但 EIP 没有被正确覆盖,尽管提供了足够大的输入以溢出缓冲区并覆盖堆栈上的推送 EIP。以下是我以 root 身份执行的命令:

sysctl -w kernel.randomize_va_space=0
gcc test.c -z execstack -z norelro -fno-stack-protector -D_FORTIFY_SOURCE=0 -ggdb -o test

如您所见,我有:

  • 使堆栈可执行
  • 移除了堆栈金丝雀
  • 禁用 ASLR 系统范围
  • 删除了 relro 保护
  • 禁用 gcc 的 FORTIFY_SOURCE 保护

这是test.c:

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

int main(int argc, char **argv) {
  char buf[128];
  if(argc < 2) return 1;
  strcpy(buf, argv[1]);
  printf("%s\n", buf);
  return 0;
}

我已经尝试过长度为 128-256 的崩溃字符串(只是所有的 As)。在 gdb 中,推送的 EIP 永远不会被覆盖。实际上它应该只是一个 132 字节的字符串来覆盖 EIP,因为没有其他本地堆栈变量。

编译时我需要禁用其他一些保护吗?或者还有什么可以用 sysctl 禁用的?

3个回答

尽管建议将所有内容移至不同功能的公认答案是正确的,但并不能解释原因。


正如您在此问答 main()中看到的,函数通常执行堆栈对齐以确保堆栈设置正确。执行以下指令:

83 e4 f0 and esp, 0xfffffff0

这会将堆栈对齐到 8 个字节。这意味着对 执行了减法运算esp所以为了溢出你需要的返回地址128 bytes + <variable stack alignment> + <optional saved ebp> + <new_return_address>

我编译并运行了你的程序(我必须添加一个-m32)。

Starting program: /home/user/Private/misc/overflow_test  
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDEEEEFFFFaaaabbbbcccc
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDEEEEFFFFaaaabbbbcccc

Program received signal SIGSEGV, Segmentation fault.
0x63636363 in ?? ()

我用了 128 个 As,然后每个新字母 4 个。

反编译程序我们看到以下几行:

;      .//overflow_test.c:4
;-- main: 
;-- sym.main: 
0x0804842d    55             push ebp  
0x0804842e    89e5           mov ebp, esp  
0x08048430    83e4f0         and esp, 0xfffffff0 
0x08048433    81ec90000000   sub esp, 0x90 

在这里,我们看到从堆栈中减去了 0x90 (144)。这意味着为局部变量分配了超过 128 字节的空间。 这个 SO answer给出了可能发生这种情况的一些原因。因此,如果您考虑 128 个字节,为局部变量添加的 16 个额外字节,并假设 8 个字节的堆栈对齐:然后您将 EBP 覆盖为0x62626262,返回地址为0x63636363.


普通函数通常不执行对齐堆栈的这一步。这就是为什么当你把它移到一个单独的函数中时,一切都按预期工作。在实际开发中,您利用进入 a 的参数的main()可能性极小。在不同的函数范围内运行更为现实。

您的示例在此处确实存在段错误(或者如果堆栈保护器处于活动状态,则会导致程序终止)。

也许您应该尝试将缓冲区溢出移到另一个函数中。也许您的 gcc 版本正在return 0;从 main 转换为exit(0);.

以防万一有人收到错误

/usr/include/stdio.h:27:10: fatal error: bits/libc-header-start.h: No such file or directory
   27 | #include <bits/libc-header-start.h>

在尝试使用 -m32 标志时,

尝试安装gcc-multilib,并且(如果也在 C++ 中)g++-multilib

sudo apt update

sudo apt install gcc-multilib

sudo apt install g++-multilib