一、The malloc maleficarum的历史由来
从2004年末开始,glibc malloc变得更可靠了。之后,类似unlink的技巧已经废弃,攻击者没有线索。但是在2005年末,Phantasmal Phatasmagoria带来了一些其他技巧,用于成功利用堆溢出
二、The malloc maleficarum的内容
虽然The malloc maleficarum技术最初包含5个内容,但是由于glib 2.23源码的发布,下面有些技术已经废弃了,不能够再使用了
The House of Prime(废弃)。 The House of Mind(废弃)。 The House of Force。 The House of Lore(废弃)。 The House of Spirit。
三、漏洞原理
攻击者通过堆溢出或者其他方式,控制到topchunk的size成员,这样我们就可以使topchunk的地址超出正常的堆段的地址,这样我们就可以控制到超出堆段之外的内存。
四、漏洞实现
①通过堆溢出或其他方式,控制到topchunk的size成员。 ②将topchunk的size成员变为一个非常大的数,这样topchunk就会超出内存中的堆段,从而访问到其他段的内存地址(got表的地址)。 ③此时通过malloc申请内存的时候,申请的就是got的内存地址,就可以更改got内存的内容。
五、虚拟机逃逸技术
原理: 我们在Windows主机中安装VMTools等软件,然后在软件中开启一个虚拟机。在虚拟机中书写一个程序,程序中包含The House of Force漏洞,因为VMTools原本就是在Windows主机的内存中开辟的一块内存空间,所以我们就可以利用虚拟机中程序的The House of Force漏洞,越界访问到VMTools之外的Windows主机的内存,从而可以控制内存的内容(例如开启一个计算器程序或者开启一个shell)。
六、演示案例
#include<stdio.h>
#include<malloc.h>
#include<unistd.h>
#include<string.h>
int main(){
long *p = malloc(0x10); //第一步
sleep(0); //只为了程序打断点使用
*(p+0x3) = -1; //第二步
sleep(0);
malloc(-4120); //第三步
sleep(0);
void *q = malloc(0x10); //第四步
sleep(0);
strcpy(q,"aaaaaaaa"); //第五步
sleep(0);
malloc(0); //第六步
sleep(0);
return 0;
}
第一步
申请一个堆块,用p指针接收,p指向此堆块的fd成员。此时堆中只有p这个chunk和topchunk两个chunk。
第二步
将p+0x3位置处的地址赋值-1,也就是将topchunk的size成员赋值为-1(因为p为long类型,在64位系统下为8字节,且chunk的成员也为8字节,又因为p不是largechunk,所以chunk的fd_nextsize和bk_nextsize成员没有被使用。因此p+0x3就是topchunk的size成员的地址)。 为什么要设置为-1:malloc的参数在进入_lib_malloc函数的时候会被转换为无符号整数,那么topchunk的size成员就会变为整数中的最大值(0xffffffffffffffff),此时topchunk能够操控的地址范围就会非常大,并且已经超出了原本堆段的地址。
当我们再去用heap查看topchunk的时候就看不到了,但是我们可以使用x命令查看内存,查看topchunk的结构(可以看到topchunk的size成员的值此时为0xffffffffffffffff)。
第三步
此时我们通过malloc函数申请一个-4120的堆空间,同理,-4120也会被_lib_malloc函数转换为一个很大的正数,因此此处是向topchunk申请一个很大的堆空间。 此时通过heap查看,可以看到一个很大的堆空间(0x601010),这个就是我们malloc出来的。并且fd指针此时指向于glibc中got表的_lib_malloc函数的位置,bk指针此时指向于got表中sleep函数的位置。
通过vmmap查看可以看到,此时我们malloc的堆块是处于数据段的(造成堆溢出了)。
第四步
此时我们再去malloc的时候,就是在got的内存地址处申请内存了,下图中可以看到0x601010这就是我们malloc的堆块。 可以看到fd指向于_lib_malloc函数地址,bk成员指向于got中一个sleep函数地址。
第五步
从第四步中可以看到,我们已经在got中申请到一个堆块,并且fd和bk成员都指向于got表的相关函数,那么此时我们就可以修改fd和bk成员,使其指向于另一个system的got函数,或者指向于one_gadget地址来起一个shell。 但是此案例中我们只是向q中写入一个字符串,由于q指向于fd成员,且fd成员为glibc中_lib_malloc函数的地址,所以此处就是将got表中原本存放_lib_malloc函数地址的内容给改了,改为一串字符串了。 通过heap的时候可以看到fd和bk都被修改了。
第六步
由于上面我们将got表中原本存放_lib_malloc函数地址的内容被改为一串字符串了,所以当我们再去malloc的时候,跳转到got表中的地址发现地址内容被修改了,于是就不能进行malloc,报错止终止。
我是小董,V公众点击"笔记白嫖"解锁更多【堆漏洞挖掘】资料内容。