0x00 UAF

pwnable.kr是一个韩国的CTF练习的网站,有很多经典的CTF题目供爱好者练习。

UAF(Use After Free)释放后重用,其实是一种指针未置空造成的漏洞。在操作系统中,为了加快程序运行速度,如果释放一块n字节大小的内存空间,当申请一块同样大小的内存空间时,会将刚刚释放的内存空间重新分配。如果指向这块内存空间的指针没有置空,会造成一系列的问题。



0x01 Fastbin

fastbin顾名思义,fast就是要快。所以fastbin旨在加快操作系统的内存分配速度,fastbin仅使用fd形成单链表的形式,且遵循LIFO原则。

当操作系统分配一块较小的内存时(64字节),会首先从从fastbin中寻找未使用的chunk并分配。


0x02 分析

通过分析题目源代码,看到各个操作的含义

  1. 调用

  2. 分配内存

  3. 释放内存

大概的思路是通过3先释放内存,因为程序释放内存后没有将指针置空。故在重新分配时会出现UAF。

0x03 Solution

这个题目涉及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都可以,不过没有测试。有兴趣的朋友可以测试一下。


【本文转载自公众号逢魔安全实验室

源链接

Hacking more

...