linux堆上的内存可执行吗,pwn的艺术浅谈(二):linux堆相关

这是linux pwn系列的第二篇文章,前面一篇文章我们已经介绍了栈的基本结构和栈溢出的利用方式,堆漏洞的成因和利用方法与栈比起来更加复杂,为此,我们这篇文章以shellphish的how2heap为例,主要介绍linux堆的相关数据结构和堆漏洞的利用方式,供大家参考。

0.前置知识

0.0 编译+patch方法

how2heap源码地址https://github.com/shellphish/how2heap,为了方便调试编译时使用gcc -g -fno-pie xx.c –o xx。这里先介绍一种linux下patch文件加载指定版本libc的方法,patchelf –set-interpreter 设置elf启动时使用指定ld.so(elf文件在启动时ld.so查找并加载程序所需的动态链接对象,加载完毕后启动程序,不同libc版本需要不同的加载器,不同版本libc和加载器下载地址https://github.com/5N1p3R0010/libc-ld.so),然后patchelf –set-rpath :/设置elf启动时加载指定libc。编译+patch示例

41b796d4f08407d37f113de2b0b18aef.png

0.1 linux堆管理简图及源码地址

6465547c035d172e153e2ae6e7775298.png

0.2 linux堆的数据结构

0.2.1堆块数据结构

首先介绍下linux下堆的基本数据结构。

ac1b81eeee6e31415e86a6e5bdcdc989.png

各字段含义如下:

0.mchunk_prev_size。当当前堆物理相邻的前一个堆为空闲状态时mchunk_prev_size记录前一个空闲堆的大小,当当前堆物理相邻的前一个堆为占用状态时mchunk_prev_size可用于存储前一个堆的数据。

1.mchunk_size,记录当前堆包含堆头的大小,堆的大小在申请时会进行对齐,对齐后堆的大小为2*size_t的整数倍,size_t为机器字长。mchunk_size的低三比特位对堆的大小没有影响,ptmalloc用它来记录当前堆的状态,三个比特位从高到低依次:

NON_MAIN_ARENA,记录当前堆是否不属于主线程,1 表示不属于,0 表示属于。

IS_MAPPED,记录当前堆是否是由 mmap 分配的。

PREV_INUSE,记录前一个堆是否被分配。

2.fd、bk,堆处于分配状态时,堆结构体偏移fd的位置存储数据;堆处于空闲状态时,fd、bk分别记录物理相邻的前一空闲堆、物理相邻的后一空闲堆,即用于对应空闲链表的管理

3.fd_nextsize、bk_nextsize,large chunk处于空闲状态时使用,分别用于记录前一个与当前堆大小不同的第一个空闲堆、后一个与当前堆大小不同的第一个空闲堆

0.2.2 空闲链表

理解ptmalloc堆漏洞利用的另一个比较重要的结构体是bin,为了节省内存分配开销,用户释放掉的内存并不会马上返还给系统,而是保存在相应的空闲链表中以便后续分配使用。Ptmalloc使用的空闲链表bin有四种,fastbin、samllbin、largebin、unsortedbin ,一个好的内存分配器应该是内存碎片少、且能在较低算法复杂度和较少内存分配次数的情况下满足用户使用内存(申请和释放)的需求,四种bin的实现就体现了这种思想。

3f67a9d7eeab6a77110d2415c1ef0cfe.png

为了减少内存碎片,ptmalloc在释放当前堆cur_chunk时会检测cur_chunk的prev_inuse位(标识物理相邻前一个堆(物理低地址)是否处于空闲状态)和cur_chunk的物理相邻下一个堆是否是top_chunk、物理相邻下一个堆的prev_inuse位。若cur_chunk的prev_inuse位为0则合并后向堆并将后向堆的地址作为新的合并后的堆的起始地址;若cur_chunk的物理相邻下一个堆的prev_inuse位为0则进行前向合并并将cur_chunk的地址作为新的合并后的堆的起始地址。若待释放的cur_chunk的物理相邻下一个堆为top_chunk则将cur_chunk和top_chunk合并,并将cur_chunk的地址作为新的top_chunk起点。

8d77901dcc0a185763cc9b52c0be67a9.png

Ptmalloc堆的一些参数

0) fastbin

fastbin是保存一些较小堆(32位系统默认不超过64字节,64位系统默认不超过128字节)的单链表结构。由于fastbin中相同index链接的都是相同大小的堆,ptmalloc认为不同位置的相同大小的堆没有区别,因此fastbin使用lifo的方法实现,即新释放的堆被链接到fastbin的头部,从fastbin中申请堆也是从头部取,这样就省去了一次遍历单链表的过程。fastbin的内存分配策略是exact fit,即只释放fastbin中跟申请内存大小恰好相等的堆。

1) smallbin

smallbin中包含62个循环双向链表,链表中chunk的大小与index的关系是2* size_t* index。由于smallbin是循环双向链表,所以它的实现方法是fifo;smallbin的内存分配策略是exact fit。

3176438dc5474dd89265b7e22037ff40.png

从实现中可以看出smallbin链接的chunk中包含一部分fastbin大小的堆,fastbin范围的堆是有可能被链入其他链表的。当用户申请smallbin大小的堆而smallbin又没有初始化或者申请大于smallbin最大大小的堆时,fastbin中的堆根据prev_inuse位进行合并后会进入如上unsortedbin的处理流程,符合smallbin或largebin范围的堆会被链入相应的链表。

2) largebin

largebin包含63个循环双向链表,每个链表链接的都是一定范围大小的堆,链表中堆的大小按从大到小排序,堆结构体中的fd_nextsize和bk_nextsize字段标识链表中相邻largechunk的大小,即fd_nextsize标识比它小的堆块、bk_nextsize标识比它大的堆块。

对于相同大小的堆,释放的堆插入到bin头部,通过fd、bk与其他的堆链接形成循环双向链表。

Largebin的分配策略是best fit,即最终取出的堆是符合申请内存的最小堆(记为chunk)。若取出的chunk比申请内存大至少minsize,则分割chunk并取合适大小的剩余堆做为last remainder;若取出的chunk比申请内存不大于minsize,则不分割chunk直接返回做为用户申请内存块。

3) unsortedbin

unsortedbin可以视为空闲chunk回归其所属bin之前的缓冲区,分配策略是exact fit。可能会被链入unsortedbin的堆块是申请largebin大小堆块切割后的last remainder;释放不属于fastbin大小且不与topchunk紧邻的堆块时会被先链入unsortedbin;在特定情况下将fastbin内的堆合并后会进入unsortedbin的处理流程(特定情况为申请fastbin范围堆fastbin为空;申请非fastbin范围smallbin的堆但smallbin未初始化;申请largechunk)

1.how2heap调试

1.0 First_fit

这个程序阐释了glibc分配内存的一个策略:first fit,即从空闲表中取出的堆是第一个满足申请内存大小的堆(fastbin、smallbin exact fit,largebin best fit)

c08b0cc3730215550208efe2dd24d38a.png

Shellphish给出的例子中先申请了0×512和0×256大小的两个堆,然后释放掉0×512大小的堆(申请0×256大小的堆的作用是避免释放不是mmap分配的堆a的时候合并到topchunk),实例中再次申请0×500大小的堆由于largebin的best fit分配策略glibc会分割堆后返回堆a,即堆c等价于堆a,这时我们输出堆a的内容即输出修改后的堆c的内容。

glibc的first fit分配策略可用于use after free(uaf,释放后重用)的利用,即修改新分配堆的内容等价于修改被释放的堆,uaf一般是由于释放堆后指针未置零造成的,不过在uaf的利用过程中我们一般使新分配的堆的大小等于被释放的堆的大小。

1.1 fastbin_dup

fastbin下doublefree的一个示例(未加tcache机制)。

f7da6eab571f6cd6fe4a22981f9be2ad.png

Shellphish给出的例子中先申请了3个0×8大小的堆(同样地申请c的原因是避免合并到topchunk),然后释放a(此时再次释放a构成doublefree双重释放,但是由于glibc在释放fastbin大小的堆时检查且仅检查fastbin头部的堆和要释放的堆是否相等,若相等则报错),为了绕过glibc在释放堆时对bin头结点的检查,我们free(b),此时fastbin如下(b=0×602020,a=0×602000;由于fastbin是单链表且LIFO,后释放的b被插入到链表头)

b0c1ce6cf484fa441770b0ecdf101574.png

然后我们再次free(a),由于此时bin头结点指向b,所以对头结点的检查被绕过,free(a)之后

909cca6814f8990d16a5234b30686769.png

可以看到此时fastbin中有两个a,如果此时我们申请三个0×8大小的堆,则依次从fastbin头部取得到a、b、a三个堆。

1.2 fastbin_dup_into_stack

fastbin下doublefree的利用示例(未开启tcache机制)。主要思路是在doublefree时我们有一次修改一个存在于fastbin链表的堆的机会,然后通过伪造堆的内容可以使得fastbin链入伪造的堆,再次申请内存可以得到伪造地址处的堆。

0c07229cb8a0082a09e239359484613e.png

示例中先申请了3个0×8大小的堆,然后通过free(a)、free(b)、free(a)构成一次doublefree(原理同fastbin_dup),此时fastbin的连接状态是a->b->a。再次申请两个0×8大小的堆,由于fastbin的lifo,此时fastbin中只剩a,且此时堆a存在于fastbin和用户申请的堆中,即我们可以控制一个存在于fastbin的堆的内容。容易想到的一种利用方式是伪造fastbin链表的内容,进而达到在伪造地址处申请堆的效果。

示例中在栈中伪造了一个0×20大小的堆(伪造堆头如下图选中部分,其中a=0×405000,&stack_var=0x00007fffffffdfb0),此时堆a的fd指向&stack_var,即fastbin:a->stack_var,此时第二次申请不超过0×18大小的堆(64位系统,跟申请堆时字节对齐有关,返回的堆的大小会被转化成满足条件的最小2*size_sz的倍数,最大0×10+8,8字节可占用下一个堆的prev_size)即可返回栈地址处的伪造堆。

586af5b4b896d3c49707f2bc06d60b46.png

1.3 fastbin_dup_consolidate

fastbin attack构成doublefree的一个示例。原理是利用申请一次largebin大小的堆会将fastbin的堆进行合并进入unsortedbin的处理流程,此时再次free fastbin中的堆会绕过free时对fastbin链表头节点的检查进而构成一次doublefree。

5ff0388b087726d06e9bbb7552180d5e.png

从下图free的流程中我们可以看出free时只会检查释放fastbin大小的堆时被释放的堆是否和fastbin的头结点是否一致,而在申请0×400的largechunk时,fastbin链表非空,fastbin中的堆会进行合并并且进入unsortedbin的处理流程,在unsortedbin的处理流程中符合fastbin大小的堆会被放入smallbin,这样就绕过了free时对fastbin头结点的检查,从而可以构成一次对fastbin大小的堆的doublefree。

a4962b7d98b0e253c7d7a86d2f858ffc.png

1.4 unsafe_unlink

堆可以溢出到下一个堆的size域且存在一个指向堆的指针时堆溢出的一种利用方式。

3dd772aad0ff5ec978d65ebc0b6e57a2.png

Unsafe unlink利用的前提是可以溢出到下一个堆的size域,利用的大致思路是在chunk0构造fakechunk且fakechunk可以绕过unlink双向链表断链的检查,修改chunk1的pre_size使之等于fakechunk的大小,修改chunk1中size域的prev inuse位为0以便free(chunk1)时检查前后向堆是否空闲时(这里是后向堆,即物理低地址)触发unlink双向链表断链构成一次任意地址写。下面看一下unlink的具体细节和原理。

示例中首先申请了两个0×80大小的堆chunk0和chunk1(非fastbin大小,因为fastbin大小的堆为了避免合并pre_inuse总是为1),然后在chunk0中构造fake_chunk

4cbcdd09c9ea7138726030f8d7d8d78e.png

需要注意的是,我们构造的fake chunk的起点是chunk0的数据部分即fd,fake chunk的prev size和size域正常赋值即可(最新的libc加入了cur_chunk’size=next_chunk’s prev_size),fake chunk中关键的部分是fake data,这一部分要绕过unlink双向链表断链的检查,即fd->bk=p&&bk->fd=p

708e926605ff6466d6a8be5c913c400a.png

chunk的结构体如下

6ca08ee6c41157b9173983a8e8101969.png

所以由结构体的寻址方式可得

(fd->bk=fd+3* size_t)=p

(bk->fd=bk+2* size_t)=p

所以可得

fd=p-3* size_t

bk=p-2* size_t

即fakechunk中fd和bk域如上构造即可绕过unlink双向链表的断链检查。

构造完fakechunk还需要修改下chunk1的prevsize和size的数据,

首先是prevsize要修改成fakechunk的大小(包含堆头,原因是glibc寻找下一个堆的宏如下,即将当前堆偏移size的数据视为下一个堆)

0ed83bcec04aa892fa14c30d90b84d47.png

chunk1 size部分的inuse位要置0,即标识物理相邻低地址堆为空闲状态(这也是unlink无法使用fastbin大小的堆的原因,fastbin大小的堆为了减少堆合并的次数inuse位总是置1)

最后构造的fakechunk+chunk1部分数据如下,chunk0堆头0×405000,fakechunk堆头0×405010,chunk1堆头0×405090,图中选中部分为fakechunk

60e6b87ae0b9e9b9ae557130fcb3b5e1.png

其中fakechunk的fd要使用指向堆节点的指针(如指向该节点的全局变量,非堆地址)的原因是unlink源码中传入的第二个参数是struct malloc_chunk * p。下面分析下unsafeunlink是如何导致任意地址写的。阅读源码可以发现smallbin范围内非fastbin范围的堆在unlink时只检查了双向链表的完整性,然后执行了双向链表摘除节点的操作。

d5ef08fa43e407f2bb37494d1f2f509e.png

断链的过程

fd->bk=bk 即(fd->bk=p)=(bk=p-2* size_t)

bk->fd=fd 即(bk->fd=p)=(fd=p-3* size_t)

最终相当于

p=p-3* size_t

即获得了两个相等的指针(struct malloc_chunk * p),试想如果此时我们可以修改一个指针指向的地址同时可以修改另一个指针指向的内容不就可以构成一次任意地址写了吗?巧的是(;p)我们恰好可以达到这样的效果。

此时我们修改fake_chunk[3]为要写的地址,修改fake_chunk[0]为要写的地址的内容即可。原因是fake_chunk[3]-3*size_t=fake_chunk,这里相当于给fake_chunk指向一个新的地址;fake_chunk[0]访问的是&fake_chunk[0]地址处的值,即上一步修改的地址处的内容。这样就构成了一次任意地址写^.^

fc68db5743b02ef413bbd62bdbd0089e.png

1.5 house_of_spirit

利用fastbin范围的堆释放时粗糙的检查可以在任意地址处伪造fastbin范围fakechunk进而返回fakechunk的一种利用方式。思路是在指定地址处伪造fastbin范围的fakechunk,释放掉伪造的fakechunk,再次申请释放掉的fakechunk大小的堆即可得到fakechunk。

a6c254fcca296813a304de2918b48720.png

其中fastbin范围的堆释放时的检查如下图所示,

ecf2ff9550eb41e9fd13907d4807676c.png

我们构造的fakechunk只需要绕过free时的检查即可:

0.2*size_sz

1.伪造的fakechunk不能是fastbin的头结点,即不能直接构成doublefree

利用house of spirit可以得到fakechunk处的堆,同时如果我们有fakechunk处写的权限利用fastbinattack即可劫持控制流。

1.6 poison_null_byte

由于glibc在返回用户申请的堆时不恰当的更新堆的presize域和错误的计算nextchunk的位置可以导致一次堆重叠。

方法是先申请堆然后释放掉中间位置的一个堆bchunk(假设堆的大小都如图所示),假设存在一个off by null的漏洞,由于前一个堆是占用状态时prevsize域用来存储前一个堆的数据,这样我们可以从achunk溢出到bchunk的size域最低位将其置0。

此时申请一个0×100大小的堆会返回释放掉的bchunk位置的堆。原因是在申请一个smallbin且非fastbin范围的堆时会检查smallbin是否为空,本例中smallbin为空则执行smallbin的初始化过程,即将可能的fastbin中的堆进行合并进入unsortedbin的处理流程,申请的堆的大小是smallbin范围,此时会取largebin头结点的一个堆进行切割返回(同样地为了减少内存碎片,largebin的堆从大到小排序)。这里largebin中只含一个0×200大小的堆,则直接对其进行切割然后返回给用户。

e097eff2cebc3352ae5adf10e2f2085b.png

然后再次申请一个0×80大小的堆。原因是0×100+0×80+两个堆头=0×200使之结束的位置正好落于cchunk

这时free(b1)、free(c)释放掉两个堆,由于nextchunk即cchunk的preinuse为0会触发前向合并(向物理高地址)过程。原因是fake了一个cchunk的presize,系统修改的是我们的fake presize,即下图的0xf0,系统依然认为bchunk的位置有一个0×210的fakechunk。

922faf7ef9ebb8fc547acffa78023699.png

此时再次申请一个0×300大小的堆,由于合并后bchunk和cchunk的大小为0×300,系统会返回合并后的bchunk。又由于此时b2chunk没有被释放处于占用态,b2chunk位于合并的bchunk内,此时构成一次堆重叠。

1.7 house_of_lore

利用伪造smallbin链表来最终达到一次任意地址分配内存的效果。前提是可以在要分配的地址处伪造堆(修改结构体中fd、bk的指向),且可以修改victim堆(被释放的smallbin堆)的bk指针。

15221c415177a1d3979e54e30e34cc16.png

方法是在要分配的内存地址(如栈地址)处构造一个fake smallbin chunk链,使之如下图所示。

0668e9196d55f3948b3bc5db3df9bd88.png

然后申请一个堆防止释放victim的时候合并到topchunk,释放掉victim,此例中victim会进入fastbin链表。

再次申请一个largechunk,触发fastbin的合并过程并使fastbin的堆进入unsortedbin的处理流程,victim处于smallbin的范围最终被链入smallbin头结点。而由于我们事先构造了如上的fake smallbin链,此时smallbin的链接情况是smallbin:victim->stack_buf1->stack_buf2。

由于smallbin的exact fit和fifo策略,此时申请一个victim大小的堆会直接返回bin结点bk指向的victim(bin的结构体是mchunkptr*),然后断链并修改bin的bk指针指向victim的bk节点即stack_buf1。glibc取smallbin的chunk源码如下。

70bb05f7607295282babb89cc9d8cf24.png

此时stack_buf1的结构如下(其中0x7fffffffdfb0=stack_buf1,0x7ffff7dd4b98=smallbin,0x7fffffffdf90=stack_buf2),即此时smallbin:stack_buf1->stack_buf2

b3fc3fe09750f889228b3fe6ecc366ff.png

这样此时再申请一个victim大小的堆直接取smallbin的bk指向的stack_buf1即得到相应地址处的堆,达到了任意地址分配内存的效果。

1.8 overlapping_chunks

通过修改一个位于空闲链表的堆的size域可以构成一次堆重叠

79f4f65bd1a18d8ee9c260b63a952780.png

过程如上。修改位于bin的p2的size域,修改后p2结构如下(p2=0×405110,选中部分为p2 data部分)

8d912a074867ad93e62c0dbd4357090c.png

此时申请一个修改后的p2 size的堆会得到从p2位置起始的fake size大小的堆p4,如下图

1f92ba04b6651e1ab0e2b0fb8f2f15e9.png

1.9 overlapping_chunks_2

通过堆溢出修改下一个占用态堆的size域构成一次堆重叠

4e68a7296b24803420412c243d061f7b.png

shellphish给出的示例中先free掉p4(我个人感觉这一步是没有必要的,shellphish可能是出于演示的目的考虑?因为稍后可以看到我们可以观察到p5的prevsize在free(p2)后会发生变化,如果有小伙伴看到这里可以一起交流,snip3r[at]163.com)。free p4后p5的prevsize为3f0

2a9d523d32e5801777ff1a6ce978935b.png

然后修改p2的size域为p2+p3+标志位,释放掉。此时glibc会认为p2的size域的大小包围的堆是要被释放的,会错误的修改p5的prevsize值。free p2后p5的prevsize为bd0

8acd7561c1b7e46d7b3190d0ae2b634c.png

此时由于物理相邻的前向堆p4处于空闲态,fake p2会和p4合并链入largebin。然后申请2000大小的largechunk会将上述合并后的堆切割后返回p2起始的堆,从而构成一次堆重叠。

1.10 house_of_force

利用topchunk分配内存的特点可以通过一次溢出覆盖topchunk的size域得到一次任意地址分配内存的效果。

24f613a3c870b493054fd9f5d4030408.png

首先通过一次堆溢出覆盖topchunk的size域为一个超大的整数(如-1),避免申请内存时进入mmap流程。

然后申请一个evilsize大小的堆改变topchunk的位置。evilsize的计算如下,这么计算的原因是当bin都为空时会从topchunk处取堆

9d883ce2bc6b193c16f762f332e4ba1c.png

修改topchunk到目标地址后在申请一次堆即可对目标地址处的内存进行改写。

1.11 unsorted_bin_into_stack

通过修改位于unsortedbin的堆的size域和bk指针指向目标fakechunk,在目标地址构造fakechunk(构造size和bk指针。我们也可以不修改victim的size,malloc两次得到目标地址的fakechunk;原理都是构造fake unsortedbin链表)可以得到一次任意地址申请内存的机会。

84736b8f5b102d1eada4d097c806cd4d.png

其中如果要伪造victim的size的话要满足check 2*SIZE_SZ (> 16 on x64) && < av->system_mem

通过溢出修改位于unsortedbin的victim的size和bk,并构造fakechunk,最终构造出如下fake smallbin链表

cc204ee56a3d8b7edcd6b942b0ffe827.png

在下一次申请内存时glibc遍历unsortedbin找到exact fit的堆块并返回,最终可以得到目标地址处的伪造堆。

1.12 unsorted_bin_attack

通过伪造unsortbin链表进行unsortedbin attack泄露信息(libc基址)的一种方法。

8ac85a5b22bc6a14f1520ed8a6bf0cd4.png

方法是构造如下fake unsortedbin链表,

5128eefe9759d4581dbcb22a057eca78.png

这样在申请得到victim后会将victim断链,从而target_addr fake chunk的fd会指向相应的bin,进而可以泄露libc基址。(当然也可以泄露bk之类位置的其他信息,如果有的话;p)

1.13 large_bin_attack

利用malloc进行unsortedbin处理时插入largebin通过修改largebin链表上的堆的bk、bk_nextsize均可以得到任意地址写的机会。

aec5e864f6e79b2873feddff784eac9d.png

首先要申请如上图3个堆和相应的为了避免合并到topchunk的barrier(只申请barrier3应该就够用了,shellphish这么写可能是在之后复杂的申请释放中不在考虑合并到topchunk的情况),其中p1要保证是smallbin且非fastbin范围(且保证在后续申请堆时堆大小够用),p2、p3要保证是largebin范围。

(1)然后依次释放p1、p2,由于非fastbin范围的堆在释放后会首先链入unsortedbin,此时unsortedbin的情况是。(简单说就是unsortedbin:p2->p1,其中各个指针的指向如图)

ba49cc265b1e30f35c3f1e6baba7df01.png

(2)此时申请一个0×90大小的堆,从glibc的源码中可以看到遍历unsortedbin的过程是从bin头结点的bk指针开始遍历。这样取到的第一个堆是0×320大小的p1,p1满足0×90的申请,glibc会从p1中分割出0×90的大小,然后继续遍历unsortedbin直至遍历结束;此时得到链表的第二个堆0×400大小的p2,p2非smallbin范围且largebin为空,被链入largebin

1f61a2bb41fb01cee32ed17d1df841cf.png

此时unsortbin:(p1-0×90),largebin:p2.

(3)然后释放0×400大小的p3,p3非fastbin范围被链入unsortedbin头结点(fd指向p3)。

(4)此时利用溢出或其他手段修改largebin中的p2的bk、bk_nextsize(或、且)和size。可以看到p2修改前的size为0×411,shellphish把它修改成了0x3f1,这样做是因为largebin中链接的一定范围的堆是从大到小降序排列的,修改后0×400大小的p3被链入largebin时会被链入头结点。

在做好以上的准备工作后再次申请一个0×90大小的堆,同(2)过程依然由p2分割得到堆,由于p3>修改后的p2的size,p3被链入largebin头结点。链入的过程类似unlink,类似的我们得到了一次任意地址写的机会。

f3f7cd9605f766d11fa4a5a446db4ec4.png

1.14 house_of_einherjar

利用一次off by null修改下一个占用态chunk的prev_inuse位,同时修改下一个下一个占用态chunk的prev_size值,利用top chunk和后向合并(物理低地址)机制得到一次任意地址分配内存的机会。这种off by null利用的前提是可以在目标地址处(最终分配内存的地址处)构造fakechunk。

f727d5041aa4dcec7f9a53e1e7150ae1.png

利用的方法是在目标地址处构造fakechunk,由于稍后会看到fakechunk处会触发unink,为了绕过双向链表完整性的检测fd、和bk均可置为fakechunk。其中设置fakechunk的prev_size和size的值是可以但没必要的。

由于占用态的堆prev_size会用来存储前一个堆的数据,所以天然的prev_size域可以修改;当存在off by null时可以将下一个占用态堆的prev inuse置0。我们修改a的prev_size为fake_size,b的prev_inuse为0。这时我们释放掉b,由于b和topchunk紧邻,b会和topchunk合并;同时由于b的prev_inuse为0会触发后向合并(物理低地址),glibc寻找下一个空闲堆的方式是chunk_at_offset(p, -((long) prevsize)),即将当前位置偏移prev_size的位置视为nextchunk,这样(b+b.prev_size)得到下一个堆位于fakechunk,合并到topchunk并最终得到新的topchunk起点为fakechunk。此时再次申请堆从topchunk处取即可得到target处的fakechunk。

bd173f23675b82760bd69a18a374c690.png

这样通过反推target=b_chunk_header-fake_size得到fake_size=b_chunk_header-target。

2.总结

本文到这里就结束了,linux pwn基础知识的介绍到这里也就结束了,但是glibc还在不断更新,堆管理一些细节也在不断微调,一些新的提高性能的机制如tcache也开始应用于新版本的libc,关于不断更新的新版本libc的漏洞利用方式的探索还远远没有结束。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/382955.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

arm嵌入式linux应用实例开发pdf,零点起步——ARM嵌入式Linux应用开发入门一书的源代码...

代码片段和文件信息属性 大小 日期 时间 名称----------- --------- ---------- ----- ----文件 24064 2016-03-20 09:49 零点起步——ARM嵌入式Linux应用开发入门\习题答案 (1).doc文件 24064 2016-03-20 09:50 零点起步——ARM嵌入式Lin…

linux上p图工具,linux图片处理工具GraphicsMagick安装使用

安装依赖包&#xff1a;yum install libpng libjpeg freetype libpng-devel libjpeg-devel libtool-ltdl-devel libtool-ltdl官网下载GraphicsMagick包官网地址&#xff1a;http://www.graphicsmagick.org/解压编译安装&#xff1a;tar xf GraphicsMagick-1.3.25.tar.gz./confi…

manjaro linux下载软件,manjaro linux

manjaro linux下载。manjaro linux是基于Arch Linux开发的Linux操作系统&#xff01;对于裸服务器、虚拟机、IaaS 和 PaaS 方面都得到了加强&#xff0c;而且内置了强大的数据中心满足商业的各种要求&#xff0c;是强大的混合云平台和物理系统&#xff01;manjaro linux介绍man…

linux 安装qt 4.6软件,QT学习之一:Linux下安装QT之版本qt-4.6.3

在Linux中分别安装应用于不同平台的QT&#xff1a;PC&#xff1b;嵌入式X86&#xff1b;ARM。这三者PC版、嵌入式X86版和ARM版的区别主要体现在&#xff1a;当configure时分别加了不同的参数&#xff0c;具体区别是&#xff1a;PC平台&#xff1a;在linux中全安装qt&#xff0c…

linux kill命令使用方法,Linux初学者的killall命令(8个例子)

Linux初学者的killall命令(8个例子)我们已经讨论了kill命令 &#xff0c;如果你想在Linux中终止进程&#xff0c;你可以使用kill命令 。 但是&#xff0c;还有一个命令行实用程序可以用于相同的目的&#xff1a; killall 。 在本教程中&#xff0c;我们将使用一些易于理解的示例…

linux wait 信号丢失,wait函数族和SIGCHLD信号的关系

一、wait()和waitpid()函数的区别pid_t wait(int *status)进程一旦调用了wait&#xff0c;就立即阻塞自己&#xff0c;由wait自动分析是否当前进程的某个子进程已经退出&#xff0c;如果让它找到了这样一个已经变成僵尸的子进程&#xff0c; wait就会收集这个子进程的信息&…

linux socket接收不到16进制数据,C下通过socket收发十六进制数据解决办法

C下通过socket收发十六进制数据系统是在LINUX下&#xff0c;下位机发送十六进制数据过来 上位机怎么解析 把数据以十六进制的形式显示出来&#xff0c;发送十六进制又如何实现------解决方案--------------------socket不就是发16进制的么------解决方案--------------------那…

c语言 字符串 url,如何对URL字符串进行百分号编码

在和web服务进行交互时&#xff0c;我们经常需要对URL中的特定字符和传输的表单数据进行百分号编码。例如&#xff0c;’&’在百分号编码时会变成’%26’。搞清楚 URL中哪部分的哪些字符应该进行百分号编码了并不是件易事。最好的资料好像是RFC 3986和W3C HTML5。出于兴趣和…

击鼓传花击鼓次数相同c语言,JavaScript 实现击鼓传花游戏

大家小时候应该都玩过击鼓传花(Hot Potato)的游戏吧&#xff01;一群小孩围成一个圆圈&#xff0c;把花尽快的传给旁边的人。某一时刻传花停止&#xff0c;这时花在谁手里&#xff0c;谁就退出圆圈结束游戏。重复此过程&#xff0c;直到剩下最后一个孩子&#xff0c;即为胜者。…

c语言查找字符串au,几个C语言词汇不懂,望老鸟们相助(俺是新手哦)

几个C语言词汇 auto break case char const continue default do double else enum extern float for goto if int long registerreturn short signed几个C语言词汇 auto break case char const continue default do double else enum extern float for goto if int long regis…

c语言中 %.2s,C2S是什么意思

1. The testing result indicates that TiO_2 has mineralized effect on C_2S, at the same time flux effect on reducing low general melting point of CaO-SiO_2 system and yielding much liquid phase, TiO_2 has definite stabilized effect on β-C_2S.结果随着TiO2掺…

前端的c语言面试题,前端工程师面试题汇总(选择题)

前端工程师面试题汇总(选择题)时间&#xff1a;2017-12-05 来源&#xff1a;前端工程师面试题推荐作为一名前端工程师&#xff0c;我们必不可少的就是参加面试&#xff0c;面试过程中会遇到各类奇葩的问题&#xff0c;今天小编为大家汇总了一些相关的问题&#xff0c;希望可…

用英文单词模拟数字计算c语言,C语言程序设计用英文单词模拟数学计算

匿名用户1级2010-05-09 回答最后输出是用的是阿拉伯数字&#xff0c;这个你再改改吧&#xff0c; 小问题了。。。。#include #include #include #include #include int carry 0;int parse_int(const char *s, int len){char tens[10], units[10];memset(tens, 0, sizeof(tens)…

c语言猜数字游戏新建,C语言编程 如何构建一个简单的猜数字小游戏

#include//生成随机函数起点时用到time.hint main(){int number1 0, choice 0, number2 0;printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");//界面设置printf("$$$$$ 欢 迎 来 到 $$$$$\n");printf("$$$$$ 猜 数 字 …

c语言循环拆分成和,C语言拆分循环链表程序

创建一个循环链表&#xff0c;并将这个循环链表拆分成为两个循环链表的示例程序&#xff0c;将以下代码保存到一个源文件中&#xff1a;split_circular_linked_list.c&#xff0c; 如下所示 –#include #include struct node { int data; struct node *next; }; struct node *e…

pic单片机c语言读eeprom,PIC16F877单片机内部EEPROM读写实例

;PIC16F877单片机内部EEPROM读写实例****************************************************************************************; This is a program to test the function of reading&writting for EEPROM.; YouCANOBServe the value of register(30H--?) buy changin…

C语言运行gis空间叠加分析,GIS空间叠加分析与缓冲区分析.doc

《地理信息系统》报告专 业 资源环境与城乡规划管理 姓 名 成 绩班 级 学 号 日 期 2014/6/20目录TOC \o "1-2" \h \u 14469 一、题目 23290 二、设计目的27200 三、设计背景2四、设计内容27200 四、步骤与过程27200 五、专题地图 37521 四、总结分析 9题目佛山市顺德…

组件文件已损坏或android内部模块,android - Android Q更新后,模块化系统组件在托管配置文件中不可用 - 堆栈内存溢出...

在从工作配置文件配置的设备设置应用中将操作系统从Android 9升级到10后&#xff0c;请停止运行。java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.settings/com.android.settings.applications.InstalledAppDetailsTop}: java.lang.NullPoin…

android文本复制自定义剪切板,android 剪切板-文本复制、粘贴

1. 粘贴&#xff0d;文本保存到剪切板中ClipboardManager clipboardManager (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);//创建ClipData对象ClipData clipData ClipData.newPlainText("orderNo", txt);//添加ClipData对象到剪切板中…

android保持服务不休眠,Android开发保持屏幕常亮和CPU不休眠唤醒状态

安卓手机 APP 开发&#xff0c;有的时候需要屏幕长时间亮着&#xff0c;也就是不锁屏&#xff0c;这时CPU会一直处于不休眠唤醒状态。下面介绍两种方法。方法一&#xff1a;通过 PowerManager 实现。此种方法会在软件安装时用户可以看到屏幕选项。首先&#xff0c;在 AndroidMa…