Fastbin Double Free原理
Fast bins
fastbins 划分为10个,其中每一个bins都是一个单向链表,并在链表首部进行插入和删除操作(先进后出)。
对于SIZE_SZ为4B的平台,小于64B的chunk分配请求,对于SIZE_SZ为8B的平台,小于128B的chunk分配请求。首先会查找fast bins中是否有所需大小的chunk存在(精确匹配),如果存在,就直接返回。
默认情况下,fast bins 只 cache 了 small bins 的前 7 个大小的空闲 chunk,也就是说:
- 对于SIZE_SZ为4B的平台,fast bins有7个chunk空闲链表(bin),每个 bin的chunk大小依次为16B,24B,32B,40B,48B,56B,64B;但是其可以支持的chunk的数据空间最大为80字节。
- 对于SIZE_SZ为8B的平台,fast bins有7个chunk空闲链表(bin),每个bin的chunk大小依次为32B,48B,64B,80B,96B,112B,128B;但是其可以支持的chunk的数据空间最大为160字节。
原理
Fastbin Double Free 是指 fastbin 的 chunk 可以被多次释放,因此可以在 fastbin 链表中存在多次。这样导致的后果是多次分配可以从 fastbin 链表中取出同一个堆块,相当于多个指针指向同一个堆块,结合堆块的数据内容可以实现类似于类型混淆(type confused)的效果。
例子
环境准备
ubuntu14.04 x86_64
pwndbg:https://github.com/pwndbg/pwndbg#readme
代码
1 |
|
释放资源超过两次可能导致内存泄漏(memory leaks)
以上代码是在fastbins进行的double-free攻击
分析
1.先malloc()三次,产生三个chunk(堆块)
1 | int *a = malloc(8); |
note:为什么malloc(8),实际上分配32个字节?
1 |
|
32位上SIZE_SZ为4字节,64位上为8字节。
MALLOC_ALIGN_MASK等于2 * SIZE_SZ。
MIN_CHUNK_SIZE 定义了最小的 chunk 的大小,32 位平台上为 16 字节,64 位平台为 24 字节或是 32 字节。MINSIZE 定义了最小的分配的内存大小,是对 MIN_CHUNK_SIZE 进行了 2 * SIZE_SZ 对齐,地址对齐后与 MIN_CHUNK_SIZE 的大小仍然是一样的。
2.打印出返回给用户的堆指针
1 | printf("1st malloc(8): %p\n", a); |
note:为什么返回给用户的指针比chunk的首地址大0x10个字节?
因为返回的是mem,而不是chunk
3.free掉第一块内存
1 | printf("Freeing the first one...\n"); |
1 | printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); |
如果我们再free(a)的话,程序就会崩溃.因为这块内存刚好在对应free-list(fastbins)的首部,再次free这块内存的时候就会被检查到.
note:我们触发了什么检查?
1 |
|
4.所以我们释放另一块chunk
1 | printf("So, instead, we'll free %p.\n", b); |
fastbin是在链表的首部进行插入删除,所以现在的首部是chunk2(b)了
5.再次释放a
1 | printf("Now, we can free %p again, since it's not the head of the free list.\n", a); |
现在,a已经不在首部了,所以当我们再次free(a)就不会触发检查了!!!
6.double free
1 | printf("Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we'll get %p twice!\n", a, b, a, a); |
现在有两个指针指向同一块内存,任何一个改变就会影响另一个。
9447 CTF 2015 writeup
准备
题目链接
https://github.com/ctfs/write-ups-2015/tree/master/9447-ctf-2015/exploitation/search-engine
系统和工具
ubuntu14.04,pwndbg
1 | sakura@ubuntu:~$ lsb_release -a |
checksec
1 | sakura@ubuntu:~$ checksec search |
分析
1 | pwndbg> b *0x0000000000400D7E |
1 | Enter the word size: |
思路
- read_int(sub_400A40)中输入48个字符时,结果不会以null结尾,从而允许leak stack。
- 删除一个句子(通过搜索找到它之后)会删除句子内容并释放该句子,但不会删除指向该句子的词语。这会造成UAF(可以通过打印输出来泄漏信息)和一个double free。
TODO
writeup
https://github.com/pwning/public-writeup/tree/master/9447ctf2015/pwn230-search
1 | sakura@sakuradeMBP:~$ python -c 'print "kaiokenx20\x00"+"A"*5+"././././././././././././././flag.txt\x00\n"+"123"'|nc 128.199.224.175 13000 |