章节大纲

  • 要利用目标程序中的缓冲区溢出漏洞,最重要的是要知道缓冲区起始位置与返回地址存储位置之间的距离。我们将使用调试方法来找出该距离。 由于我们有目标程序的源代码,我们可以用调试标志将其编译出来,这样会更方便调试。

    我们需要向 gcc 命令添加 -g 标志,因此二进制文件中包含了调试信息。如果你运行 make,已经创建了调试版本。我们将使用 gdb 来调试 stack-L1-dbg。在运行程序之前需要先创建一个名为 badfile 的文件。

    $ touch badfile                                       ← 创建一个空的 badfile
    $ gdb stack-L1-dbg
    gdb-peda$ b bof                                       ← 在函数 bof() 设置断点
    Breakpoint 1 at 0x124d: file stack.c, line 18.
    gdb-peda$ run                                         ← 开始执行程序
    ...
    Breakpoint 1, bof (str=0xffffcf57 ...) at stack.c:18
    18  {
    gdb-peda$ next                                        ← 执行下一条语句
    ...
    22      strcpy(buffer, str);
    gdb-peda$ p $ebp                                      ← 查看 ebp 的地址
    $1 = (void *) 0xffffdfd8   
    gdb-peda$ p &buffer
    $2 = (char (*)[100]) 0xffffdfac                       ← 查看缓冲区的地址
    gdb-peda$ quit

    1. 当 gdb 停在 bof() 函数内部时,它会在设置 ebp 寄存器以指向当前栈帧之前停止,因此如果我们在此处打印出 ebp 的值,将会获得调用者的 ebp 值。我们需要使用 next 执行几条指令,并在修改了 ebp 寄存器以指向 bof() 函数的栈帧之后停止。 gdb 的行为与 SEED 书籍基于 Ubuntu 16.04,因此书中没有包含 next 步骤。
    2. 请注意,从 gdb 获取的框架指针值在实际执行时是不同的,因为 gdb 在运行调试程序之前将一些环境数据推入栈中。 当直接运行程序而不是使用 gdb 时,栈不包含这些数据,所以实际的帧指针值更大。当你构建你的 payload 时请记住这一点。