2025全国大学生软件系统安全赛——VM题解
字数 1990 2025-08-22 12:22:54
2025全国大学生软件系统安全赛VM题解教学文档
1. 题目概述
这是一道虚拟机(VM)相关的PWN题目,具有以下特点:
- 保护全开(包括ASLR、NX等)
- 代码量大,逆向分析是主要难点
- 使用自定义的VM架构
- 通过vmdata和vmcode文件提供初始数据
2. 初始分析
2.1 程序启动流程
-
初始化函数(sub_30C0):
- 设置三个关键指针:
- qword_6120 → 0x64617461000
- qword_6128 → 0x7063000
- qword_6160 → 0x73746163000
- 设置三个关键指针:
-
读取外部数据(sub_3107):
- 读取vmdata和vmcode文件
- 将文件内容(跳过前4字节长度字段)分别写入0x64617461000和0x7063000
2.2 主要数据结构
- VM内存布局:
- 0x64617461000: 数据区域
- 0x7063000: 代码区域
- 0x73746163000: 可能为栈区域
3. VM指令解析
3.1 指令解码流程(sub_2F6F)
-
指令提取(sub_132D):
- 从vmcode读取1字节
- vmcode指针后移1字节
- context[0] = 读取的字节
- context[1] = 字节 & 3 (用于分支选择)
-
分支选择:
根据context[1]的值(0-3)跳转到不同处理函数
3.2 各分支功能
分支3 (value & 3 == 3)
- 处理函数(sub_2A49):
- 根据vmcode >> 2选择操作
- 主要操作形式:
*(vmcode_6120 + 8 * (*(context + 4) + 2LL)) - 关键操作(case 3): 直接赋值操作
分支2 (value & 3 == 2)
- 处理函数(sub_23A7):
- 数组元素间的赋值操作
分支1 (value & 3 == 1)
- 处理函数(sub_2142):
- 对数组的赋值操作
分支0 (value & 3 == 0)
- 处理函数(sub_19AD):
- 包含堆操作和内存读写功能
- 漏洞点所在
4. 漏洞分析
4.1 关键函数(sub_19AD)
-
安全检查:
sub_12E8: 确保qword_6120[3] ≤ 0x30000
-
堆操作:
- 可以申请16个无限制大小的堆块
- free后未清空指针,存在UAF漏洞
-
内存操作:
read_from_memory: 从0x64617461000的偏移地址读取数据到堆中write_to_memory: 将堆中的数据写入0x64617461000的偏移地址
4.2 可利用点
-
控制能力:
- context可控
- qword_6120数组下标≥2可控
-
利用链:
- 通过choice3控制数组元素
- 通过choice0进行堆操作和内存读写
5. 利用思路
5.1 阶段一: 泄露libc和heap地址
- 设置size=0x500,申请堆块0
- 修改size,申请堆块1
- 释放堆块0,使其进入largebin
- 申请比堆块0大的堆块2
- 利用write_to_memory读取堆块0中的libc和heap地址
- 通过write操作泄露地址
5.2 阶段二: 泄露栈地址
- 设置size=0x90,申请两个0x90堆块并释放
- 修改fd指向environ
- 重新申请,获取包含environ的堆块
- 读取environ中的栈地址
- 通过write操作泄露栈地址
5.3 阶段三: ROP攻击
- 设置size=0x80,申请两个0x80堆块并释放
- 修改fd指向返回地址(选择sub_132D函数中的返回地址)
- 写入ROP链
- 触发函数返回执行ROP
6. 完整利用代码分析
6.1 关键payload构造
# 设置size=0x500
code = p32(0x0500000f).ljust(10, b'\x00') # choice3修改qword_6120[2+0]为0x500
code += p32(0x030000cc) # 申请chunk 0
6.2 地址泄露
# 泄漏libc地址
libc_base = u64(io.recv(6).ljust(8, b'\x00')) - 0x21b110
# 泄漏heap地址
heap_base = u64(io.recv(6).ljust(8, b'\x00')) - 0x2b0
6.3 ROP链构造
# ROP链
payload = p64(stack_addr)*4 + p64(rdi) + p64(ret) + p64(rdi) + p64(bin_sh) + p64(system)
7. 关键技巧总结
-
逆向分析技巧:
- 优先分析可能包含漏洞的分支(如choice0)
- 不必完全理解所有指令功能,重点寻找可利用的读写原语
-
利用技巧:
- 利用largebin泄露libc地址
- 利用environ泄露栈地址
- 精心选择返回地址位置确保ROP链执行
-
VM PWN通用方法:
- 理解VM的内存布局和指令集
- 寻找内存读写和堆操作原语
- 利用VM自身的功能构造利用链
8. 防御建议
-
对题目设计者:
- 在free后清空指针
- 限制堆块大小
- 增加内存访问的边界检查
-
对参赛者(防御角度):
- 注意UAF漏洞的检测
- 检查所有内存读写操作的边界
- 确保敏感数据(如指针)不被泄露
9. 扩展思考
-
其他可能的利用方式:
- 利用VM的指令集实现任意代码执行
- 篡改VM的关键数据结构实现控制流劫持
-
类似题目训练建议:
- 研究其他VM PWN题目(如Defcon Quals中的VM题目)
- 练习自定义指令集的逆向分析
- 熟悉各种虚拟架构的内存管理方式