针对 CVE-2016-6187 的内核漏洞利用(本地权限提升)(受影响版本:< 4.6.5)
该漏洞利用是针对自定义编译的 4.6 内核 + buildroot(kconfig 即将发布)开发的,
可绕过 KASLR、SMEP、SMAP(KPTI 在 4.6 上不可用)
被利用的漏洞是 AppArmor 的一个 LSM 钩子(setprocattr)中基于堆的单字节空溢出。参见 https://nvd.nist.gov/vuln/detail/CVE-2016-6187
初步测量表明,获得 root shell 的概率为 94.44%。在 18 次中约有 1 次,该漏洞利用会使内核 oops。在获得 root 访问权限后,仍需进一步工作以完全稳定内核。
我们利用空字节溢出破坏 kmalloc-128 中 freelist 指针的最低有效字节(LSB),使其实际上指向一个已分配的对象。之后,我们释放该已分配对象,造成双重释放场景。
现在我们可以从 kmalloc-128 缓存中分配两个重叠的结构。第一个结构是一个内容可以被用户空间读回的对象。为此,我选择了 ip6_sf_socklist。第二个结构将分配在 ip6_sf_socklist 之上,应包含内核指针——rfkill_data 很合适。它包含一个堆指针(空的 rfkill_data.events 列表)和一个指向 rfkill_fds 的全局数据指针(rfkill_data.list.prev)。一旦 rfkill_data 分配在 ip6_sf_socklist 之上,我们就可以通过调用 getsockopt(sock, IPPROTO_IPV6, MCAST_MSFILTER, gsf, &optlen) 获取内核指针。然后可以从 rfkill_fds 推导出内核文本基址。
然后我们制造第二个双重释放场景,但这一次我们利用消息队列的链接过程来覆盖 freelist 指针,并欺骗分配器在我们实际请求 kmalloc-128 块时返回一个来自 kmalloc-96 的块。
然后我们可以利用大小不匹配来溢出到 kmalloc-96 块的 freelist 指针,从而获得分配任意地址的原语。在我们的案例中,我们瞄准 ptmx_fops 结构,并用指向我们的栈迁移 gadget 的指针覆盖 ptmx_fops.unlocked_ioctl 回调。
对 /dev/ptmx 调用 ioctl 会触发栈迁移 gadget,我们将栈迁移到 kmalloc-128 中的一个伪造栈,那里我们已经准备好了第一阶段的 ROP 链。
由于 kmalloc-128 伪造栈上的空间有限(我们不知道下一个块是否在同一个 slab 上),第一阶段 ROP 链的任务是将第二阶段 ROP 链从用户空间复制到内核 dmesg 日志缓冲区(__log_buf),并将栈迁移到 __log_buf。
第二阶段 ROP 链随后尝试修复内核(恢复 ptmx_fops 等),然后调用 commit_creds(prepare_kernel_cred(NULL)) 提升权限。
最后,它通过 iretq 退出内核空间,我们以提升后的权限返回到 execve("/bin/sh", 0, 0) 子例程。
非特权用户必须至少能够打开 /dev/rfkill。某些发行版可能不允许这样做。我检查过 Ubuntu 和 Fedora,两者都允许非特权用户打开 /dev/rfkill(尽管 Fedora 使用 SELinux 而不是 AppArmor)
以下部分说明如何在 qemu-x86_64 中复现本地提权。
首先,你需要获取一个 initrd 和 bzImage 内核。有两种方法:
最简单、最快的方法。你可以在 prebuilt/ 中找到所有必需的组件。
或者,你也可以自己构建这些组件。只需获取 4.6 内核,并使用 config/ 中提供的 x86_64_vuln_kern_defconfig 来编译 bzImage。
对于 initrd,你可以使用 buildroot。只需确保在你的 init 中为 /dev/rfkill 设置正确的权限
chmod 664 /dev/rfkill
这与 Ubuntu-16.04 和许多其他发行版中的设置相同。另外,不要忘记编译该漏洞利用程序并将其放入你的 initrd
make
获得组件后,启动易受攻击的机器
./boot.sh <path/to/bzImage> <path/to/rootfs.cpio>
然后执行漏洞利用程序
./exploit
你可能需要多次运行该漏洞利用程序,具体取决于我们是否将一个原本已为零的 LSB 置零。另请注意,在获得 root 访问权限后仍然有较小的可能性(也许 10%-20%?)崩溃——我正在努力解决这个问题。
玩得开心。
ptmx_fops 以提高稳定性kmalloc-128 freelist 以提高稳定性