写着写着发现好像不过是每日新坑orz,之前的都没怎么写完,还得留着后边填坑。。。
至少先熟悉这些利用方式,后边再补充好了。。。
参考
Unsorted Bin Attack 被利用的前提是控制Unsorted Bin Chunk 的 bk 指针。可以达到的效果是实现修改任意地址值为一个较大的数值。
Unsorted Bin
来源
1、当一个较大的chunk被分割为两部分的时候,如果剩下的部分大于MINSIZE,就会被放到unsorted bin中。
2、释放一个不属于fast bin的chunk,并且该chunk不和top chunk紧邻时,该chunk会被首先放到unsorted bin中。
3、当进行malloc_consolidate时,可能会把合并后的chunk放到unsorted bin中(如果不和top chunk紧邻的话)。
使用
1、unsorted bin在使用过程中,采用的顺序遍历时FIFO,即先入先出。
2、在程序malloc时,如果在fastbin。small bin中找不到对应大小的chunk,将会尝试从unsorted bin中寻找chunk。如果取出来的chunk大小刚好满足,就会直接返回给用户,否则就会把这些chunk分别插入到对应的chunk中。
原理
在_init_malloc中这么一段代码,当将一个unsorted bin取出时,会将bck->fd
的位置写入本Unsorted bin的位置。
1 | /* remove from unsorted list */ |
即如果控制了bk的值,我们就能将unsorted_chunks(av)
写到任意地址。
栗子
借助sellphish的unsorted_bin_attack.c
1 |
|
运行结果如下
1 | ./unsorted_bin_attack |
然后通过gdb调试看看。
在第一次分配malloc(400)
之后
1 | heap |
然后分配malloc(500)
防止释放的时候被合并到top chunk中。
在free(p)
之后
1 | heap |
此时该chunk的fd和bk都指向同样main_arena+88的位置
在修改chunk的bk指针之后,指向栈上的地址-0x10处(32位为-0x8)
1 | heap |
在malloc之前,栈上地址(0x7fffffffdcd8)处的值为0
1 | 00:0000│ rsp 0x7fffffffdcd0 —▸ 0x400890 (__libc_csu_init) ◂— push r15 |
在malloc(400)
之后,栈上的地址写入了main_arena+88的值
1 | 00:0000│ rsp 0x7fffffffdcd0 —▸ 0x400890 (__libc_csu_init) ◂— push r15 |
在最后一次malloc的时候,所申请的chunk大小在unsorted bin所在的范围,就去unsorted bin内查找,找到以后返回,执行以下操作
1 | while ((victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) { |
- victim = unsorted_chunks(av)->bk = p
- bck = victim->bk = p->bk = target addr - 0x10
- unsorted_chunks(av)->bk = bck = target addr - 0x10
- bck->fd = *(target addr - 0x10 + 0x10) = unsorted_chunks(av)
可以看出,在将unsorted bin的最后一个chunk拿出来的过程中,victim的fd并没有发挥作用,所以即使修改掉也没有关系。但是,unsorted bin链表可能就此破坏,在插入chunk时,可能会出现问题。
这样可以使得我们可以通过这,将目标地址的值改成一个比较大的值,但是这个值不受我们的控制。这个在某些时候还是很有用的,比如说:
- 通过修改循环次数,达到多次循环
- 通过修改heap中的的 global_max_fast来使得更大的chunk可以被视为fast bin,这样我们可以执行一些fast bin attack了。
一些例子
HITCON Training lab14 magic heap
查看一下保护
1 | checksec magicheap |
程序逻辑很简单
- 创建堆,给定堆的大小,大小没有限制,数量有限制
- 删除堆,会清空指针
- 修改堆,漏洞在这里,修改的大小是自己输入的,所以有堆溢出漏洞
- 输入4869,这时比较magic的值和0x1305的大小,如果大于,那么就能获得flag。
思路就很简单,释放一个chunk到unsorted bin中,然后通过堆溢出修改该chunk的fd值为&magic
exp
1 | #!/usr/bin/env python |
2016 0CTF zerostorange
看看保护
1 | checksec zerostorage |
嗯,看来保护都开了23333
分析一下功能,主要有插入、修改、合并、删除、展示和列举:
插入,如果不到32个记录,那就再插入一个记录,记录的格式是这样
1
2
3
4
5struct record{
QWORD flag; //当前记录是否被占用(1-被占用,0-为占用)
QWORD size; //保存当前记录的大小
QWORD ptr; //指向记录的指针
}malloc分配的大小限制再128-4096的范围内,但是size保存的是输入的大小
修改,根据index和输入的大小判断是否重新分配一块内存保存新的内容
- 合并,合并两个记录到新的记录上去,删掉原来两个记录,并清零指针,但是chunk2的没有被释放,并且没有检查两个index是否相同
- 删除,删除记录,并且清零指针
- 展示,根据index展示记录内容
- 列举,列举每个有效记录的序号和大小