写点什么

musl 堆利用技巧,你知道多少

  • 2022 年 2 月 16 日
  • 本文字数:1768 字

    阅读完需:约 6 分钟

前言

最近比赛出的 musl 题型的越来越多,不得不学习一波 musl 的堆利用来应对今后的比赛。这里要讲的是 musl1.22 版本的利用,因为网上可以找到很多审计源码的文章,所以这篇文章是通过一道题目来 debug 去学习堆的利用技巧,这里用到的是 2021 第五空间线上赛的 notegame 题目。

题目分析

1、首先是 add 函数,使用了 calloc,申请的最大 size 是 0x90



2、接着是 delete 函数,free 之后将指针清空了



3、然后是 edit 函数,漏洞就出现在这里,这里存在溢出空字节的漏洞,可以对 index 清零指向 fake_meta



4、最后来看这个 update 函数,这个 realloc 函数会将原来 chunk 的内容复制到新的 chunk 里面,我们可以用这个来进行泄露 libc 地址



【一>所有资源获取<一】1、网络安全学习路线 2、电子书籍(白帽子)3、安全大厂内部视频 4、100 份 src 文档 5、常见安全面试题 6、ctf 大赛经典题目解析 7、全套工具包 8、应急响应笔记

调试分析

musl 的 chunk 跟 glibc 的区别就是,chunk 头的结构存放了比较少的堆块信息,没有像 glibc 那样存放了一些指针地址信息,所以我们如果要泄露 libc 地址的话也是要特定的条件,就是要 chunk 里面保存着另外一个 chunk 的指针地址或者其他指针地址的信息,而且也再不能直接改指针去达到任意分配的效果,而是要改 chunk 头仅有的信息去伪造 meta 进行任意分配。

malloc_context

add(0x20,'a'*0x20)



1、secret 是用来校验 meta 域的一个 key


2、free_meta_head 存放着释放掉的 meta,是个单链表结构,这里还没有释放,所以为空


3、active 是根据 size 大小分出来的不同的 meta


4、usage_by_class 是对应 meta 的数量

meta

add(0x20,'a'*0x20)add(0x20,'a'*0x20)add(0x20,'a'*0x20)add(0x20,'a'*0x20)free(0)
复制代码



1、prev 和 next 分别是上一个和下一个 meta 页,这里都指向本身,表示只有一个 meta 页


2、 mem 表示 group 的地址,它是由多个 chunk 组成


3、avail_mask 表示可以分配的 chunk 情况,0x3f0=0b01111110000,因为我们已经分配了 4 个堆块,所以这里表示前四个不可分配。


4、freed_mask 表示已经释放的 chunk 情况,因为我们释放掉了第一个 chunk,所以这里的 0x1 表示的是 free 掉的第一个 chunk


5、last_idx 表示最后一个 chunk 的下标,这里是 0x9,总数是 0xa 个


6、freeable 表示已经释放的堆块个数


7、sizeclass 表示管理的 group 的大小


8、maplen 如果不为零表示 mmap 分配的内存页数

chunk

add(0x20,'a'*0x20)add(0x20,'a'*0x20)add(0x20,'a'*0x20)add(0x20,'a'*0x20)free(3)
复制代码



1、表示距离 group 首地址的偏移分别为 0x0、0x30、0x60,系统是根据这个偏移来找到对应的 meta 地址,所以我们如果能改这个偏移比如把 chunk1 的偏移置零的话,就能在 chunk1-0x10 的地方伪造一个 meta 的指针,而这个地方又是我们可以控制的 chunk0 的 data 域,于是我们就可以在任意地方伪造一个 meta,不过这个地址必须是跟 0x1000 对齐的。


2、表示当前 chunk 的下标,当 chunk 被 free 之后会变成 0xff


3、表示剩下用户空间的大小,chunk 头后面的 4 个字节跟 glibc 的 prev_size 那样可以被上一个 chunk 复用, 所以我们就可知道我们分配的大小跟 chunk 大小的关系


0x10:0-0xc0x20:0xd-0x1c0x30:0x1d-0x2c0x40:0x2d-0x3c...
复制代码

chunk 的分配释放

add(0x50,'a'*0x50)add(0x50,'a'*0x50)add(0x50,'a'*0x50)free(0)add(0x50,'a'*0x50)
复制代码



avail_mask = 0x10=0b10000


freed_mask = 0x1 =0b00001


musl 的 chunk 释放了之后并不会马上分配,这里 group 里面有 5 个 chunk,先是申请了 3 个 chunk,然后 free 掉第一个,再次申请的时候并不会把第一个 chunk 分配出来,而是把 group 的第四个 chunk 申请出来,然后对应的 avail_mask 置零


add(0x50,'a'*0x50)add(0x50,'a'*0x50)add(0x50,'a'*0x50)add(0x50,'a'*0x50)free(0)free(1)free(2)add(0x50,'a'*0x50)add(0x50,'a'*0x50)
复制代码



avail_mask = 0x6 =0b0110


freed_mask = 0x0 =0b0000


耗尽 group 的 chunk 的时候,musl 会把释放掉的申请出来,并把其他 chunk 对应的 avail_mask 置 1

meta 的释放

add(0x50,'a'*0x50)free(0)
复制代码



当只有一个 chunk 是被分配出去的,而 freed_mask=0,我们把这个 chunk 给 free 掉之后,系统会回收整块 meta 空间


add(0x50,'a'*0x50)add(0x50,'a'*0x50)add(0x50,'a'*0x50)add(0x50,'a'*0x50)add(0x50,'a'*0x50)free(0)free(1)free(2)free(3)free(4)
复制代码



总结起来,就是说avail_mask |freed_mask的结果是满状态的时候,就会释放这个 meta。

总结

本篇先通过 debug 的方法来简单阐述 musl 堆块的结构,后续再讲如何对它进行利用。

用户头像

我是一名网络安全渗透师 2021.06.18 加入

关注我,后续将会带来更多精选作品,需要资料+wx:mengmengji08

评论

发布
暂无评论
musl堆利用技巧,你知道多少