注意:在回答之前我会说,这纯粹是一个学术回答,不打算用于恶意目的。我知道 OP 正在做的练习,它们是开源的,并不打算鼓励任何用户在未经批准的情况下使用这些技术。
我将在下面详细介绍该技术,但为了您的参考,我将看看 Vudo malloc 技巧(在您上面的一个链接中引用了它),因为我的概述将是一个简短的概述:http ://www.phrack.com /issues.html?issue=57&id=8
它详细说明了 malloc 如何处理创建内存块、从列表中提取内存和其他事情。特别是 unlink 攻击对这种攻击很感兴趣(注意:您是正确的,glibc 现在出于这个特殊原因对大小执行完整性检查,但您应该使用较旧的 libc 进行此练习......遗留兄弟)。
从论文中可以看出,分配块和空闲块使用相同的数据结构,但数据处理方式不同。看这里:
chunk -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| prev_size: size of the previous chunk, in bytes (used |
| by dlmalloc only if this previous chunk is free) |
+---------------------------------------------------------+
| size: size of the chunk (the number of bytes between |
| "chunk" and "nextchunk") and 2 bits status information |
mem -> +---------------------------------------------------------+
| fd: not used by dlmalloc because "chunk" is allocated |
| (user data therefore starts here) |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| bk: not used by dlmalloc because "chunk" is allocated |
| (there may be user data here) |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| |
| |
| user data (may be 0 bytes long) |
| |
| |
next -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| prev_size: not used by dlmalloc because "chunk" is |
| allocated (may hold user data, to decrease wastage) |
+---------------------------------------------------------+
分配的块不使用 fd 或 bk 指针,但空闲的会。这在以后会很重要。您应该了解足够的编程知识,才能理解 Doug Lea 的 malloc 中的“块”被组织成一个双向链表;有一个用于空闲块的列表,另一个用于分配的块(从技术上讲,有几个空闲列表取决于大小,但在这里无关紧要,因为代码分配了相同大小的块)。所以当你释放一个特定的块时,你必须修复指针以保持列表的完整性。
例如,假设您正在从下面的列表中释放块 y:
x <-> y <-> z
请注意,在上图中,bk 和 fd 的位置包含沿列表迭代所需的指针。当 malloc 想要从列表中取出一个块 p 时,它会调用一个宏来修复列表:
#define unlink( y, BK, FD ) {
BK = P->bk;
FD = P->fd;
FD->bk = BK;
BK->fd = FD;
}
宏本身并不难理解,但在旧版本的 libc 中需要注意的重要一点是,它不对大小或正在写入的指针执行完整性检查。在您的情况下,这意味着没有任何类型的地址随机化,您可以预测和可靠地确定堆的状态,并通过以特定方式溢出堆(通过此处的 strncopy)将任意指针重定向到您选择的地址.
要使攻击起作用,需要做一些事情:
- 您的块的 fd 指针指向您要覆盖的地址减去 12 个字节。偏移量与 malloc 在修改列表时清理对齐有关
- 你的块的 bk 指针指向你的 shellcode
- 大小需要为-4。这完成了一些事情,即它设置块中的状态位
因此,您必须在特定示例中使用偏移量,但您尝试使用 strcpy 传递的一般恶意格式是以下格式:
| 垃圾填满合法缓冲区| -4 | -4 | 您要覆盖的地址 -12 (0x0C) | 您想调用的地址
请注意,负数将 prev_size 字段设置为 -4,这使得自由路由认为 prev_size 块实际上开始于您控制/正在破坏的当前块。
是的,如果不提到这种攻击不适用于当前版本的 glibc,那么正确的解释是不完整的。大小已完成完整性检查,而 unlink 方法将不起作用。这与地址随机化等缓解措施相结合,使得这种攻击在遗留系统之外的任何东西上都不可行。但是这里描述的方法是我如何应对挑战的;)