发布于

Gadgets

作者

Gadgets 是一小段后跟 ret 指令的代码。例如:pop rdi; ret。我们可以操纵这些 gadgets 的 ret,将它们串成一个链来完成我们想要做的事情。

0x01 例子

假设在执行 pop rdi; ret gadget 期间栈看起来像这样:

origin

很明显:0x10 被弹出到 rdi 中,因为它在弹出到 rdi 前位于栈顶。一旦出栈,rsp 就会移动:

origin

由于 ret 相当于 pop rip ,因此 0x5655576724 被移至 rip 中。请注意栈是如何布局的。

0x02 使用 Gadgets

当我们覆盖返回地址时,我们覆盖了 rsp 指向的值。一旦该值出栈,它就会指向栈中的下一个值。但请等待,我们可以覆盖栈中的下一个值。

假设我们想要利用二进制文件跳转到 pop rdi; ret gadget,将 0x100 弹出到 rdi 中,然后跳转到 flag()。让我们一步步执行:

origin

在原来的 ret 上,我们覆盖了返回地址,我们让 gadget 地址出栈。现在 rip 移动指向到 gadget,rsp 移动到下一个内存地址。

origin

rsp 移动指向到 0x100rip 变为 pop rdi。现在,当我们出栈时,0x100 被移入 rdi

origin

RSP 移动到栈上的下一个项目,即 flag() 的地址。执行 ret 并调用 flag()

0x03 总结

本质上,如果 gadget 从栈中弹出值,只需将这些值放在后面(包括 ret 中的 pop rip)。如果我们想将 0x10 弹出到 rdi 然后跳转到 0x16,我们的 payload 将如下所示:

origin

Important

如果你有多个 pop 指令,则可以添加更多值。

origin

Note

之所以使用 rdi 作为示例,是因为如果你还记得的话,那是 64-bit 程序中的第一个参数的寄存器。这意味着使用该 gadget 控制该寄存器非常重要。

0x04 查找 Gadgets

我们可以使用 ROPGadget 工具来查找可能的 gadgets。

$ ROPgadget --binary vuln-64

Gadgets information
============================================================
0x0000000000401069 : add ah, dh ; nop dword ptr [rax + rax] ; ret
0x000000000040109b : add bh, bh ; loopne 0x401105 ; nop ; ret
0x0000000000401037 : add byte ptr [rax], al ; add byte ptr [rax], al ; jmp 0x401020
[...]

将其与 grep 结合起来查找特定的寄存器:

$ ROPgadget --binary vuln-64 | grep rdi

0x0000000000401096 : or dword ptr [rdi + 0x404030], edi ; jmp rax
0x00000000004011db : pop rdi ; ret