实验目的
掌握堆漏洞中fastbinattack的原理和重复释放漏洞的利用方法.
实验条件
- 操作系统:Linux
- 语言环境:python
- 调试器:gdb、IDA Pro
实验要求
- 对被攻击程序的漏洞利用过程进行详细分析;
- 详细列出重复释放漏洞利用过程中 ,
fastbin在4次malloc过程中的变化情况,以及system()函数地址被写入和system(/bin/sh)调用被调用的过程;
四、程序分析
通过IDA对程序进行反编译,发现程序提供了四种操作new、write、delete、exit,对它们分别进行分析;

new
用于malloc分配堆块,但限制最多只能分配九个堆块,并且限制了分配的大小小于96大于0,并且将malloc(v2)后的指针赋值给ptr,由于ptr数组是未被初始化的,因此ptr位于bss段;

write
用于在ptr[i]指向的位置直接进行read写操作,如果可以控制prt[i]的内容,就可以完成任意写;

delete
函数中使用free释放空间后,ptr指针没有清零,造成DouobleFree漏洞;

system
程序存在system函数,位于0x4006E0处,可以通过system函数实现/bin/sh;

实验步骤
程序限制了malloc的大小,使得new只能申请到fastbin,所以利用fastbin attack来构造特定的chunk单链表链。
程序可以申请的大小为96字节(0x60,再加上size与prev_size各8字节,一共是0x70, 在fastbin中会位于0x70的位置。
分析四次malloc过程中,fastbin的变化情况:
第一次malloc
首先进行第一次double free ,查看fastbin中的指针变化,步骤为
按照顺序申请chunk0、chunk1;
按照顺序释放chunk0、chunk1、chunk0;
1
2
3
4
5New(p, 0x60) # 0
New(p, 0x60) # 1
Delete(p, 0)
Delete(p, 1)
Delete(p, 0)在申请chunk之前,fastbin如下:

申请两个chunk之后,将chunk分配到fastbin中,其中堆顶的位置为
0xb2c0e0;
当free
chunk0之后,chunk0被放进fastbin里面,地址为0xb2c000;
free
chunk1之后,chunk1被放进fastbin中,chunk1指向chunk0,fd表示了 下一个未被使用的chunk的地址,这时后free的chunk1成为了fastbin中的首个chunk;
再次执行free
chunk0时,由于fastbin在执行free的时候仅验证了链表指针头部的块,对于链表后面的块,并没有进行验证。所以再次freechunk0的时候,实际上是把chunk0又加到了链的开头;
第二次malloc
在double free之后,我们使得链表的形式为0xb2c000—▸0xb2c070◂—0xb2c000,再次malloc时,会从链表末尾取下一个块,直接分配给用户,所以malloc到的2号实际上是0xb2c000,对该块进行编辑时,编辑起始的位置是0xb2c0e0
1 | New(p, 0x60) # 2 |
在执行过write 2 之后,地址0xb2c070位置被改变了,变成了0x60208d。由于0xb2c000仍然被记录在链表中,所以fastbins中链表的最后一项也发生了改变;
修改了的fastbin链表,导致的是0x60208d这块被当做了fastbin的一个块,在分配的时候,申请的0x60大小实际上会分配0x70大小,而0x7f,也就是图中的0x60802d开始的第二个字节,恰好满足分配的条件,如果再往左或往右偏移,会出现不满足条件的情况;

接下来进行了三次malloc操作,每一次malloc操作都会从fastbin链表头取一个块进行分配;
1 | New(p, 0x60) # 3 |
取第一个块进行分配,分配
0xb2c070;
取第二个块进行分配,分配
0xb2c000;
第三次分配,把
0xb2c070写入ptr[5]中,fastbin只剩下了之前0x60208d这个地址里面的内容;
查看
ptr所在的地方,可以看到ptr[0]=ptr[2]=ptr[4]、ptr[1]=ptr[3],而ptr[5]是bss段上的一个地址;
第三次malloc
接下来需要进行任意写,更改got表里某一函数的地址为system,并写入参数/bin/sh;
1 | Write(p, 4, '/bin/sh\x00') |

在向5写入payload之后,也就是向bss段上的ptr写入payload,把0、1、2这三个的ptr都改为了free的got所在的地址0x602018;

ptr地址

执行write 2之后,free函数got表的位置,理论上被写成system函数的地址,但是由于掌握不熟练,一直没有调试到地址位置0x4006E0;
get shell
此时程序已经get shell完毕,可以执行命令如下;
