不知不觉,好像又鸽了快一个月没更新了2333虽说开学但是其实好像也没有很忙,可能就是一直在摸鱼。。。吧
2018 0CTF Babyheap
这个题目做了我还算蛮久的,主要问题在于。。。它开的保护看懵了我orz
1 | checksec babyheap_0ctf_2017 |
啊,太绿了(bushi
分析
打开程序,发现是个菜单类的题目。不过堆指针没有放在.bss
段上,而是使用map开了一段内存来存放。程序功能如下:
分配
1 | void __fastcall func_create(__int64 a1) |
每一项通过一个结构体保存,不过显然应该是没办法用到这个结构体了,因为是随机在内存中分配的。
不过,这里有个需要注意的地方,那就是程序通过calloc
函数分配内存,这将导致分配的区域被清零。
填充
1 | __int64 __fastcall func_fill(__int64 a1) |
可以发现,这里有个任意长度写的机会,这样就能通过堆溢出来实现各种可能的操作。
删除
1 | __int64 __fastcall func_delete(__int64 a1) |
删除倒是没什么问题,指针都清零了。
显示
1 | signed int __fastcall func_dump(__int64 a1) |
会通过结构体的size
字段来控制显示内容的大小。
利用
由于无法通过修改指针来改写值,所以只能使用别的办法,那就是,在unsorted bin
中的chunk会保存指向main_arena
某处的值。我们只需要泄露这个值,再通过main_arena
与libc base
的固定偏移,就能确定libc
的基址。
那么我们的利用思路就是通过覆盖某个hook函数为one gadget
来get shell。那么,如何覆盖呢。
这里用到一个小技巧,通过调试我们可以发现,在main arena
的附近有__malloc_hook
,这样我们就把目标定为修改__malloc_hook
为one gadget
。然后,在__malloc_hook
附近,又可以发现:
再分开一点看。。。
1 | x/56xb 0x7f9023211af0 |
可以发现,在0x7f9023211af5
处,刚好有一串0x7f 0x00 0x00 0x00 0x00 0x00 0x00 0x00
的字节,这转成QWORD
正好就是0x7f
,这样的话,就可以把这里作为fake chunk
的size
字段,那么fake chunk
的开头就是0x7f9023211af5 - 0x8
的位置了。
那么如何把fake chunk
分配出来呢?这就用到fast bin attack
了,通过double free
实现,注意分配的fastbin chunk
大小需要满足为0x70就行。
这样,把fake chunk
分配出来,然后修改__malloc_hook
为one gadget
,在分配一次,就好了。
完整exp如下:
1 | #!/usr/bin/python |