—
pwnable.kr是一个韩国的CTF练习的网站,有很多经典的CTF题目供爱好者练习。
UAF(Use After Free)释放后重用,其实是一种指针未置空造成的漏洞。在操作系统中,为了加快程序运行速度,如果释放一块n字节大小的内存空间,当申请一块同样大小的内存空间时,会将刚刚释放的内存空间重新分配。如果指向这块内存空间的指针没有置空,会造成一系列的问题。
—
fastbin顾名思义,fast就是要快。所以fastbin旨在加快操作系统的内存分配速度,fastbin仅使用fd形成单链表的形式,且遵循LIFO原则。
当操作系统分配一块较小的内存时(64字节),会首先从从fastbin中寻找未使用的chunk并分配。
—
通过分析题目源代码,看到各个操作的含义
调用
分配内存
释放内存
大概的思路是通过3先释放内存,因为程序释放内存后没有将指针置空。故在重新分配时会出现UAF。
—
这个题目涉及C++程序的逆向,我们可以看一下C++中的继承是怎么体现的,以Man为例
先new了一个Human的类,在修改这个类的虚表(vptr)为Man类的虚表,最后给类的成员变量赋值。
可以看到这个对象m所占的内存空间为8(vptr) + 8(int[age]) + 8(ptr[name]) = 24
字节。知道了m对象所占的内存空间,下面需要观察内存空间的布局。
m对象内存布局的示意图
在看一下在C++中,程序是如何调用虚函数的。
对应的C++代码:
m->introduce();w->introduce();
可以看出是通过虚表的index来完成函数调用,所以要调用getshell函数需要把虚表指针的base - 8。
看对方服务器上虚表的地址
可以看到,需要覆盖的虚表指针为0x401550 - 0x8 = 0x401548
。只要将m对象的虚表指针覆盖为0x401548
,再通过m -> introduce()
即可完成invoke shell。通过UAF可以完成m对象指向的内存空间的修改。
但是,释放内存空间的过程是先释放m再释放w。
delete m;delete w;
通过一次UAF只能修改w指向的内存空间,而在引用的时候却先引用了m指向的内存空间。
m->introduce();w->introduce();
这是m指向的内存空间已经被释放,会造成段错误。
因为这块内存空间仅为24字节,所以属于fastbin。根据前面的知识,fastbin是一个LIFO的结构。所以我们只需要分配两次24字节的内存空间,第二次就会分配到之前被释放的m所指向的内存空间。所以需要运行两次分配空间的过程。
后话:因为堆是8字节对齐的,只要重新分配的内存在9-24字节之间就可以分配到之前释放的m和w。所以,程序第一个参数为9-24都可以,不过没有测试。有兴趣的朋友可以测试一下。
【本文转载自公众号逢魔安全实验室】