KEPLER-新型内核ROP构造方法

摘要:

漏洞利用面临的挑战有保护机制、缺陷路径和不合适的原语,导致很难手动构造exp。提出KEPLER,利用符号执行和特殊的gadget,自动生成"single-shot"利用链(漏洞只触发一次),对比Q和FUZE,能生成更多有效的exp。

挑战:a. 保护机制,如CFI(效率原因,Linux主版本未采用);b. 缺陷路径,数据构造错误可能导致访存错误、死循环等;c. 不合适的利用原语:漏洞本身的缺陷,如控制的寄存器个数有限。

引言

KEPLER采用一种技术将控制流劫持原语的利用转变为在内核堆栈中构造经典的溢出漏洞,这种利用技术对于利用原语的质量和堆栈转移gadget的可用性要求较低,并能绕过当前广泛部署的内核缓解措施,从一个可能不适用的控制流劫持原语(CFHP)开始,KEPLER克服了堆栈转移gadget的缺乏,并成功构建了一个"单次执行"的利用链,以启动现有的图灵完备的利用技术,如返回导向编程(ROP)[56],同时具备绕过主流内核缓解措施和避免利用路径陷阱的能力。

为了绕过Linux内核中广泛部署的缓解措施,KEPLER利用一个经过精心设计的代码重用模板。KEPLER首先增强了一个利用原语,以满足同时控制双寄存器(例如x86-64架构中的rip和rdi)的最低要求。从这个原语开始,KEPLER生成一个利用代码,按顺序执行一系列五个gadget。代码重用模板的设计涉及到Linux内核编码风格的几个见解。具体而言,KEPLER重用了那些基于堆栈的内核I/O通道函数调用,以泄露和破坏当前进程的内核堆栈,并执行任意用户提供的ROP负载。KEPLER利用了"blooming" gadget来增强对控制流劫持原语所需寄存器的控制能力。

KEPLER利用一个桥接gadget将泄露内核堆栈canary和破坏内核堆栈的实践结合成一个单次操作,从而防止意外的内核崩溃。为了针对任意内核二进制生成每个CFHP的利用代码,KEPLER分为以下两个阶段进行操作:首先,KEPLER对内核二进制进行静态分析,以获取五类候选gadget。然后,KEPLER从CFHP开始进行内核符号执行,并基于候选gadget执行基于深度优先搜索(DFS)的gadget拼接算法。我们对KEPLER的评估表明,它在利用原语评估方面非常强大。为了突出KEPLER的有效性,我们将其与现有的利用加固/生成工具(例如Q [60]、fuze [75])进行了比较,结果显示KEPLER在Linux内核的现代缓解设置下生成有效的内核利用中表现优秀。

KEPLER执行过程:KEPLER分为以下两个阶段进行操作:首先,KEPLER对内核二进制进行静态分析,以获取(五类)候选gadget。然后,KEPLER从CFHP开始进行内核符号执行,并基于候选gadget执行基于深度优先搜索(DFS)的gadget拼接算法。

贡献:

我们对KEPLER进行的评估显示它在利用原语评估方面非常强大。为了突出KEPLER的有效性,我们将其与现有的利用加固/生成工具(例如Q [60]、fuze [75])进行了比较,结果显示KEPLER在Linux内核的现代缓解设置下生成有效的内核利用中表现优秀。这项研究工作做出了以下贡献:

Kernel single-shot exploitation:我们提出了一种代码重用的利用技术,该技术在现代Linux内核缓解措施和原语本身的各种限制下,将一个不适合的控制流劫持原语转化为执行任意ROP负载(Arbitrary ROP payload execution--指能够执行任意ROP(返回导向编程)负载的能力。)。所提出的技术利用了普遍存在的内核编码风格和相应的gadget,因此很难被击败。我们计算利用链的方法是可自动化的,因为gadget拼接问题可以转化为在一个合理大小的搜索空间上进行搜索。此外,这种技术的“单次”特性使其适用于容易出现意外终止的漏洞,因为它避免了多次对控制流劫持原语的压力测试。

Semi-automatic exploit generator for Linux kernel:我们使用一组工具,包括IDA SDK、QEMU/KVM和angr,来实现KEPLER。从用户提供的控制流劫持原语开始,KEPLER分析Linux内核二进制,追踪有用的内核gadget,并自动生成许多gadget链,用于启动“单次”利用并绕过内核缓解措施。它不需要内核源代码,并且可以应用于剥离了符号信息的内核映像。KEPLER适用于现代Linux内核;我们的评估使用的是4.15.0版本,这是我们评估时的最新版本。

Practical impacts:我们系统地评估了KEPLER的有效性和效率,使用了16个真实世界的内核漏洞和3个最近发布的CTF挑战。在给定内核控制流劫持原语的情况下,我们证明KEPLER通常能够生成数万个不同的利用链,具有绕过内核缓解措施和执行成功利用的能力。我们展示了KEPLER可以在不到50分钟的时间内输出针对内核漏洞的第一个可工作的利用代码。

贡献总结:a. 提出"single-shot" 利用方法,自动生成rop—将一个不适合的控制流劫持原语转化为执行任意ROP负载;b. 半自动exp生成:利用IDA SDK、QEMU/KVM、angr,实现KEPLER,它不需要内核源代码,并且可以应用于剥离了符号信息的内核映像。KEPLER适用于现代Linux内核;c.实用性好,对16个CVE、3个CTF能够生成有效的不同利用链。

2.背景和相关工作

利用原语是指在各个层面上违反安全策略的机器状态,并表明攻击者可能获得超出原始程序提供的正常功能之外的额外能力。控制流劫持原语(CFHP)是一种可能偏离合法控制流图的机器状态。在符号分析的上下文中,通常通过应用启发式方法来识别控制流劫持原语,该方法查询后端约束求解器,检查控制流跳转目标包含符号字节时是否超出阈值的可行控制流跳转目标数量。任意内存写入原语是指攻击者可以随意修改内核内存的机器状态。类似地,任意内存泄露原语是指允许攻击者在任意内核地址处转储数据内容的机器状态。有时原语不允许攻击者在任意内核地址修改/泄露数据(例如,只在内核堆栈上转储几个字节的堆栈信息泄露 [68]),它们被称为受限制的内存写入/泄露原语。

如上所述,这项研究工作主要集中在两个方面:一方面,通过设计一种新的利用技术,促进了对不适合的利用原语的评估,并绕过广泛部署的内核缓解机制;另一方面,开发了一个工具来自动化新提出的内核利用方法。因此,与我们的工作最相关的是与利用原语识别、利用原语评估和内核利用技术/缓解措施相关的工作。接下来,我们将描述在这三个方向上的现有工作,并讨论它们与我们的工作的区别

2.1 利用原语识别
为了辅助找到有用的利用原语(如控制流劫持原语和内存写入/泄露原语),存在大量的研究工作。例如,Brumley等人利用预处理的符号执行和共享执行技术开发了AEG和mayhem,以识别可进一步利用的控制流劫持原语[3] [9] [7]。Shoshitaishvili等人开发了一个名为Mechanical Phish的网络推理系统[62]。它构建在angr[64] [69] [63]之上,通过模糊测试和符号跟踪来识别利用原语的PoC。为了高效地探索Linux内核中的利用原语状态空间,Wu等人提出了一种利用下文模糊测试和部分符号执行来探索UAF漏洞的CFHP和内存写入原语的自动化技术[75]。为了构建具有越界访问能力的更好的利用原语,Heelan等人利用回归测试获得了堆布局操作的知识[30]。Lu等人为了获得更好的堆栈Use-Before-Initialization漏洞的利用原语,提出了一种确定性堆栈喷射方法和一种详尽的内存喷射技术[46]。在本研究中,我们不专注于促进利用原语的识别。相反,我们假设利用原语已经被识别出来,我们的研究工作集中在后续的利用原语评估阶段。

2.2 利用原语评估
在利用原语评估阶段,安全分析师或自动利用生成系统尝试适合先前确定的可利用状态的利用技术。最初,这些系统在不考虑数据执行预防的情况下,使用简单的技术,如具有CFHP的ret2stack-shellcode和ret2libc [3] [9] [62]。考虑到W ⊕ X,Schwartz等人提出了Q [60],通过自动构建ROP链来促进利用CFHP。我们的工作解决了无需堆栈旋转装置的ROP引导问题,并且与自动ROP链技术[33] [60] [66] [24] [57]无关,因为我们不解决ROP有效负载构造的问题。

借助前向和后向污点分析的便利,Mothe等人设计了一种技术方法,用于为用户模式应用程序中的简单漏洞创建工作利用程序[48]。利用符号执行,Repel等人为那些存在于用户空间应用程序中的堆溢出漏洞创建具有单一内存写入原语(如不安全的解链接和旁路列表破坏)的利用程序[55]。为了促进内核Use-After-Free利用的原语评估,Xu等人提出了两种内存冲突机制[77]来释放CFHPs。

最近,一些研究工作考虑了CFI(Control-Flow Integrity)来进行原语评估[29] [8] [59] [23] [31] [32] [35]。例如,Ispoglou等人提出了面向块的编程(BOP)[35],以证明在CFI和常见用户空间缓解措施下的图灵完备性,从而促进可重复任意内存写入原语的评估。BOP假设存在一个分派器gadget,并且还自动化了利用生成过程。由于可重复的任意内存写入原语几乎是内核利用的“上帝模式”,我们的工作便于对那些较弱的利用原语(例如不可重复和不适合的CFHP)进行实际环境中的原语评估

在这项工作中,我们还开发了一个工具来促进原语评估。然而,这项研究工作在以下至少一个方面与前述工作根本不同。首先,在不假设完美的利用原语(如无限次调用任意内存写入原语)的情况下,我们可以促进通常被忽视的利用原语(如不适合的原语和仅能触发一次的原语)的评估。其次,我们的工具不是针对用户空间的应用程序,而是针对涉及复杂操作并通常启用了复杂的安全缓解机制的Linux内核进行利用。第三,我们的工具不是为目标漏洞生成单一的利用程序,而是自动探索许多可能的利用链,并输出各种有效的利用程序。

2.3 内核利用技术/缓解措施
最初,内核中的CFHP可以直接在用户空间中执行shellcode,因为用户空间和内核空间之间没有隔离(例如,ret2usr)。监管模式执行预防(SMEP)[38]防止内核执行用户空间代码。攻击者可以使用代码重用攻击。为了将堆栈指针设置为受控有效载荷,她使用了常见的“pivotto-userspace” gadget来将堆栈切换到用户空间[44]。随着监管模式访问预防(SMAP [11])的采用,攻击者不能再依赖于用户空间中的虚假堆栈,因为除了在I/O通道函数期间,用户空间内存访问是被禁止的。因为Linux内核通常没有内核内部的堆栈旋转gadget,所以攻击者通常选择通过翻转cr4寄存器中的相应位来禁用SMAP [41]。然而,“cr4-flipping”攻击通常依赖于双重CFHP [41],对于一个不可重新触发的CFHP来说并不适用。此外,基于虚拟化的Hypervisor可以通过检查vmexit来检测cr4寄存器的修改,从而缓解此类利用[49] [51]。Ret2dir [39]攻击通过调用syscall mmap来喷洒物理映射区域,由于直接映射的物理内存先前被标记为可执行,将CFHP转移到物理映射区域上将导致任意shellcode的执行。然而,通过应用内核补丁,这些物理映射页不再可执行。

为了对内核强制执行CFI策略,已经提出了几种内核CFI解决方案[16] [70] [26],然而这些缓解措施并没有被CentOS、Ubuntu和Debian等主要Linux发行版本广泛采用。


仅使用数据的内核利用技术直接使用内存写入原语来修改敏感的内核数据对象,如进程凭证、页表和虚拟动态共享对象(vdso)[36]。然而,已经提出了一些缓解措施[17] [67]并进行了部署[40],以防止这些低级的攻击。


需要注意的是,一些内存写入原语可以通过覆盖和调用内核数据段或堆中的代码指针来转换为控制流劫持原语[19]。

为了提供给攻击者一个不可预测的攻击表面,广泛部署了内核地址空间布局随机化(KASLR)。然而,由于它缺乏及时的重新随机化和粗粒度的特性(只随机化节的基址),攻击者甚至不需要任意读取原语[45] [71]就可以绕过KASLR。利用硬件侧信道[34] [28],他可以推断出粗略的内存布局,而不泄漏任何内核内存内容。尽管内核页表隔离(KPTI [13])通过额外的开销消除了一些侧信道,但攻击者仍然可以使用受限的内存泄漏原语来推断粗略的内存布局[68]。在Linux内核的默认设置中,了解粗略的内存布局就足够应对各种利用技术。(内核)代码多样化/随机化[14] [15] [27] [74] [42] [53]可以通过阻止攻击者定位有用的gadget显著提高代码重用利用的难度。

可能的未来研究

展望未来,我们建议未来的研究可以从两个方面进行。从自动利用原语评估的角度来看,我们认为有必要发明技术来系统评估各种利用原语,特别是那些较弱的利用原语。在实践中,应该提出理论和技术,以便从最初较弱的利用原语中衍生出更好的利用原语。从防御的角度来看,一方面,我们认为有必要为Linux内核设计轻量级的控制流强制机制。另一方面,可以在编译时增强GCC的能力,而不是手动彻底改写内核代码。



参考作者:bsauce

链接:https://www.jianshu.com/p/53570db6fcba

我们的工作解决了在没有堆栈转移gadget的情况下启动ROP的问题,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值