CVE-2016-6187 Exploiting Linux kernel heap off-by-one 利用堆大小差一错误爆破Linux内核(上)[翻译]CVE-2016-6187 Exploiting Linux kernel heap off-by-one 利用堆大小差一错误爆破Linux内核(上)
Exploitation(漏洞利用)
利用该漏洞的一个优势是我们能控制目标对象的大小(args对象大小由用户决定)。为了利用该漏洞,对象大小应该被设置为缓存大小中的一个(如8,16,32,64,96等)。本文不会详细介绍SLUB分配器如何工作(linux默认内核内存分配器),我们所需要知道的是为了提高效率分配器会预先分配大量相同尺寸的对象。slab是在缓存上包含同样大小对象主要的页。自由对象在偏移地址0(默认)处有一个“next free”的指针指向slab的下一个自由对象。
我们的方案是在同样的一个slab放置我们脆弱的对象(A)邻近一个自由对象(B),然后清除对象B的“next free”指针的least-significant字节。当两个新对象在同样的slab上被分配,最后的对象将会被分配在靠着“next free”指针的对象A和/或者对象B。
上文情境(重叠A和B对象)是仅仅可能结局之一。目标对象“变化”的值是一个字节(0-255)并且最终目标对象的位置会依靠在原始的“next free”指针的值和对象大小。
假设目标对象会与对象A和B重叠,我们想要控制这些对象的内容。
在一个高等级,漏洞利用程序如下:
-
在同样的slab上在邻近对象B处放置脆弱对象A
-
重写 B中的“next free”指针的least-significant字节
-
在同样的slab分配两个新对象:第一个对象将会被放在B处,并且第二个对象将会替代我的目标对象C
-
如果我们控制对象A和B的内容,我们可以强制对象C被分配在用户空间
-
假设对象C有一个能从其他地方触发函数指针,在用户空间或者可能的一个ROP链(绕过SMEP)中设置这个指针为我们的权利提升的payload。
为了执行步骤1-3,连续的对象分配能够取得使用一个标准的堆耗尽技术。
接下来,我们需要选择正确的对象的大小。对象比128字节更大(例如,申请缓存256,512,1024个字节)的话就不会在这里起作用。(原因在于我们只能重写一个字节,想清楚这点很关键)让我们假设起始的slab地址是0x1000(标记slab的起始地址是与页大小一致的并且连续对象分配是相连的)。接下来的C程序列出了被给定对象大小的一个单页的分配:
// page_align.c
#include
int main(int argc, char **argv) {
int i;
void *page_begin = 0x1000;
for (i = 0; i < 0x1000; i += atoi(argv[1]))
printf("%p\n", page_begin + i);
}