一道题了解虚拟机本身的机制实现的shellcode
字数 1498 2025-08-22 12:22:15

虚拟机机制实现的Shellcode分析与利用

前言

本文记录了一种利用虚拟机(VM)自身机制实现Shellcode的技术,而非传统的通过数据越界泄露libc的方法。这种技术在2024 SCTF的vmcode题目中首次遇到,具有独特的技术特点。

程序保护机制分析

程序采用了沙盒规则限制,反编译工具无法直接查看,需要通过汇编代码分析和调试来理解其工作原理。

虚拟机工作机制

关键跳转逻辑

  1. 程序通过rax寄存器值进行关键跳转控制:

    • rax需要大于等于0x21
    • 跳转地址计算方式:0x123a + offset[i]
  2. 地址计算过程:

    0x5f2bae170257 <main+238> mov rcx, rax
    0x5f2bae17025a <main+241> lea rax, [rip + 0xdbf]
    0x5f2bae170261 <main+248> mov ax, word ptr [rax + rcx*2]
    0x5f2bae170265 <main+252> movzx rax, ax
    0x5f2bae170269 <main+256> pop rcx
    0x5f2bae17026a <main+257> push rcx
    0x5f2bae17026b <main+258> push rcx
    0x5f2bae17026c <main+259> add rax, rcx
    0x5f2bae17026f <main+262> push rax
    0x5f2bae170270 <main+263> and edi, 0xf
    0x5f2bae170273 <main+266> ret
    

功能函数分析

虚拟机提供了19个功能函数,通过传入大于0x21的值加上0x123a来控制执行流程:

  1. 0x21 ($0x1274):

    • 将传入值与初始值0x44相加,结果传给rsi作为后续code的索引值
  2. 0x22 ($0x1299):

    • 调整rdi值作为索引传给esi,影响后续code索引
  3. 0x23 ($0x12A7):

    • 将栈中stack[v1]stack[v1-8]异或,结果存入stack[v1-8]
  4. 0x24 ($0x12c4):

    • 交换stack[v1]stack[v1-0x10]位置
  5. 0x25 ($0x12e0):

    • 交换stack[v1]stack[v1-0x8]位置
  6. 0x26 ($0x12fc):

    • 从code中取值放入stack段
  7. 0x27 ($0x1319):

    • stack[v1]的值变为stack[v1的低位]
  8. 0x28 ($132e):

    • rdi减一
  9. 0x29 ($0x1332):

    • 取出栈中的值右移8位后放回
  10. 0x2a ($0x1348):

    • stack[v1]放入stack[v1+8]
  11. 0x2b ($0x135c):

    • 取出栈中的值左移8位后放回
  12. 0x2c ($0x1372/0x138c):

    • 从stack中读值,如果是0则rsi加2返回,否则取code值处理
  13. 0x2d ($0x13a3):

    • 从栈中获取两个相邻值
    • 使用第二个值作为循环右移位数对第一个值进行循环右移
    • 结果写回栈的前一个位置,同时减少索引rdi
  14. 0x2e ($0x13c0):

    • 类似0x2d,但执行循环左移
  15. 0x2f ($0x13dd):

    • 位与操作
  16. 0x30 ($0x13fa):

    • 关键系统调用:可以控制raxrdirsirdx进行系统调用
  17. 0x31 ($0x1425):

    • stack[v1-1]的值存入stack[v1]
  18. 0x32 ($0x1439):

    • 将code地址偏移rsi后存入stack段

漏洞利用分析

关键利用点

  1. 系统调用控制(0x30):

    • 可以完全控制raxrdirsirdx寄存器
    • 实现ORW(Open-Read-Write)操作链
  2. PIE绕过:

    • 通过[rbx+rdi*8-8]地址读取绕过PIE保护
    • 解决了'flag'字符串地址获取问题

ORW构造过程

  1. open('./flag\x00',0,0):

    push_4_byte(reversed_string_to_int(b'flag'[::-1])) + 
    push_rsp() + 
    push_4_byte(0) + 
    swap_8_10() + 
    push_4_byte(2) + 
    syscall()
    
  2. read(0,adr,len):

    push_rsp() + 
    copy_and_push()*6 +  # 保证读入地址不变,抬高栈防止覆盖
    push_4_byte(0x100) + 
    swap_8_10() + 
    push_4_byte(3) + 
    push_4_byte(0) + 
    syscall()  # read(3,addr,0x100)
    
  3. write操作:

    pop() + 
    copy_and_push() + 
    push_4_byte(0x100) + 
    swap_8_10() + 
    push_4_byte(1) + 
    push_4_byte(1) + 
    syscall()
    

技术要点总结

  1. 通过虚拟机自身的跳转机制实现代码执行控制
  2. 利用系统调用功能(0x30)实现ORW链
  3. 通过栈操作和寄存器控制绕过PIE保护
  4. 仅用61字节即可实现完整的flag读取功能
  5. 关键点在于精确控制栈布局和寄存器值

这种技术展示了在受限环境下如何利用虚拟机自身机制实现攻击,为虚拟机逃逸和沙盒绕过提供了新的思路。

虚拟机机制实现的Shellcode分析与利用 前言 本文记录了一种利用虚拟机(VM)自身机制实现Shellcode的技术,而非传统的通过数据越界泄露libc的方法。这种技术在2024 SCTF的vmcode题目中首次遇到,具有独特的技术特点。 程序保护机制分析 程序采用了沙盒规则限制,反编译工具无法直接查看,需要通过汇编代码分析和调试来理解其工作原理。 虚拟机工作机制 关键跳转逻辑 程序通过 rax 寄存器值进行关键跳转控制: rax 需要大于等于 0x21 跳转地址计算方式: 0x123a + offset[i] 地址计算过程: 功能函数分析 虚拟机提供了19个功能函数,通过传入大于 0x21 的值加上 0x123a 来控制执行流程: 0x21 ($0x1274) : 将传入值与初始值 0x44 相加,结果传给 rsi 作为后续code的索引值 0x22 ($0x1299) : 调整 rdi 值作为索引传给 esi ,影响后续code索引 0x23 ($0x12A7) : 将栈中 stack[v1] 和 stack[v1-8] 异或,结果存入 stack[v1-8] 0x24 ($0x12c4) : 交换 stack[v1] 和 stack[v1-0x10] 位置 0x25 ($0x12e0) : 交换 stack[v1] 和 stack[v1-0x8] 位置 0x26 ($0x12fc) : 从code中取值放入stack段 0x27 ($0x1319) : 将 stack[v1] 的值变为 stack[v1的低位] 0x28 ($132e) : rdi 减一 0x29 ($0x1332) : 取出栈中的值右移8位后放回 0x2a ($0x1348) : 将 stack[v1] 放入 stack[v1+8] 0x2b ($0x135c) : 取出栈中的值左移8位后放回 0x2c ($0x1372/0x138c) : 从stack中读值,如果是0则 rsi 加2返回,否则取code值处理 0x2d ($0x13a3) : 从栈中获取两个相邻值 使用第二个值作为循环右移位数对第一个值进行循环右移 结果写回栈的前一个位置,同时减少索引 rdi 0x2e ($0x13c0) : 类似0x2d,但执行循环左移 0x2f ($0x13dd) : 位与操作 0x30 ($0x13fa) : 关键系统调用 :可以控制 rax 、 rdi 、 rsi 、 rdx 进行系统调用 0x31 ($0x1425) : 将 stack[v1-1] 的值存入 stack[v1] 0x32 ($0x1439) : 将code地址偏移 rsi 后存入stack段 漏洞利用分析 关键利用点 系统调用控制(0x30) : 可以完全控制 rax 、 rdi 、 rsi 、 rdx 寄存器 实现ORW(Open-Read-Write)操作链 PIE绕过 : 通过 [rbx+rdi*8-8] 地址读取绕过PIE保护 解决了'flag'字符串地址获取问题 ORW构造过程 open('./flag\x00',0,0) : read(0,adr,len) : write操作 : 技术要点总结 通过虚拟机自身的跳转机制实现代码执行控制 利用系统调用功能(0x30)实现ORW链 通过栈操作和寄存器控制绕过PIE保护 仅用61字节即可实现完整的flag读取功能 关键点在于精确控制栈布局和寄存器值 这种技术展示了在受限环境下如何利用虚拟机自身机制实现攻击,为虚拟机逃逸和沙盒绕过提供了新的思路。