Fastbin Attack之雷霆万钧:0ctf2017 babyheap
本文要点概括:
fastbin attack
__malloc_hook与size错位构造
绕过calloc泄露内存的通用思想(堆块溢出“受孕”、fastbin attack利用、远交近攻“隔山打牛”)
边缘效应与耦合缓解(unsorted_bin中chunk再分配、清空bin环境)
libc依赖:
有关不同libc版本下的堆地址
随着堆的学习,最近一直保持着有关libc堆漏洞利用的文章的更新,之前以babynote为例讲了unsorted bin attack,这次以0ctf2018 babyheap为例讲解一下fastbin attack的东西。
堆的知识细节很庞大,每次pwn一个challenge都会收获很多东西。之前是复现的babynote那道题,但毕竟是参考了别人的exp自己心里还是没底,而这次的babyheap的exploit开发则是彻头彻尾自己完成的,过程和结果令人惊喜:自己写出的有效exp之后和网上的exp进行了对比,发现思路有比较大的出入,也就意味着学到了更多的东西。
题目链接
一、逆向分析与漏洞挖掘
丢进IDA,main函数F5,如下(函数名我已进行手动重命名):
0x01、new_log()如下:
我们的堆块就是通过该函数分配,索引表的结构就是传统的堆题目结构,由exist字段、大小字段和用户区指针构成;值得注意的是此处使用的内存分配函数是calloc而不是malloc,calloc分配chunk时会对用户区数据进行置空,也就是说之前的fd和bk字段都会被置为0,这在进行内存泄露时会造成一定的难度;返回的chunk下标也是传统的exist字段遍历法,下标从0开始。
0x02、edit_log()如下:
可以看到,程序并没有对用户输入的Size长度进行检查,这就造成了任意长度输入,形成堆溢出漏洞;此外,输入没有尾补字符串结束符,有可能会造成内存泄露(该程序后经分析,内存泄露不利用此处缺陷)
0x03、delet_log()如下:
可以看到,这段free函数写的是很安全的,首先对用户通过下标选择进行free的chunk在索引表层面做了存在性检查,如果exist字段为0说明已经free便不再继续执行free,这有利于防范double free;free成功后,相应的索引表的exist字段置空、堆指针置NULL也做到位了。总之该部分没有安全漏洞。
0x04、print_log()如下:
其中sub_130F():
这个读内容函数也是安全的,首先作了存在性检查,如果exist字段为0就不会去读,也就是说只能读new过的记录;并且读取用的是write而不是puts,write读的长度也是索引表中记录的长度(即当初new的时候输入的长度的多大就只能读多大 )
0x05、逆向分析小结:
该程序存在堆溢出漏洞,但是由于其他保护作的较好,在泄露内存阶段应该会遇到较大阻力;堆溢出漏洞可能带来Fastbin Attack的机会。
二、漏洞利用分析
在进行具体分析之前,我们先粗略讲一下fastbin attack的相关知识:
(详细讲解请参考ctf wiki上的教程)
1.fastbin是单链表,按chunk大小递增一共有好几个,用户free一个chunk以后,如果大小是属于fastbin的、又不与top chunk相邻,就链入fastbin中大小对应的单链表
2.fastbin单链表是个栈,LIFO,链表结点(被free的chunk)的插入用的是头插法,即紧邻表头插入,fd指针则往链尾方向指向下一个chunk(此处的“头尾”是以表头为头)
3.大体上插入就是chunk->fd = fastbinY[x] ->fd ; fastbinY[x]->fd = chunk ; 而对应的拆卸过程就是 fastbinY[x]->fd = fastbinY[x]->fd->fd(看懂意思就好不要太较真,大家可以自行去看libc源码)
4.fastbin的相关安全检查:首块double free检查,当一个chunk被free进fastbin前,会看看链表的第一个chunk是不是该chunk,如果是,说明double free了就报错;分配前size字段校验,从fastbin表中malloc出一个chunk时,拆卸前会检查要分配的这个chunk的size字段是不是真的属于它当前所在的fastbin表,如果size字段的值不是当前fastbin表的合法chunk大小值,则报错,其代码 ((((unsigned int)(sz)) >> (bitl == 8 ? 4 : 3)) – 2);根据size算得应在的表的下标,再和当前所在fastbin的下标对比
5.fastbin chunk头部字段特点:presize为0,size的inuse位恒为1(不被合并,符合当时设计常驻较小块以提高效率的初衷)
6.fastbin attack:用过一定手段篡改某堆块的fd指向一块目标内存(当然其对应size位置的值要合法),当我们malloc到此堆块后再malloc一次,自然就把目标内存分配到了,就可以对这块目标内存为所欲为了(可以是关键数据也可以是函数指针)
下面正式开始分析:
我们的主要思路就是首先泄露得到libc的基地址,然后通过fastbin attack篡改libc中某个函数指针,最终在调用的时候实现劫持并get shell
本文要点概括:
fastbin attack
__malloc_hook与size错位构造
绕过calloc泄露内存的通用思想(堆块溢出“受孕”、fastbin attack利用、远交近攻“隔山打牛”)
边缘效应与耦合缓解(unsorted_bin中chunk再分配、清空bin环境)
libc依赖:
有关不同libc版本下的堆地址
随着堆的学习,最近一直保持着有关libc堆漏洞利用的文章的更新,之前以babynote为例讲了unsorted bin attack,这次以0ctf2018 babyheap为例讲解一下fastbin attack的东西。
堆的知识细节很庞大,每次pwn一个challenge都会收获很多东西。之前是复现的babynote那道题,但毕竟是参考了别人的exp自己心里还是没底,而这次的babyheap的exploit开发则是彻头彻尾自己完成的,过程和结果令人惊喜:自己写出的有效exp之后和网上的exp进行了对比,发现思路有比较大的出入,也就意味着学到了更多的东西。
题目链接
一、逆向分析与漏洞挖掘
本文来自无奈人生安全网
丢进IDA,main函数F5,如下(函数名我已进行手动重命名):
0x01、new_log()如下:
我们的堆块就是通过该函数分配,索引表的结构就是传统的堆题目结构,由exist字段、大小字段和用户区指针构成;值得注意的是此处使用的内存分配函数是calloc而不是malloc,calloc分配chunk时会对用户区数据进行置空,也就是说之前的fd和bk字段都会被置为0,这在进行内存泄露时会造成一定的难度;返回的chunk下标也是传统的exist字段遍历法,下标从0开始。
0x02、edit_log()如下:
可以看到,程序并没有对用户输入的Size长度进行检查,这就造成了任意长度输入,形成堆溢出漏洞;此外,输入没有尾补字符串结束符,有可能会造成内存泄露(该程序后经分析,内存泄露不利用此处缺陷) 无奈人生安全网
0x03、delet_log()如下:
可以看到,这段free函数写的是很安全的,首先对用户通过下标选择进行free的chunk在索引表层面做了存在性检查,如果exist字段为0说明已经free便不再继续执行free,这有利于防范double free;free成功后,相应的索引表的exist字段置空、堆指针置NULL也做到位了。总之该部分没有安全漏洞。
0x04、print_log()如下:
其中sub_130F():
这个读内容函数也是安全的,首先作了存在性检查,如果exist字段为0就不会去读,也就是说只能读new过的记录;并且读取用的是write而不是puts,write读的长度也是索引表中记录的长度(即当初new的时候输入的长度的多大就只能读多大 ) 内容来自无奈安全网
0x05、逆向分析小结:
该程序存在堆溢出漏洞,但是由于其他保护作的较好,在泄露内存阶段应该会遇到较大阻力;堆溢出漏洞可能带来Fastbin Attack的机会。
二、漏洞利用分析
在进行具体分析之前,我们先粗略讲一下fastbin attack的相关知识:
(详细讲解请参考ctf wiki上的教程)
1.fastbin是单链表,按chunk大小递增一共有好几个,用户free一个chunk以后,如果大小是属于fastbin的、又不与top chunk相邻,就链入fastbin中大小对应的单链表
2.fastbin单链表是个栈,LIFO,链表结点(被free的chunk)的插入用的是头插法,即紧邻表头插入,fd指针则往链尾方向指向下一个chunk(此处的“头尾”是以表头为头)
3.大体上插入就是chunk->fd = fastbinY[x] ->fd ; fastbinY[x]->fd = chunk ; 而对应的拆卸过程就是 fastbinY[x]->fd = fastbinY[x]->fd->fd(看懂意思就好不要太较真,大家可以自行去看libc源码)
4.fastbin的相关安全检查:首块double free检查,当一个chunk被free进fastbin前,会看看链表的第一个chunk是不是该chunk,如果是,说明double free了就报错;分配前size字段校验,从fastbin表中malloc出一个chunk时,拆卸前会检查要分配的这个chunk的size字段是不是真的属于它当前所在的fastbin表,如果size字段的值不是当前fastbin表的合法chunk大小值,则报错,其代码 ((((unsigned int)(sz)) >> (bitl == 8 ? 4 : 3)) – 2);根据size算得应在的表的下标,再和当前所在fastbin的下标对比
5.fastbin chunk头部字段特点:presize为0,size的inuse位恒为1(不被合并,符合当时设计常驻较小块以提高效率的初衷)
6.fastbin attack:用过一定手段篡改某堆块的fd指向一块目标内存(当然其对应size位置的值要合法),当我们malloc到此堆块后再malloc一次,自然就把目标内存分配到了,就可以对这块目标内存为所欲为了(可以是关键数据也可以是函数指针)
下面正式开始分析:
我们的主要思路就是首先泄露得到libc的基地址,然后通过fastbin attack篡改libc中某个函数指针,最终在调用的时候实现劫持并get shell
内容来自无奈安全网