澳门新葡8455手机版-澳门新葡8455最新网站

您的位置:澳门新葡8455手机版 > 新闻资讯 > chunk合并到当前chunk就称为向前合并,Linux堆溢出

chunk合并到当前chunk就称为向前合并,Linux堆溢出

2019-10-10 09:39

unlink是行使glibc malloc 的内部存款和储蓄器回收机制导致攻击的,大旨就在于当五个free的堆块在大要上相邻时,会将她们联合,并将原本free的堆块在原本的链表中解链,参预新的链表中,但诸如此比的联结是有标准化的,向前或向后统一。但那边的前和后都以指在情理内部存款和储蓄器中的岗位,并非fd和bk链表所指向的堆块。以当下的chunk为条件,将preivous free chunk合併到前段时间chunk称为向后联合,将前边的free chunk合并到眼下chunk就叫做向前合併。

Linux堆溢出漏洞使用之unlink,溢出疏漏unlink

Linux堆溢出疏漏使用之unlink

作者:走位@Ali聚安全

 

/* consolidate backward */ if (!prev_inuse { prevsize = p->prev_size; size += prevsize; p = chunk_at_offset(p, - prevsize)); unlink(p, bck, fwd); }#define chunk_at_offset ((mchunkptr)))

0 前言

事先大家深入摸底了glibc malloc的运营机制(文章链接请看文末▼),上边就让大家开始真的的堆溢出漏洞使用学习啊。说真的,写那类作品,作者是比较怂的,因为本身眼下转业的劳作跟漏洞发掘完全非亲非故,学习这一部分知识也纯粹是个人爱好,于周天无聊时打发下时间,以致本身最早的靶子也单独是能相当的慢看懂、复现种种漏洞使用POC而已…鉴于此,后续的篇章大概会由二种内容结合:1)各类有关小说的下结论,再提炼;2)有些好小说的翻译及实行。本文两个都有,首要仿照效法文献见这里。

unlink的概念如下:

 

#define unlink(P, BK, FD) {  FD = P->fd;  BK = P->bk;  if (__builtin_expect (FD->bk != P || BK->fd != P, 0))  malloc_printerr (check_action, "corrupted double-linked list", P);  else {  FD->bk = BK;  BK->fd = FD;  if (!in_smallbin_range (P->size)  && __builtin_expect (P->fd_nextsize != NULL, 0)) {  assert (P->fd_nextsize->bk_nextsize == P);  assert (P->bk_nextsize->fd_nextsize == P);  if (FD->fd_nextsize == NULL) {  if (P->fd_nextsize == P)  FD->fd_nextsize = FD->bk_nextsize = FD;  else {  FD->fd_nextsize = P->fd_nextsize;  FD->bk_nextsize = P->bk_nextsize;  P->fd_nextsize->bk_nextsize = FD;  P->bk_nextsize->fd_nextsize = FD;  }  } else {  P->fd_nextsize->bk_nextsize = P->bk_nextsize;  P->bk_nextsize->fd_nextsize = P->fd_nextsize;  }  }  } }

1 背景介绍

首先,存在破绽的前后相继如下:

图片 1

在代码[3]中留存多个堆溢出错误疏失:假诺客商输入的argv[1]的大大小小比first变量的666字节越来越大的话,那么输入的数目就有望覆盖掉下贰个chunk的chunk header——那足以变成放肆代码施行。而攻击的为主思路便是运用glibc malloc的unlink机制。

上述顺序的内部存储器图如下所示:

图片 2

里面有无数检查评定是事先未曾的,首先把单纯的unlink弄精通。

2 unlink本领原理

#define unlink{FD=P->fd;BK=P->bk;FD->bk=BK;BK->fd=FD;...}

2.1 基本知识介绍

unlink攻击技能正是使用”glibc malloc”的内部存款和储蓄器回收机制,将上海教室中的second chunk给unlink掉,何况,在unlink的经过中动用shellcode地址覆盖掉free函数(或任何函数也行)的GOT表项。那样当程序继续调用free函数的时候(如上边代码[5]),就转而实施大家的shellcode了。显著,核心正是精通glibc malloc的free机制。

 

在正规意况下,free的实践流程如下文所述:

PS: 鉴于篇幅,这里根本介绍非mmaped的chunks的回收机制,回看一下在怎样景况下行使mmap分配新的chunk,哪些状态下不用mmap?

比如涉及到free内部存款和储蓄器,那么就表示有新的chunk由allocated状态成为了free状态,此时glibc malloc就需求开展联合操作——向前以致(或)向后统一。这里所谓向前向后的概念如下:将previous free chunk合併到方今free chunk,叫做向后统一;将前边的free chunk合併到日前free chunk,叫做向前合併。

 

一、向后联合:

       相关代码如下:

图片 3

图片 4

首先检验前贰个chunk是不是为free,那足以经过检查评定当前free chunk的PREV_INUSE(P)比特位知晓。在本例中,当前chunk(first chunk)的前一个chunk是allocated的,因为在私下认可意况下,堆内部存储器中的首先个chunk总是被安装为allocated的,尽管它根本就不设有。

 

假定为free的话,那么就进展向后统一:

1)将前二个chunk占用的内部存款和储蓄器合併到当下chunk;

2)修改指向当前chunk的指针,改为指向前三个chunk。

3)使用unlink宏,将前三个free chunk从双向循环链表中移除(这里最佳温馨美术精晓,学过数据结构的应该都没难题)。

在本例中出于前叁个chunk是allocated的,所以并不会开展向后联合操作。

 

二、向前合併操作:

先是检验next chunk是或不是为free。那么怎么样检验呢?很简短,查询next chunk之后的chunk的PREV_INUSE (P)就能够。相关代码如下:

图片 5

 

整套操作与”向后统一“操作看似,再经过上述代码结合注释应该很轻巧通晓free chunk的迈入结合操作。在本例中当前chunk为first,它的下一个chunk为second,再下贰个chunk为top chunk,此时top chunk的 PREV_INUSE位是设置为1的(表示top chunk的前一个chunk,即second chunk,已经应用),由此first的下贰个chunk不会被“向前合併“掉。

   

介绍完向前、向后统一操作,上面就供给精晓合併后(或因为不知足合併条件而没统一)的chunk该怎么样进一步管理了。在glibc malloc中,会将统一后的chunk放到unsorted bin中(还记得unsorted bin的含义么?)。相关代码如下:

图片 6

图片 7

 

上述代码达成的整个过程轻松总结如下:将日前chunk插入到unsorted bin的率先个chunk(第1个chunk是链表的头结点,为空)与第2个chunk之间(真正含义上的首先个可用chunk);然后通过安装本身的size字段将前一个chunk标识为已接纳;再更改后多个chunk的prev_size字段,将其安装为当下chunk的size。

 

只顾:上一段中陈述的”前四个“与”后一个“chunk,是指的由chunk的prev_size与size字段隐式连接的chunk,即它们在内存中是一连、相邻的!并非经过chunk中的fd与bk字段组成的bin(双向链表)中的前一个与后叁个chunk,切记!。

 

在本例中,只是将first chunk增多到unsorted bin中。

 

unlink能够省略看作上面包车型客车代码部分,将链表中的P脱链,把此前P的下一个chunk与P的上一个chunk连接,使P离开链表。首先检查实验前一个chunk是不是为free状态,通过检查测试当前free chunk的PREV_INUSE标识位,即使为0代表free状态,但内部存款和储蓄器中第八个申请的chunk的前二个chunk日常都被认为在选取中,所以不会发生向后统一。若是或不是内部存款和储蓄器中的第三个chunk且它的前叁个chunk标志为free状态时,产生向后统一:率先修改chunk的size位大小为四个chunk size之和再将指针移动到前贰个chunk处最终调用unlink将前贰个chunk从它所在的链表中移除。

2.2 初阶攻击

当今大家再来深入分析假诺贰个攻击者在代码[3]中留意布局输入数据并通过strcpy覆盖了second chunk的chunk header后会爆发什么境况。

 

一经被遮住后的chunk header相关数据如下:

1) prev_size =三个偶数,那样其PREV_INUSE位正是0了,即意味着前八个chunk为free。

2) size = -4

3) fd = free函数的got表地址address – 12;(后文统一简称为“free addr – 12”)

4) bk = shellcode的地址

 

那正是说当程序在[4]处调用free(first)后会产生哪些吧?大家一步一步分析。

一、向后联合

       鉴于first的前贰个chunk非free的,所以不会产生向后统一操作。

二、向前合并

先剖断后一个chunk是还是不是为free,前文已经介绍过,glibc malloc通过如下代码判定:

图片 8

PS:在本例中next chunk即second chunk,为了便于明白后文统一用next chunk。

 

从地点代码能够领略,它是透过将nextchunk + nextsize总结获得针对性下下一个chunk的指针,然后剖断下下个chunk的size的PREV_INUSE标志位。在本例中,此时nextsize被大家设置为了-4,那样glibc malloc就能够将next chunk的prev_size字段看做是next-next chunk的size字段,而我们已经将next chunk的prev_size字段设置为了多个偶数,因而此时因而inuse_bit_at_offset宏得到到的nextinuse为0,即next chunk为free!既然next chunk为free,那么就需求展开向前合併,所以就能够调用unlink(nextchunk, bck, fwd);函数。真正的要紧就是其一unlink函数!

 

在前文2.1节中早已介绍过unlink函数的落到实处,这里为了有帮衬表达攻击思路和进度,再详细剖析一次,unlink代码如下:

图片 9

此时P = nextchunk, BK = bck, FD = fwd。

1)首先FD = nextchunk->fd = free地址– 12;

2)然后BK = nextchunk->bk = shellcode开头地址;

3)再将BK赋值给FD->bk,即(free地址– 12)->bk = shellcode起先地址;

4)最终将FD赋值给BK->fd,即(shellcode初叶地址)->fd = free地址– 12。

前边两步辛亏领会,首若是末端2步相比吸引。我们作图明白:

图片 10

 

结合上海教室就很好精晓第3,4步了。留意的相爱的人曾经注意到,free addr -12和shellcode addr对应的prev_size等字段是用虚线标志的,为啥呢?因为实际它们对应的内部存款和储蓄器并非chunk header,只是在我们的攻击中要求让glibc malloc在拓宽unlink操作的时候将它们强制看作malloc_chunk结构体。那样就很好驾驭为何要用free addr – 12调换next chunk的fd了,因为(free addr -12)->bk刚好正是free addr,也等于说第3步操作的结果就是将free addr处的多少替换为shellcode的起首地址。

 

鉴于已经将free addr处的数目替换为了shellcode的开场所址,所以当程序在代码[5]处再一次实行free的时候,就能转而实行shellcode了。

 

由来,整个unlink攻击的准则已经介绍完毕,剩下的行事便是依据上述原理,编写shellcode了。只然则这里须求留意一点,glibc malloc在unlink的长河中会将shellcode + 8地方的4字节数据替换为free addr – 12,所以大家编辑的shellcode应该跳过前边的12字节。

 

if (nextchunk != av->top) { /* get and clear inuse bit */ nextinuse = inuse_bit_at_offset(nextchunk, nextsize); /* consolidate forward */ if (!nextinuse) { unlink(nextchunk, bck, fwd); size += nextsize; } else clear_inuse_bit_at_offset(nextchunk, 0);#define clear_inuse_bit_at_offset (((mchunkptr)))->size &= ~(PREV_INUSE))

3 对抗技巧

此时此刻,上述unlink能力早就过时了(但不意味全部的unlink才具都失效,实际情况见后文),因为glibc malloc对相应的平安体制举行了进步,具体来讲,正是增添了之类几条安全检验机制。

 

迈进合併不纠正P的指针,只增添size大小。在联合后glbc malloc会将联合后新的chunk到场unsorted bin中,出席第多少个可用的chunk在此之前,更动本身的size字段将前三个chunk标识为已用,再将后七个chunk的previous size改为当下chunk的大大小小。

3.1 Double Free检测

该机制不容许释放三个早已处于free状态的chunk。由此,当攻击者将second chunk的size设置为-4的时候,就代表该size的PREV_INUSE位为0,也即是说second chunk此前的first chunk(大家要求free的chunk)已经处在free状态,那么此时再free(first)的话,就能够报出double free错误。相关代码如下:

图片 11

 

设若四个相邻的chunk在率先个chunk写入数据时产生了溢出,覆盖了后四个chunk的数额为独特含义的多少,那么就有极大希望使程序执行特定的代码,进而决定程序流程到达相应的目标。当大家因而溢出改写多少如下时会满意非常的基准:

3.2 next size非法检验

该机制检查评定next size是还是不是在8到当下arena的任何系统内部存款和储蓄器大小之间。由此当检查实验到next size为-4的时候,就能够报出invalid next size错误。相关代码如下:

图片 12

 

previous size => 一个偶数size =>-4fd => free@got addr-12bk =>shellcode addr

3.3 双链表冲突检查测试

该机制会在奉行unlink操作的时等候检查查评定链表中前一个chunk的fd与后贰个chunk的bk是不是都对准当前急需unlink的chunk。那样攻击者就无法交替second chunk的fd与fd了。相关代码如下:

图片 13

 

当覆盖数据后,因为改写的是下四个chunk的数码,当free当前先是个chunk时,先考虑会不会向后统一,那时因为第一个chunk 的前两个总是占用的,即便她有史以来海市蜃楼,所以当第向后chunk被free后不会时有发生向后联合,再判定向前合併,先是去检验下贰个chunk是或不是处于free状态亟待通过next->next chunk的size标记位检查实验,当大家设置next chunk的size为-4时,next chunk的previous size字段会被视作next->next chunk的size字段,此时又因为next chunk的previous size 字段为偶数,即next->next chunk->size为偶数,P标志位为0,表示next chunk为free状态,知足向后统一的口径,触发unlink。当满意unlink的基准时,内部存储器的变动使用八个有的时候变量FD、BK将后一个chunk从原本的free链表中解链

4 另一种unlink攻击掌艺

透过上述3层安全检查实验,是或不是意味全部unlink技艺都失效了啊?答案是或不是认的,因为进行漏洞攻击的人脑洞永恒比天天津大学学!以前刚刚见到一篇好文(生硬推荐),主讲在Android4.4上使用unlink机制落到实处堆溢出攻击。家谕户晓,Android内核基于linux,且其堆内部存款和储蓄器管理也是运用的glibc malloc,即便在局地细节上有个别许差别,但基本原理类似。该文介绍的攻击方式就成功绕过了上述三层检查评定。

 

首先FD=P->fd;BK=P->bk;这时FD的值为free@got-12,BK为shellcode地址再一次FD->bk=BK;BK->fd=FD;因为这时候FD,BK是挟持被看成七个chunk的,所以它的bk与fd相对的地方与几个寻常chunk是一模二样的,FD->bk与FD的地址相差12,而FD为free@got-12,那么FD->bk的职分正是free@got的职位,被赋值了BK=shellcode,那时当施行free函数时转而实施shellcode,完结了经过unlink修改free@got表的指标。

5 总结

本文详细介绍了unlink攻击本事的核心原理,固然上述介绍的unlink漏洞使用工夫早就失效,而任何的unlink本领难度也越加大,可是我们照旧有必要认真读书,因为它一面可以更上一层楼加重大家对glibc malloc的堆栈管理机制的知道,另一方面也为承袭的种种堆溢出攻击本领提供了思路。

从上文的剖释可以见见,unlink首要依旧采取的glibc malloc中隐式链表机制,通过覆盖相邻chunk的数目完结攻击,那么大家能或不能够在呈现链表中也找到攻击点呢?请关注下一篇小说:基于fastbin的堆溢出漏洞使用介绍。

 

将贰个大的chunk伪产生五个极小的堆块,在填充数据时经过第三个假冒堆块的size标识位P使前三个伪chunk处于free状态,那时因为这几个大的堆块本来就处于inuse状态,所以第1个伪堆块的下壹个堆块size位P=1,表示前二个chunk处于选拔状态,当free前面的伪堆块时会将前贰个伪堆unlink,

Linux技艺深入分析体系作品

Linux堆内部存储器管理深入分析(上)

Linux堆内部存储器管理深切深入分析(下)

 

我:走位@Ali聚安全,越来越多安全技巧小说,请访谈Ali聚平安博客

Linux堆溢出错误疏失使用之unlink 我:走位@Ali聚安全 0 前言 之前大家深刻领会了glibc malloc的运转...

图片 14伪堆构造

图中革命边框为三个大的申请的堆块,暗紫为率先个伪堆块,黄色为第二个伪堆块,通过数据填充构造上海教室的内部存储器布局,因为ptr为申请内部存款和储蓄器时重临的指针,所以ptr一发端就指向fake_prev,要绕过unsafe_unlink,将第3个伪堆块的fd=ptr-0x18,bk=ptr-0x10,那样当检查FD->bk=p的时候成功绕过了检验,满意了unlink能够完结延续的选用。

本文由澳门新葡8455手机版发布于新闻资讯,转载请注明出处:chunk合并到当前chunk就称为向前合并,Linux堆溢出

关键词: