栈迁移详解
字数 1171 2025-08-25 22:58:40

栈迁移技术详解

1. 栈迁移基本概念

栈迁移(Stack Pivoting)是一种通过修改栈指针(ESP/RSP)或基指针(EBP/RBP)来将栈转移到其他内存区域的技术,通常用于解决以下情况:

  • 栈溢出空间不足(如只能溢出少量字节)
  • 原始栈空间不可执行
  • 需要更大的空间构造ROP链

关键指令解释

  • leave指令相当于:
    mov esp, ebp
    pop ebp
    
  • ret指令相当于:
    pop eip
    

2. 栈迁移基本原理

迁移过程

  1. 通过溢出修改EBP为伪造的栈地址(如bss段)
  2. 控制EIP执行leave; ret指令序列
  3. 第一次leave
    • mov esp, ebp:将ESP指向伪造的栈地址
    • pop ebp:将伪造栈上的值弹出到EBP
  4. 第二次leave
    • 将ESP完全迁移到伪造的栈区域
    • 此时可以执行伪造栈上的ROP链

为什么要两次leave

  • 第一次leave将ESP指向伪造栈,但仍在原始栈上执行
  • 第二次leave将ESP完全迁移到伪造栈区域
  • 这样可以在有限溢出空间内完成完整的栈迁移

3. 栈迁移实战案例

案例1:vnctf2023 traveler

利用步骤:

  1. 第一次栈迁移:

    payload = cyclic(0x20) + p64(bss4) + p64(read)
    
    • 修改RBP为bss段地址(bss4)
    • 返回地址设置为read函数(0x401216)
  2. 第二次栈迁移:

    payload = cyclic(0x20) + p64(bss4+0x20) + p64(read)
    
    • 将RBP进一步迁移到bss+0x20
  3. 构造ROP链泄露libc:

    payload = p64(bss4+0x30) + p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
    
    • 泄露puts地址后计算libc基址
  4. 再次栈迁移执行one_gadget:

    payload = p64(bss6+0x30) + p64(r12) + p64(0) + p64(og)
    

案例2:新春杯mg

利用步骤:

  1. 第一次栈迁移:

    pay = b'a'*0x20 + p64(bss) + p64(0x4011FD)
    
  2. 第二次栈迁移:

    pay1 = b'a'*0x20 + p64(bss+0x20) + p64(0x4011FD)
    
  3. 构造ROP链泄露libc:

    pay2 = p64(bss+0x30) + p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
    
  4. 最终getshell:

    payload = p64(bss+0x130) + p64(r12) + p64(0) + p64(og)
    

4. 关键问题解答

为什么要写入bss+0x10的地址?

  • 这是为了在第二次leave时,pop ebp会将伪造栈上的值弹出到EBP
  • 通常需要预留空间存储ROP链,所以选择稍远的地址

如何解决极小溢出空间(如10字节)?

  1. 利用有限的溢出空间修改EBP和返回地址
  2. 返回地址设置为leave; ret指令序列
  3. 通过多次迁移逐步将栈转移到可控区域

5. 技术要点总结

  1. 地址选择

    • 伪造栈通常选择bss段或data段
    • 需要可写且地址已知的区域
  2. 指令序列

    • 需要找到程序中的leave; ret或能构造此序列的gadget
  3. ROP链构造

    • 在伪造栈上构造完整的ROP链
    • 注意栈对齐和参数传递
  4. 多次迁移

    • 当一次迁移无法完成时,可分多步进行
    • 每次迁移逐步将栈转移到更可控的位置
  5. 寄存器控制

    • 注意one_gadget的条件约束
    • 可能需要额外的gadget设置寄存器值

6. 参考资源

  1. 栈平衡和栈迁移原理
  2. PWN技术中的栈迁移技巧
  3. 相关CTF题目writeup

通过掌握栈迁移技术,可以解决许多传统栈溢出无法应对的场景,特别是在溢出空间受限的情况下。关键在于理解栈指针的变化过程,并能够精确控制每一步的迁移操作。

栈迁移技术详解 1. 栈迁移基本概念 栈迁移(Stack Pivoting)是一种通过修改栈指针(ESP/RSP)或基指针(EBP/RBP)来将栈转移到其他内存区域的技术,通常用于解决以下情况: 栈溢出空间不足(如只能溢出少量字节) 原始栈空间不可执行 需要更大的空间构造ROP链 关键指令解释 leave 指令相当于: ret 指令相当于: 2. 栈迁移基本原理 迁移过程 通过溢出修改EBP为伪造的栈地址(如bss段) 控制EIP执行 leave; ret 指令序列 第一次 leave : mov esp, ebp :将ESP指向伪造的栈地址 pop ebp :将伪造栈上的值弹出到EBP 第二次 leave : 将ESP完全迁移到伪造的栈区域 此时可以执行伪造栈上的ROP链 为什么要两次leave 第一次 leave 将ESP指向伪造栈,但仍在原始栈上执行 第二次 leave 将ESP完全迁移到伪造栈区域 这样可以在有限溢出空间内完成完整的栈迁移 3. 栈迁移实战案例 案例1:vnctf2023 traveler 利用步骤: 第一次栈迁移: 修改RBP为bss段地址(bss4) 返回地址设置为read函数(0x401216) 第二次栈迁移: 将RBP进一步迁移到bss+0x20 构造ROP链泄露libc: 泄露puts地址后计算libc基址 再次栈迁移执行one_ gadget: 案例2:新春杯mg 利用步骤: 第一次栈迁移: 第二次栈迁移: 构造ROP链泄露libc: 最终getshell: 4. 关键问题解答 为什么要写入bss+0x10的地址? 这是为了在第二次 leave 时, pop ebp 会将伪造栈上的值弹出到EBP 通常需要预留空间存储ROP链,所以选择稍远的地址 如何解决极小溢出空间(如10字节)? 利用有限的溢出空间修改EBP和返回地址 返回地址设置为 leave; ret 指令序列 通过多次迁移逐步将栈转移到可控区域 5. 技术要点总结 地址选择 : 伪造栈通常选择bss段或data段 需要可写且地址已知的区域 指令序列 : 需要找到程序中的 leave; ret 或能构造此序列的gadget ROP链构造 : 在伪造栈上构造完整的ROP链 注意栈对齐和参数传递 多次迁移 : 当一次迁移无法完成时,可分多步进行 每次迁移逐步将栈转移到更可控的位置 寄存器控制 : 注意one_ gadget的条件约束 可能需要额外的gadget设置寄存器值 6. 参考资源 栈平衡和栈迁移原理 PWN技术中的栈迁移技巧 相关CTF题目writeup 通过掌握栈迁移技术,可以解决许多传统栈溢出无法应对的场景,特别是在溢出空间受限的情况下。关键在于理解栈指针的变化过程,并能够精确控制每一步的迁移操作。