护网杯 2019 pwn flower 详解
TOC
- 1. flower 漏洞
- 2. scanf 触发 malloc_consolidate
- 3. 利用 malloc_consolidate 巧妙 unlink
- 4. chunk overlap 泄露地址
- 5. 劫持 top_chunk
- 6. 劫持hook
- 7. 完整代码
这题的质量是真心不错,学到了很多东西,所以拿出来特地讲解一下。
源程序下载:flower.zip 。
flower 漏洞
靶机环境 glibc-2.23 。
void __cdecl read_n(_BYTE *a1, unsigned int a2) |
非常明显的off by one漏洞,但是由于size限制为size > 0 && size <= 0x58,所以使得程序的利用十分麻烦。
scanf 触发 malloc_consolidate
由于size的限制,我们只能申请到fastbin,如果直接off by one会把size给踩没了,这样free的话会直接crash,而且不放进unsorted bin的话,我们也无法泄露地址,但是如何将chunk放入unsorted bin呢?
当top_chunk不够时,或者申请了一个large bin,也就是size大于0x400的chunk就能触发malloc_consolidate,使得fastbin合并,并且放入unsorted bin中。
这里用到了scanf的一个缓冲机制,当scanf的缓冲区不够用时,就会malloc一块更大的chunk来充当新的缓冲区,然后使用完之后在free掉,当我们的输入大于0x400时,自然会申请一块大于0x400的chunk来当缓冲区,正是这个申请可以触发malloc_consolidate。
for i in range(6): |
调试结果:
pwndbg> bin |
这里的chunk被放入smallbin是因为申请0x400的chunk时,对unsorted bin进行了归位操作。
利用 malloc_consolidate 巧妙 unlink
虽然有unsorted bin可以用了,但是我们并没有一个size为0x100的chunk可以free,根据size的限制,我们也不可能申请到,那么该如何进行unlink呢,这里就要用到malloc_consolidate一个巧妙的地方。
下面源码来自:glibc-2.23/malloc/malloc.c:4122
static void malloc_consolidate(mstate av) |
可以看到malloc_consolidate操作是从小的fastbin开始,然后逐渐转向大的,使他们都合并成unsorted bin,如果我们先把size的尾巴踩掉,使得该unsorted bin和后面的chunk断片,然后在申请一块较小的chunk,那么malloc_consolidate时,这块较小的chunk,会优先放入unsorted bin中,然后在合并后面断片的chunk时,就会直接unlink进行合并,那么我们就可以利用中间的chunk来进行 chunk overlap 的操作了。
add(0x58, 0, 'a' * 0x50 + p64(0x61)) |
合并之前的情况如下:
pwndbg> bin |
根据我上面说的原理,0x55f4dccbe060和0x55f4dccbe1e0在malloc_consolidate会合并成一个大chunk。
chunk overlap 泄露地址
简单的地址泄露。
add(0x18, 0, '\n') |
劫持 top_chunk
还是因为size > 0 && size <= 0x58的限制,我们没有办法使用正常的0x7fsize来劫持__malloc_hook,这时就需要我们想出新的办法来劫持hook。
由于fastbin和top_chunk邻近,而且fastbin一般都是0x56....(开了PIE)之类的,那么size > 0 && size <= 0x58的限制刚好可以申请到这种size,所以我们利用fastbin的地址充当size,然后malloc出 main_arena,再劫持 top_chunk 。
remove(3) |
代码的调试信息如下:
pwndbg> bin |
可以看到我们已经可以拿出main_arena,由于只有当size为0x0000000000000055才能申请出来,所以几率应该是1/3。
然后我们可以将top_chunk指向<_IO_wide_data_0+296>,因为那里有一个天然的size:
pwndbg> x/8gx 0x7ff5bb0bbb00-0x20-8 |
劫持hook
当我们成功劫持top_chunk后,只要把unsorted bin用完,那么程序就会从top_chunk里面切割内存给我们,这样我们就能劫持下面的__malloc_hook了。
add(0x48, 0, '\0' * 0x3b + p64(main_arena_addr - 0x28)) |
完整代码
概率是1/3 。
#!/usr/bin/python2 |