2026 SUCTF Pwn 方向 WriteUp:堆溢出、内核 Page Cache 篡改与 V8 引擎利用
字数 6437
更新时间 2026-04-02 13:46:46
2026 SUCTF Pwn方向WriteUp教学文档
目录
1. 比赛与题目概述
本教学文档基于2026年SUCTF(SUCTF 2026)Pwn方向的官方WriteUp撰写。该比赛Pwn方向包含多个高难度题目,涉及用户态和内核态的多种漏洞利用技术,包括堆利用、内核Page Cache篡改、V8引擎利用以及新型通信架构的漏洞利用。WriteUp提供了详细的逆向分析、漏洞原理、利用链构建和最终利用脚本(exp)的解释。
2. 2.41heap(SU_minivfs)
2.1 题目背景与环境
- 题目名称: SU_minivfs
- 核心漏洞: 堆溢出(Off-by-null)
- 环境: glibc 2.41,启用seccomp,程序有正常退出路径。
- 程序功能: 模拟一个带“鉴权”的简易文件系统,支持
touch、rm、cat、write、stat、ls等命令,分别对应堆内存的malloc、free、read、write等操作。
2.2 逆向分析与关键点
-
鉴权绕过:
- 所有敏感操作都需要一个
auth参数。 - 逆向分析发现,程序对文件路径进行FNV-1a哈希和混淆后,仅与用户输入的
auth进行简单比较 (v7[1] == mixer_result)。 - 由于哈希值可预测,因此“鉴权”并非真正的安全机制,可被轻易绕过。WriteUp中通过本地计算正确的
auth值来自动化所有命令。
- 所有敏感操作都需要一个
-
漏洞定位:
cat命令: 直接按记录的长度输出堆块内容,成为一个稳定的堆信息泄漏原语,可用于泄露libc和堆地址。write命令: 当写入数据大小恰好等于堆块容量(cap)时,补零操作(\0)会写到堆块边界之外,形成一个Off-by-null漏洞。这可以污染下一个堆块的size字段的PREV_INUSE位。
2.3 利用链构建(House of Einherjar -> FSOP)
利用思路围绕Off-by-null展开,目标是最终通过FSOP(File Stream Oriented Programming)劫持控制流。
-
堆布局与泄漏阶段:
- 首先创建一系列文件(堆块),利用
cat命令泄漏出libc基址和堆地址,为后续利用做准备。
- 首先创建一系列文件(堆块),利用
-
利用阶段 - 堆重叠构造:
- 创建两个大小为
0x4f8的堆块(对应/aj和/ap),使其最终在内存中大小为0x500。 - 向
/aj写满数据,触发Off-by-null,将/ap堆块的PREV_INUSE位清零。 - 在
/aj的用户数据区预先布置一个伪造的堆块(fake chunk)。 - 当
free(“/ap”)时,glibc会因PREV_INUSE=0而尝试向前合并,从而将我们的伪造堆块合并进来,造成堆块重叠。这相当于获得了use-after-free (UAF) 能力。
- 创建两个大小为
-
利用阶段 - 控制流劫持:
- 利用堆重叠后的读写能力,进行largebin attack等操作,最终目标是将
_IO_list_all全局指针改写为指向我们伪造的FILE结构体链。 - 伪造的
FILE结构体链放置在可控的堆内存中(例如/ar和/ak文件对应的堆块):FILE结构体本身- 伪造的
_wide_data - 伪造的虚函数表(vtable)
- ROP链(或Shellcode)及路径字符串
- 通过
setcontextgadget进行栈迁移,最终执行ORW(Open-Read-Write)链来读取flag。
- 利用堆重叠后的读写能力,进行largebin attack等操作,最终目标是将
-
最终利用与Flag获取:
- 首次ORW读取
./flag可能得到假flag(障眼法)。 - 修改利用脚本,先通过
getdents系统调用(或类似方法)列出目录,找到真正的flag文件路径,再进行读取。
- 首次ORW读取
2.4 关键技术点总结
- 漏洞挖掘: 关注边界条件,
write在写满时的行为是突破口。 - 利用原语: Off-by-null -> House of Einherjar -> 堆重叠 -> UAF。
- 劫持手法: 结合largebin attack与FSOP,利用程序正常退出时的
_IO_flush_all_lockp触发。 - 绕过技巧: 识别并绕过虚假的鉴权机制。
3. core(SU_Chronos_Ring)
3.1 题目背景
- 题目类型: 内核驱动题。
- 核心漏洞: 通过驱动接口篡改文件的Page Cache。
- 目标: 普通用户权限下,通过利用驱动漏洞,让root进程执行被篡改的脚本,从而读取高权限的
/flag文件。
3.2 逆向分析与接口梳理
驱动通过/dev/chronos_ring设备文件提供一系列ioctl命令:
| ioctl 命令码 | 作用 | 关键点 |
|---|---|---|
0x1001 |
创建 ring buffer | 分配 0x1000 大小的内核缓冲区 |
0x1002 |
鉴权 | 通过后设置 ctx->flags |
0x1003 |
pin 用户页 | pin_user_pages_fast |
0x1004 |
绑定文件页 | fget + read_cache_page |
0x1005 |
创建 view | 为 buffer 创建一个视图(view) |
0x1007 |
向 buffer 写数据 | 向 ring buffer 中 memcpy 数据 |
0x1008 |
把 buffer 内容拷到 view | 本题核心原语 |
0x1009 |
读状态 | 调试辅助 |
0x100a |
销毁 buffer | 清理 |
核心利用链:
0x1004 (绑定文件页) -> 0x1005 (创建view) -> 0x1008 (buffer内容拷贝到view)。
0x1004将指定文件(如/tmp/job)的某一页(page cache)关联到驱动上下文。0x1005为该缓冲区创建一个视图(view),作为数据写入的目标。0x1008将ring buffer中的数据拷贝到上一步创建的view中,实质上是直接修改了文件在内存中的page cache。拷贝后会调用set_page_dirty标记页面为脏。
3.3 漏洞利用流程
-
鉴权绕过:
0x1002命令的鉴权逻辑使用了kfree函数地址的高位经过变换后的值作为种子的一部分。- 由于
kfree地址高位相对固定,熵较低,可以暴力枚举可能的种子值来通过鉴权。
-
目标文件锁定:
- 驱动对
0x1004绑定的文件名有校验,只允许操作/tmp/job文件。 - 题目提供了一个root守护进程,每3秒以root权限执行一次
/tmp/job。
- 驱动对
-
完整攻击链:
0x1001创建缓冲区。0x1002暴力枚举通过鉴权。0x1007向缓冲区写入恶意Shell脚本(如#!/bin/sh\ncat /flag > /tmp/flag\nchmod 666 /tmp/flag)。0x1003pin一个用户页(为view链做准备)。0x1004绑定/tmp/job文件的第0页。0x1005为缓冲区创建view。0x1008执行拷贝,将缓冲区中的Shell脚本写入/tmp/job文件的page cache。- 等待root进程执行被篡改的
/tmp/job。 - 普通用户读取
/flag(或由脚本写入的/tmp/flag)。
3.4 关键技术点总结
- 漏洞本质: 滥用驱动提供的“将缓冲区数据写入文件缓存页”的原语,实现对只读文件的篡改。
- 利用场景: 结合系统的特权进程(root helper)定期执行特定脚本的机制,将权限提升转化为文件篡改。
- 内核利用特点: 本题目无需复杂的内核ROP,关键在于理解驱动接口的组合语义和内核Page Cache机制。
4. IOT
WriteUp中提及此题目将单独撰写复现文章,因此链接内容未提供详细信息。
5. 老版本J2V8学习(SU_BOX)
5.1 题目背景
- 题目类型: JavaScript引擎漏洞利用(V8)。
- 环境: Java应用程序调用老版本的J2V8库(V8 9.3.345.11,对应Chrome 93)。
- 目标: 在受限的J2V8环境中实现任意代码执行。
5.2 环境搭建与调试
- 题目提供了Java App和J2V8库(
libj2v8-linux-x86_64.so)。 - 为了辅助利用,WriteUp修改了Java App源码,增加了强大的调试原语:
log(x): 打印输出。addr(obj): 返回V8对象的原生地址。read64(addr)/read32(addr): 任意地址读。dump(addr, size): 内存dump。write64(addr, value): 任意地址写(关键原语)。jgc(): 手动触发Java GC。
5.3 漏洞利用思路(CVE-2021-38003相关)
由于是旧版本V8,参考了历史漏洞的利用思路,但需适配J2V8环境。
-
制造“TheHole”:
- 利用
JSON.stringify()一个特殊构造的异常对象,得到一个可触发后续Map状态破坏的“令牌”。
- 利用
-
破坏Map并制造OOB(Out-Of-Bounds)访问:
- 利用上一步得到的对象进行操作,破坏某个Map的状态,进而污染一个数组的对象头,使其获得越界读写的能力。
- 在远程环境下,这个OOB窗口可能较小且不稳定,需精确控制。
-
定位可执行内存:
- 创建一个
WebAssembly.Instance对象。WASM实例会分配一块具有RWX(可读、可写、可执行) 权限的内存页用于存放编译后的代码。 - 使用获得的OOB能力,读取wasm实例对象内部的指针,泄露出这块RWX内存的地址。
- 创建一个
-
劫持ArrayBuffer/DataView:
- 创建一个
ArrayBuffer和一个DataView。 - 利用OOB能力,修改
ArrayBuffer的backing store指针(在对象偏移+0x28处)和DataView的data pointer(在对象偏移+0x30处),将它们都指向泄露出的RWX内存页。
- 创建一个
-
写入并执行Shellcode:
- 通过被篡改的
DataView的setUint8等方法,将Shellcode直接写入RWX内存页。 - 调用WASM实例的函数,执行Shellcode。
- 通过被篡改的
5.4 关键技术点总结
- 环境差异: J2V8与标准d8环境在稳定性、对象布局、可用gadget上存在差异,不能直接套用公开PoC。
- 利用链拆分: 采用分步策略:一个OOB窗口用于读地址(如RWX),另一个用于写指针(如backing store)。
- 稳定利用: 远程环境脆弱,对象创建顺序和布局需要精细调整。
6. webpwn(evbuffer)
6.1 题目背景与架构
- 程序功能: 一个同时监听TCP和UDP端口的服务。
- 漏洞类型: 基于libevent库的漏洞利用,涉及全局变量溢出和回调函数劫持。
- 保护机制: 全保护开启(ASLR, PIE, NX等)。
6.2 漏洞分析
-
信息泄漏:
- TCP连接: 在处理TCP连接时,程序在回复数据包中会包含对端的地址信息,其中
hostname字段未初始化,残留了栈上的数据,可能包含libc和PIE地址。 - UDP通信: 通过发送特定报文,可以触发类似的未初始化数据读取,泄漏PIE基址。
- TCP连接: 在处理TCP连接时,程序在回复数据包中会包含对端的地址信息,其中
-
关键溢出漏洞:
- 在处理UDP数据包的某个函数中,存在一个
memcpy,其目标指针最终指向一个全局变量g_udp_ctx附近。 - 对输入IP地址的校验存在缺陷,可通过
\x00截断绕过长度检查。 - 因此,通过发送精心构造的长UDP数据包,可以溢出覆盖
g_udp_ctx结构体中的关键字段,特别是其内部指向bufferevent结构体的指针。
- 在处理UDP数据包的某个函数中,存在一个
6.3 利用链构建(伪造libevent结构体)
-
劫持指针:
- 利用UDP溢出漏洞,覆盖
g_udp_ctx中存储的bufferevent指针,使其指向我们可控内存区域(如.bss段)伪造的bufferevent结构。
- 利用UDP溢出漏洞,覆盖
-
理解libevent触发路径:
- 后续代码会调用
bufferevent_get_output(bev)。 - 该函数内部会访问
bev->output(一个evbuffer指针)。 - 因此,我们只需在伪造的
bufferevent中,将output字段指向另一个我们伪造的evbuffer结构。
- 后续代码会调用
-
利用
evbuffer_add_reference的清理回调:- 在伪造的
evbuffer中,设置其last指针指向一个伪造的evbuffer_chain链表。 evbuffer_chain结构体包含一个cleanup回调函数指针和cleanup_arg参数。evbuffer_add_reference函数在插入新数据前,会清理尾部空的chain,即调用chain->cleanup(chain->buffer, chain->buffer_len, chain->cleanup_arg)。- 通过连续伪造多个
evbuffer_chain,可以构造一个连续的函数调用链。
- 在伪造的
-
构造ORW链:
- 将伪造的
cleanup函数设置为open、read、write等库函数地址。 - 精心设置
cleanup_arg作为参数,构造以下调用序列:open(“flag”, 0, 0)-> 返回文件描述符fd。read(fd, buf, 0x40)-> 读取flag到缓冲区。write(conn_fd, buf, 0x40)-> 将flag写回TCP连接。- (可选)继续读取flag剩余部分。
- 将伪造的
6.4 利用步骤
- 通过TCP连接泄漏libc地址。
- 通过UDP泄漏PIE地址。
- 在.bss段等可写区域布置伪造的
bufferevent、evbuffer、evbuffer_chain结构体链。 - 发送恶意UDP包,溢出覆盖
g_udp_ctx->bev指针指向伪造的bufferevent。 - 触发相关逻辑(如发送特定TCP请求),使程序执行
bufferevent_get_output,进而走入我们伪造的结构体链。 - 通过伪造的
cleanup回调链执行ORW,将flag通过现有的TCP连接发送回来。
6.5 关键技术点总结
- 漏洞组合: 未初始化数据泄漏 + 全局缓冲区溢出。
- 利用框架: 针对特定版本libevent的内部机制进行结构体伪造。
- 回调链构造: 利用
evbuffer_chain的cleanup机制,将数据结构的释放转化为可控的函数调用链,避免了在NX开启下直接执行Shellcode的困难。 - 稳定利用: 利用已有的TCP连接作为输入和输出通道,实现稳定的信息交互和flag回传。
相似文章
相似文章