首页
社区
课程
招聘
[分享]0ctf2017 - babyheap
发表于: 2017-12-21 16:57 20974

[分享]0ctf2017 - babyheap

2017-12-21 16:57
20974

学习 how2heap 中 fastbin attack 的知识点

babyheap

考察的知识点:

利用 fastbin attack 即 double free 的方式泄露 libc 基址,当只有一个 small/large chunk 被释放时,small/large chunk 的 fd 和 bk 指向 main_arena 中的地址,然后 fastbin attack 可以实现有限的地址写能力。

程序保护全开,并且没有 debug symbols。

程序没有 uaf ,内存被释放后无法查看其中内容,可以通过 double free 获得指向 small bin 的 index,将其释放后 dump 出来。

首先分配一系列相同大小的 fast chunk,再分配一个 small chunk,释放掉其中一个 fast chunk。

此时我们查看一下堆内存,和 main_arena。

释放的那个 fast chunk 被放入到 fastbin 中,fastbin 为单链表形式,如果再释放一个 fast chunk,将其插入 fastbin 的头部,释放的第二个 chunk 其 fd 会被设置成第一个 chunk 的地址。

此时使用 fill 覆盖 fastbin 头部 chunk 的 fd 值,将其改写成 small chunk 的地址,那么通过两次 alloc,先将 small chunk 放入 fastbin,再将其取出来,获得指向它的 index。要这么做必须绕过 malloc 的安全检查:

查看其 chunksize 与相应的 fastbin_index 是否匹配,实际上 chunksize 的计算方法是 victim->size & ~(SIZE_BITS)),而它对应的 index 计算方法为 (size) >> (SIZE_SZ == 8 ? 4 : 3) - 2,这里 64位的平台对应的 SIZE_SZ 是8,则 fastbin_index 为 (size >> 4) - 2,那么我们将 small chunk 的 size 域改写成 0x21 即可。

可以看到 index[2] 存放的是 small chunk 的地址,此时将 small chunk 的 size 改写回来,将其释放掉就可以 dump 出来了。

获得了 libc 地址,我们可以使用 fastbin attack 将一个 libc 上的地址放入 fastbin 链表中,然后 malloc 出来,这样就可已改写 libc 的内容。malloc_hook 是一个 libc 上的函数指针,调用 malloc 时如果该指针不为空则执行它指向的函数,可以通过写 malloc_hook 来 getshell。

同样的,这里我们也要绕过 malloc 的安全检查,chunksize 必须与 fastbin_index 相对应,初看 __malloc_hook 附近没有合适的 chunksize,这里需要巧妙的偏移一下。

可以看到以这个地址作为 chunk 指针即可构造出 index 为 5 的 fastbin,那么我们就可以成功的改写 __malloc_hook了,现在只差可执行代码。

这里介绍一个神奇的工具 one gadget,只用一个 gadget 地址就可以成功调用 execve("/bin/sh")。

最后给出完整的 exploit 代码 exp.py

Reference

 
 
 
 

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2018-3-26 13:40 被gd菜鸡编辑 ,原因: 更新链接
收藏
免费 1
支持
分享
最新回复 (9)
雪    币: 285
活跃值: (1095)
能力值: ( LV13,RANK:405 )
在线值:
发帖
回帖
粉丝
2
支持
2017-12-24 22:13
0
雪    币: 4975
活跃值: (3858)
能力值: ( LV13,RANK:270 )
在线值:
发帖
回帖
粉丝
3
牛皮,Bill
2018-3-7 17:36
0
雪    币: 699
活跃值: (444)
能力值: ( LV9,RANK:240 )
在线值:
发帖
回帖
粉丝
4
最近正打算调0ctf2017,mark
2018-3-8 02:14
0
雪    币: 5676
活跃值: (1303)
能力值: ( LV17,RANK:1185 )
在线值:
发帖
回帖
粉丝
5
不错
2018-3-9 04:33
0
雪    币: 1218
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学习一波
2018-8-17 17:28
0
雪    币: 5
活跃值: (33)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
gdb 地址显示g 8字节更好吧
2018-8-21 11:28
0
雪    币: 22
活跃值: (54)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
最后面写one_gadget 偏移错了吧,应该是19,你上面算下来是22
2018-11-13 01:29
0
雪    币: 4
活跃值: (197)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
你好,我按照你的过程进行调试,但第一步的结果和你的不一样,释放后的chunk没有放入fast bin管理,调试研究了三天了都没找到问题,能不能帮我看一下?
一. 我按照你帖子中的,先创建4个fast chunk,再创建一个small chunk,然后把第1个fast chunk释放:
alloc(0x10)
alloc(0x10)
alloc(0x10)
alloc(0x10)
alloc(0x80)
free(1)

此时的内存如下(和你帖子里的基本是一样的):
gdb-peda$ x/40wx 0x555555757260-0x10
0x555555757250:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 0 (fastbin, in use)
0x555555757260:        0x00000000        0x00000000        0x00000000        0x00000000  
0x555555757270:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 1 (fastbin, free)
0x555555757280:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757290:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 2 (fastbin, in use)
0x5555557572a0:        0x00000000        0x00000000        0x00000000        0x00000000
0x5555557572b0:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 3 (fastbin, in use)
0x5555557572c0:        0x00000000        0x00000000        0x00000000        0x00000000
0x5555557572d0:        0x00000000        0x00000000        0x00000091        0x00000000  <--- chunk 4 (smallbin, in use)
0x5555557572e0:        0x00000000        0x00000000        0x00000000        0x00000000

这个时候我查看main_arena,在fast bins里并没有找到chunk1:
gdb-peda$ x/20wx &main_arena
0x7ffff7fa8c40 <main_arena>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c50 <main_arena+16>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c60 <main_arena+32>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c70 <main_arena+48>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c80 <main_arena+64>:        0x00000000        0x00000000        0x00000000        0x00000000
gdb-peda$ p main_arena
$1 = {
  mutex = 0x0, 
  flags = 0x0, 
  have_fastchunks = 0x0, 
  fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
  top = 0x555555757360, (top chunk)
  last_remainder = 0x0, 
  bins = {0x7ffff7fa8ca0 <main_arena+96>, 0x7ffff7fa8ca0 <main_arena+96>, 
    0x7ffff7fa8cb0 <main_arena+112>, 0x7ffff7fa8cb0 <main_arena+112>, 
       
二. 然后我再释放chunk2, free(2),释放后的内存如下:
gdb-peda$ x/40wx 0x555555757260-0x10
0x555555757250:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 0 (fastbin, in use)
0x555555757260:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757270:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 1 (fastbin, free)
0x555555757280:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757290:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 2 (fastbin, free)
0x5555557572a0:        0x55757280        0x00005555        0x00000000        0x00000000
0x5555557572b0:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 3 (fastbin, in use)
0x5555557572c0:        0x00000000        0x00000000        0x00000000        0x00000000
0x5555557572d0:        0x00000000        0x00000000        0x00000091        0x00000000  <--- chunk 4 (smallbin, in use)
0x5555557572e0:        0x00000000        0x00000000        0x00000000        0x00000000
因为是先free(1),再free(2),所以fast bin的头接点应该是chunk2,chunk2的fd指向chunk1,看上面的内存确实有点像,但是chunk2的fd应该是0x555555757270的呀,为什么是0x555555757280了,差了0x10,不明白。
而且这个时候再查看main_arena,发现fastbins里还是空的,要哭了:
gdb-peda$ x/20wx &main_arena
0x7ffff7fa8c40 <main_arena>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c50 <main_arena+16>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c60 <main_arena+32>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c70 <main_arena+48>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c80 <main_arena+64>:        0x00000000        0x00000000        0x00000000        0x00000000
gdb-peda$ p main_arena
$2 = {
  mutex = 0x0, 
  flags = 0x0, 
  have_fastchunks = 0x0, 
  fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
  top = 0x555555757360, (top chunk)
  last_remainder = 0x0, 
  bins = {0x7ffff7fa8ca0 <main_arena+96>, 0x7ffff7fa8ca0 <main_arena+96>, 
    0x7ffff7fa8cb0 <main_arena+112>, 0x7ffff7fa8cb0 <main_arena+112>, 
    0x7ffff7fa8cc0 <main_arena+128>, 0x7ffff7fa8cc0 <main_arena+128>, 
    0x7ffff7fa8cd0 <main_arena+144>, 0x7ffff7fa8cd0 <main_arena+144>, 
三. 我再尝试申请一个大小为0x10的fast chunk,alloc(0x10),按照fast bin的特性,应该是返回刚刚释放的chunk2,但结果并不是这样的,而是从top chunk里分隔出一个新的chunk返回了。
此时的内存如下:
gdb-peda$ x/80wx 0x555555757260-0x10
0x555555757250:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 0 (fastbin, in use)
0x555555757260:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757270:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 1 (fastbin, free)
0x555555757280:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757290:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 2 (fastbin, free)
0x5555557572a0:        0x55757280        0x00005555        0x00000000        0x00000000
0x5555557572b0:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 3 (fastbin, in use)
0x5555557572c0:        0x00000000        0x00000000        0x00000000        0x00000000
0x5555557572d0:        0x00000000        0x00000000        0x00000091        0x00000000  <--- chunk 4 (smallbin, in use)
0x5555557572e0:        0x00000000        0x00000000        0x00000000        0x00000000
0x5555557572f0:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757300:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757310:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757320:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757330:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757340:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757350:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757360:        0x00000000        0x00000000        0x00000021        0x00000000  <--- chunk 5 (fastbin, in use)
0x555555757370:        0x00000000        0x00000000        0x00000000        0x00000000
0x555555757380:        0x00000000        0x00000000        0x00020c81        0x00000000
此时的main_arena如下:
gdb-peda$ x/20wx &main_arena
0x7ffff7fa8c40 <main_arena>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c50 <main_arena+16>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c60 <main_arena+32>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c70 <main_arena+48>:        0x00000000        0x00000000        0x00000000        0x00000000
0x7ffff7fa8c80 <main_arena+64>:        0x00000000        0x00000000        0x00000000        0x00000000
gdb-peda$ p main_arena
$4 = {
  mutex = 0x0, 
  flags = 0x0, 
  have_fastchunks = 0x0, 
  fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
  top = 0x555555757380, 
  last_remainder = 0x0, 
  bins = {0x7ffff7fa8ca0 <main_arena+96>, 0x7ffff7fa8ca0 <main_arena+96>, 
    0x7ffff7fa8cb0 <main_arena+112>, 0x7ffff7fa8cb0 <main_arena+112>, 
    0x7ffff7fa8cc0 <main_arena+128>, 0x7ffff7fa8cc0 <main_arena+128>, 
    0x7ffff7fa8cd0 <main_arena+144>, 0x7ffff7fa8cd0 <main_arena+144>, 
    0x7ffff7fa8ce0 <main_arena+160>, 0x7ffff7fa8ce0 <main_arena+160>, 
    0x7ffff7fa8cf0 <main_arena+176>, 0x7ffff7fa8cf0 <main_arena+176>, 

整个过程中fast bin好像并没有生效,好奇怪,求指导~
       




最后于 2019-1-1 15:23 被liuxucau编辑 ,原因: 错别字
2019-1-1 15:20
0
雪    币: 279
活跃值: (26)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
代码有个bug,其实文中脚本调用的还是系统的libc,调用本地应该是 process(elf,env=ENV)。
脚本的libc偏移应该是基于2.23的。
2019-1-16 00:09
0
游客
登录 | 注册 方可回帖
返回
//