简介
题目:KOOBE: Towards Facilitating Exploit Generation of Kernel Out-Of-BoundsWrite Vulnerabilities
会议:USENIX Security ‘20 Summer Quarter Accepted Papers
链接:https://www.usenix.org/conference/usenixsecurity20/presentation/chen-weiteng
介绍
KOOBE:Kernel Out-Of-Bound Exploit(内核越界漏洞利用),本文研究的是内核堆内存的越界。
内核保护着操作系统的基础架构,不幸的是,一些内核例如linux内核是用C写的,由于C语言自身的属性会导致一些内存相关漏洞频发。
2006-2018:已修复的安全bug中70%与内存相关。攻击者可以利用这些漏洞进行提权进而获取整个系统的控制权。
syzbot:https://syzkaller.appspot.com/upstream,Linux内核fuzzing的bug显示。
2017.8-2018.9:1216个linux内核漏洞被 syzkaller 发现,平均每天3.42个。毫无疑问会给开发者带来很大的工作量。而这些漏洞有些可以很容易提权,有些则无足轻重,因此需要将这些分开,即给这些bug设定优先级。其中一个办法是利用PoC自动生成一般的内存漏洞利用脚本从而对这些可以利用的漏洞进行评估。当然,内核漏洞不止一种,可以分而治之,UAF漏洞的工作已经有了一定的成果(Fuze),本文研究的是OOB。
OOB:内核越界访问,本文研究的是内核堆内存
挑战:不同的OOB所表现的利用能力(Capability)不同。PoC不能展示所有的漏洞。
Capability: how far, how many, what value
1 | CVE-2016-6187 can overwrite only one single byte(off by one) |
内存属性:函数指针,结构体指针,具体的值等等
本文主要工作:给OOB漏洞分级,自动生成Expliot(AEG)
本文主要贡献:
- KOOBE可以提取OOB这一类型漏洞的Capability
- 代码开源(https://github.com/seclab-ucr/KOOBE),可供研究
- 测试了已知CVE和syzbot上的bug,证明了有效性,有助于开发exploit
范围和假设
研究范围
AEG(Automatic exploit generation)在linux内核的应用具有挑战性。KOOBE专注于性能提取(capability ex-traction )和漏洞评估( exploitability evaluation),这是本文开发堆OOB漏洞的Exploit的关键步骤。给定PoC,触发一个或多个OOB访问,KOOBE生成Exploit从而达到指令指针(IP)劫持。
假设(攻击模型)
内核被常用的保护机制所保护。
KASLR:Kernel Address Space Layout Randomization(内核地址空间布局随机化)
SMEP: Supervisor Mode Execution Prevention,禁止内核执行用户空间代码
SMAP: Supervisor Mode Access Prevention,禁止内核访问用户空间
当我们劫持IP之后,这些都可以绕过。
ret2dir:Rethinking kernel isolation,可以绕过SMEP和SMAP
From collision to exploitation: Unleashing use-after-free vulnerabilitiesin linux kernel
KEPLER :无条件地自动将IP控制转化为任意代码执行。
背景和示例
背景
内核OOB漏洞的危害性巨大,实际中内核OOB的研究是一项劳动密集型任务,手动分析花费很多精力还不一定奏效,接下来通过实例详细描述一下OOB漏洞。
示例
CVE-2018-5703:Linux Kernel 4.14.0 ,简化如下:
1 | 1. struct Type1 { ...; }; |
漏洞点:line 12,使用KASAN发现
vulnerable object: 漏洞点
target object: OOB区域
漏洞形成: line 11 -> line 12
咋一看: 好像只能越界写0x08080000000000, 该地址既不属于内核空间也不属于用户空间
再一看: 如果sys_setsockopt()被调用,则可以写任意值(PoC中并未提及,限制漏洞的可利用性, 无公开Exploit)
实际情况: 该漏洞没有公开的exploit,大概是fuzzing发现了咋一看的bug就没有继续进行下去。再一看的漏洞正是本文的KOOBE发现的,并自动生成了可以利用的exploit, 下一章的第三节会详细讲述如何发现的。
exploit简化如下:
1 | 1. for (i = 0; i < N; i++) |
利用过程分为四步:
性能概要
大部分的漏洞是Fuzzing发现,该漏洞的PoC可以破坏一些内存但是还没达到可利用的层次。因此,此时该漏洞的性能等级较低。KOOBE首先会根据PoC进行性能探测(计算当前性能和探测更高级的性能)。
堆风水
Linux内核使用的是 slab/slub 分配器,根据size分配相匹配大小的chunk(相同的size所分配的chunk大小相同,例如type1和type3)。被释放的chunk会在堆cache中,因此为了是vulnerable object和target object相邻,首先通过堆喷将堆cache中的内存耗尽。见exploit line1-4。
选择目标对象(target object)
通过前面的性能概要发现更高级的漏洞,并且布置好了堆内存。下面就需要选择攻击的目标并且写好payload,通常我们可以把攻击目标分成几种:
函数指针,见type3,可以直接控制程序流
数据指针,见type4,可以覆写结构体
非指针:需要具体讨论
- uid,写成0直接提权
- reference counter: 减少可以造成UAF,见type5
1
2
3reference counter机制
一个对象可以有多个owner,该计数器保存了程序中该对象有几个owner的信息。
当对该实例的reference counter变为0,也就是没有owner时,dealloc将被调用,以释放该实例内存。
这里选择type3,size同vulnerable object。由此看来,收集不同的target object是很有必要的。
例如:CVE-2016-6778
1 | void example1(size) |
明显的off by null漏洞,,这时候如果target object为函数指针就没无法像上面一样控制整个指针,这时候选择RC作为target object就比较合适,因为低字节清零一般会减少RC的值从而使该内存提前释放造成UAF。
在Linux内核中,可以找到2000多个潜在的target object。收集这些object将有助于自动生成exploit。
exploit合成
基于target object调整PoC进而合成exploit。在这个过程,,我们需要绕过高级检测来达到任意代码执行。
类似KASLR、SMAP、SMEP只会让攻击复杂化而不能完全防止攻击。下面简要介绍这三种防护的绕过:
KASLR:信息泄露
SMEP:ROP/JOP
SMAP:physmap spray,用户空间内存映射到physmap,内核可直接访问physmap
最后利用KEPLER把IP劫持转化成任意代码执行。
KEPLER: Facilitating control-flow hijacking primitive eval-uation for linux kernel vulnerabilities
设计
we describe the overview of KOOBE, a novel framework to extract the capabilities of heap OOB-based vulnerabilities and assess their exploitability.
首先进行漏洞分析,利用符号跟踪(symbolic tracing)来总结PoC的性能(capability),然后利用一个或更多的target object来自动确定是否可以利用,如果不能,将触发性能探测(Capability Exploration)来发现新的PoC,然后对新PoC进行分析,直到找到可利用的target object或者timeout。最后利用PoC生成exploit。
漏洞分析(Vulnerable Analysis)
给定PoC,KOOBE尝试发现漏洞点(OOB访问处)以及相应的漏洞对象,如下所示
1 | { “vuln_obj”: { |
KASAN: Kernel Address Sanitizer 的缩写,它是一个动态检测内存错误的工具,主要功能是检查内存越界访问和使用已释放的内存等问题。KASAN可以检测的内存异常包括:slab-out-of-bounds/user-after-free/stack-out-of-bounds/global-out-of-bounds等。基于影子内存(shadow memory)和红色区域(red zones)
缺陷:
- 无法提供所有的OOB,例如,OOB 访问绿色区域。
- 无法准确指出漏洞对象,大部分都指在红色区域
KOOBE方案:符号追踪结合KASAN,例如: CVE-2017-7184
1 | void example2(i) |
将vul和i都进行符号化,分析符号表达式vul+i/8有可能大于sizeof(TYPE)并且i没有约束时可以确定这是一个漏洞点。
性能概要(Capability Summarization)
Capability:在本文中,capability表示OOB写的能力,为了量化它,本文做出以下定义:
Definition 1 OOB write set
E:符号执行引擎所支持的所有符号表达式
P:所有路径
Np:可以触发漏洞的路径
Tp={(offpi,lenpi,valpi)|i∈Np∧off,len,val∈E}:OOB可写集
off:how far
len:how many
val:what value
Tpi:OOB可写集的个例
for循环:抽象成一次OOB write
Definition 2 Capability
Cp={sizep,Tp,f(p)|sizep∈E}:路径p的性能
size:漏洞对象的大小,size的大小有关target object的个数
f(p)::执行时p的路径约束,例如:line 14 -> line 15
In the motivating example, the capability corresponding tothe original PoC can be expressed as:
Corig={sizeof(Type1),{(offsetof(Type2,option),8,0x08080000000000)},/0}(1)
while the complete capability should be:
Ccomp={sizeof(Type1),{(offsetof(Type2,option),8,val)},{val!=−1}}(2)
when ‘sys_setsockopt’ is invoked before triggering the vul-nerability point.
Definition 3 Capability Comparison
∀e1,e2∈E, e1<=e2 if e1 is identical to e2 or e1is a constant whose value can be taken in e2
∀p1,p2∈P, Tp1i<=Tp2i if offp1i<=offp2i ∧ lenp1i<=lenp2i ∧ valp1i<=valp2i
∀p1,p2∈P, Cp1<=Cp2 if sizep1<=sizep2 ∧ ∀i∈Np1 Tp1i<=Tp2i
因此:Corig < Ccomp
Capability Generation
函数调用:例如memcpy,解决循环问题
直接访问
memcpy(a1,a2,a3)
a1:目的地址,提取出off
a2:源地址,提取出al
a3:长度,作为len
性能探测(Capability Exploration)
通常,一个漏洞在不同的出发路径上有不同的漏洞点,不同的漏洞点有不同的性能。甚至不同路径触发的相同漏洞点也有不同的性能(如示例)。一般的PoC只有一条触发路径,因此我们需要触发新的路径来扩展性能或者产生新的性能。本文提出一种 capability-guided fuzzing方案来探索新的性能。
Capability-Guided Fuzzing
Syzkaller :基于覆盖反馈,探索新路径而无法探索新性能
输入:PoC,Cp
方法:突变种子,在覆盖反馈的同时计算Cp,并利用Cp进行反馈(触发OOB)
重点:种子过滤。例如:当value任意时,其它只关于value的种子可以丢弃。
可利用性评估(Exploitability Evacuation)
目标约束:target object可以利用的条件,例如:指针必须指向有效地址空间,target object的大小等于vulnerable object 如果利用堆风水(不是必须,为了稳定)。
然后把目标约束和Cp丢进约束求解器进行求解,无解则换下一个目标。具体过程如下:
示例的可利用性评估如下:
性能构成
同一性能可以重复利用,如CVE-2017-7184,一个OOB可能有多个性能,解决方案-贪心算法,具体如下:
相关定义:
可利用基元生成(Exploit Primitive Synthesis)
堆喷,堆风水
实现
Syskaller:内核fuzz,主要用在性能探测和利用脚本生成
S2E:二进制符号执行框架,主要用在性能概要和可利用性评估
angr:二进制符号执行分析引擎,主要用在漏洞分析
细节如下:
动态插桩来实现 Capability-Guided Fuzzing
利用QEMU模式的Syskaller和S2E来进行CGF,Syskaller可以监测内核的内部状态而进行non-crashing fuzzing,避免KASAN的警告来保证持续fuzz(跳过但是记录导致OOB的指令)。缺点是这样可能产生误报导致一些假阳性的漏洞点或者性能。
可支持的符号长度
在可利用性评估中,我们主要考虑三个参数off,len,value并且将它们符号化。相较于符号索引来说,符号执行引擎对符号长度的支持不太友好。
解决方案:利用KLEE和Z3对长度进行迭代约束求解
1 | for i in [0, 10]: |
循环中的性能提取
循环会将阻塞符号执行(fuzzification好像有利用这个方法来阻塞DTA),因为隐式数据流。
SAGE:循环引导和模式匹配
Angr:静态分析
处理符号索引和循环边界来解决路径冲突
1 | 1. void loop(n)//n = 64 |
处理方案:消除不必要的约束
松懈不必要的约束
由于内核的复杂性,复杂的路径约束通常导致约束求解器无法再timeout前完成求解。一些无关的约束可以被松懈或直接忽略。
目标收集
总共收集2615个目标
评估
数据集:7个CVE+10个Syzbot bug
Ubuntu 16.04 、16G RAM 、Intel(R) Core i7-7700K CPU @ 4.20GHz* 8.
IP劫持基元(IP-Hijacking Primitives)
EXP:19 :5,6个新增,其中4个非CVE
约束松懈(Constraint Relaxation)
实例学习(Case Studies)
时间消耗(Time Cost)
讨论和未来工作
- 本文讨论的时OOB,可以扩展到其他类型的漏洞
- KOOBE还可以继续优化
相关工作
漏洞点发现
动态内存防护措施:KASAN,Valgrind,ASan,MSan等
解决方案 :结合KASAN和符号追踪(污点跟踪和内存探测的超集)
Fuzzing
基于覆盖反馈:AFL,Syzkaller,Honggfuzz
结合静态和动态分析的覆盖反馈:Vuzzer
基于梯度下降搜索: Angora
类神经网络:Neuzz
输入状态:Redqueen
Revery: From proof-of-concept toexploitable
AEG
相关技术:符号执行以及混合符号执行
用户程序:
APEG:Automatic patch-based exploit genera-tion is possible: Techniques and implications
Automatic generation of control flowhijacking exploits for software vulnerabilities.
Modular synthesis of heap exploits:Windows heap management
Gollum: Modular and greybox exploit generation for heapoverflows in interpreters
Towardsautomated generation of exploitation primitives for webbrowsers
内核:
Unleash-ing use-before-initialization vulnerabilities in the linuxkernel using targeted stack spraying
Fuze: Towards facilitating exploitgeneration for kernel use-after-free vulnerabilities.
Q: Exploit hardening made easy:需要给定任意地址写或者IP劫持基元
Block oriented programming: Au-tomating data-only attacks
KEPLER: Facilitating control-flow hijacking primitive eval-uation for linux kernel vulnerabilities
Heaphopper: Bringing bounded model checking toheap implementation security