【bsauce读论文】SLAKE-内核slab自动化布置技术

本文来自CCS 2019,SLAKE- Facilitating Slab Manipulation for Exploiting Vulnerabilities in the Linux Kernel。源码见https://github.com/chenyueqi/SLAKE

摘要:

目标:通过操控slab布局进行提权。

难点:一是不知道哪个对象和系统调用有利于利用;二是不知道如何操控slab以获得预期布局。

方法:先用静态/动态分析技术探索有助于利用的内核对象和系统调用,对常用的利用方法建模,研究出一种方法来调整slab布局。

实现:工具SLAKE,扩展LLVM和Syzkaller。

实验:用27个真实内核漏洞,不仅能丰富利用方法而且能增大内核漏洞可利用性,不仅找到了所有常用的布置slab的系统调用,还找到了不常用的。

1.Introduction

研究原因:内核漏洞危害很大,但人力有限,来不及及时修补漏洞,一般根据可利用性来确定优先级,进行修补,所以要研究。

废话:利用方法是操纵slab布局,以劫持控制流并提权,难点已说明。已有的文章如[15]是关于自动布置堆结构,难点是系统太过复杂。

本文方法:SLAKE(SLAB manipulation for Kernel Exploitation)。步骤方法和实验结果已说明。

贡献

a.设计一种新方法,用静态/动态分析去识别有助于利用的内核对象和系统调用;

b.建模已有的利用方法,并设计方法以获得预期slab布局;

c.扩展LLVM和Syzkaller实现SLAKE,并在27个内核漏洞上验证有效性。

2.背景和挑战

2.1 问题、假设、目标

问题:许多内核漏洞最后都要利用SLAB/SLUB分配器,但目前没有一个通用、系统的方法来促进内核漏洞布局。

假设:a. 只能利用PoC的能力,eg,PoC只能触发覆写1字节,而漏洞本身可以任意写,则分析者只能写1字节;b. 可利用性 == 程序计数器是否可控(只要能劫持控制流,就很容易绕过保护并提权)。

目标:a. 识别有助于利用的对象和相关系统调用;b. 构造预期的内存布局。

2.2 技术背景

说明

  • victim object —— syscall产生的含函数指针的对象 VO
  • spray object —— syscall产生的可布置数据的喷射对象 SO
  • vulnerable object —— 漏洞代码中的对象 VULO

SLAB/SLUB分配器:同一cache中的对象大小相同,后进先出LIFO。SLUB中,每个空闲槽(slab)都有个meta-data header指向下一个空闲槽,组成一条单链和假的head freelist(存单链表的表头,非数组);而SLAB则用freelist索引数组来存对象(非链表)。参见SLUB和SLAB的区别

内核利用方法

总体步骤是,先确定漏洞类型和可控内存,再劫持控制流,最后关闭内核保护并利用。见Figure 1。

  • OOB(out-of-bounds write):a. 覆盖相邻对象中的函数指针;b. 覆盖相邻对象中的函数表指针(指向physmap[20,37]或用户空间,伪造函数表)。
  • UAF:使可控的spray object和vulnerable object重叠,通过spray object修改vulnerable object上的关键函数指针或函数表指针。
  • Double-Free:两次释放同一个块,VULO的metadata头将指向自身。先选取和VULO等大的VO;再申请VO;最后申请SO来修改VO中的关键函数指针或函数表指针。
  • 伪造metadata头:以上3类漏洞都能够达到篡改metadata头的目的,使SLUB将VO分配到可控的内存区域,很容易篡改函数指针或函数表指针。
Figure1-Exploit approach.png

2.3 挑战

a. 选取被覆盖对象VO(必须含函数指针,且大小合适)

b. 如何利用syscall分配到目标对象,并调用目标对象上的函数指针。

c. 如何调整syscall,以获得预期的slab布局,避免分配无关的内核对象。

3. 对象&syscall识别——挑战a/b

主要针对挑战a/b,直观思路是,fuzz测试syscall,观察记录slab和函数指针引用。难点,一是内核代码太多,很难用常规testcase找到所有对象的申请/释放和函数指针调用,二是syscall太多,各个syscall参数不同,导致fuzz测试效率低。解决办法,先静态分析找到感兴趣的程序点(对象申请/释放和函数指针调用),记录对象类型、size、cache、关键函数指针在对象(VO)中的偏移;再分析内核调用图的可达性,以此引导内核fuzz只fuzz能够到达兴趣程序点的syscall,记录能够到达兴趣点的syscall和相应参数。

3.1 静态分析——识别对象和兴趣点

如何识别关键对象,如何记录关键对象,如何识别通过VO引用函数指针的程序点。

(1)关键内核对象

a. victim object——针对OOB、Double-Free

特征:包含函数指针或函数表指针,通过和DF漏洞的VULO重叠或分配到OOB漏洞的VULO相邻,覆盖VO的函数指针来劫持控制流。

检测方法:检查对象是否含函数指针,如果是结构指针,则递归检测。

注意:不要分析链表,以免陷入死循环。

b. spray object——针对UAF、Double-Free

特征:能申请内核到空闲对象且被悬垂指针所引用,并布置数据。

检测方法:判断copy_from_user()的dst参数是否为堆分配函数(如kmalloc()、kmem_cache_alloc())的返回值。

(2)关键对象的分配/释放点识别

目标:目标是识别能够分配VO或SO的分配/释放点。

分配点:对分配函数(如kmalloc)的返回值,根据其def-use链,检查返回值是否属于某类关键对象的指针,属于则为感兴趣的分配点。

释放点:对释放函数(如kfree),检查传入的指针是否属于某类关键对象的指针。

(3)函数指针引用点(VO)——Dummy dereference sites

难点:a. 过程间数据流分析不准确,很难构造准确的CFG;b. 内核的软中断机制(如Read-Copy Update RCU)会释放对象,因而异步调用函数指针(比较隐蔽)。

解决:先用静态分析识别引用点,再用fuzz和动态数据流分析追踪真正的引用点和相应的syscall。对于RCU引用,引用点就是释放函数(kfree_call_rcu()和call_rcu_sched()),它们会释放VO并异步调用VO中的函数指针;对于非RCU引用,则比较明显,若调用VO中的函数指针则为引用点。

3.2 Fuzz——搜索syscall

目标:通过内核fuzz,找到能分配目标对象和引用函数指针的syscall相应参数。也即如何到达该路径

问题:传统kernel fuzz只能找到申请/释放和引用函数指针的这些点,但是并不能确定释放的是否是指定的VO、引用的指针是否来自于指定的VO。

解决:基于上下文的fuzzing和动态数据流分析。

(1)Panic Anchors——插桩

目的:在目标点(申请、释放、引用点)插桩,如果fuzz到目标点,则终止并记录syscall和参数。

问题:误识,其他进程的异常信号、设备的中断信号、内核线程、用户进程也可能执行到目标点。

解决:Panic Anchors 负责 a. 检查内核变量system_state == SYSTEM_RUNNING,表示正执行用户调用的syscall;b. 检查task_struct结构中的comm值,显示是否为用户调用的syscall。 并记录分配对象的地址。

// comm值可由用户进程指定
// kernel代码的打印信息中常可看到使用该成员表示相关进程信息,例如
 printk(KERN_INFO "note: %s[%d] exited\n",
  current->comm, task_pid_nr(current));

// 使用函数set_task_comm设置该成员的值,使用函数get_task_comm获取该成员的值。
char *get_task_comm(char *buf, struct task_struct *tsk)
void set_task_comm(struct task_struct *tsk, char *buf)

(2)syscall识别

目的:减少fuzz的syscall目标数,提高效率。

方法:构造内核call graph,对目标点进行可达性分析(可达且不需要特权执行CAP_SYS_ADMIN),只fuzz可达的syscall。

记录

  • a. 分配点:执行到syscall的分配点,则记录相应参数和分配的slab,有利于布局slab和基于上下文的fuzzing。存储database细节见Appendix。
  • b. 释放点:先执行syscall分配对象并记录,再fuzz到释放点,检查释放对象是否为之前的分配对象,记录syscall和相应参数。
  • c. 引用点:先执行syscall分配对象并记录,再fuzz到引用点,检查引用的函数指针是否位于之前的分配对象VO中(方法是,当执行到引用点,则继续执行直到退出当前函数,记录整个的执行路径,以此构造use-define chain,根据use-define chain来判断函数指针是否来自VO),记录syscall和相应参数。

4. slab布局——挑战c

方法:搜索以上database,找到能匹配漏洞能力的可用对象,使用slab布局方法获得有助于利用的slab布局。

4.1 匹配漏洞能力和可用的对象

(1)漏洞和对象建模

Ar[m]——表示漏洞能力,即m个用户可控的不重叠的内存对象(VO/SO),元素为(l, h)—起始与终止偏移。

Ap[n]——n个关键数据(函数指针/metadata)的偏移。

w——指针的size,4或8。

Figure2-modeling.png

(2)配对漏洞和可用对象

具体方法的描述见Appendix。

  • a. OOB:一是覆盖相邻空闲对象的metadata,并将VO分配到可控区域,要求是VO与VULO属于同一cache;二是申请VO与VULO相邻,再利用漏洞覆盖VO,要求是VO与VULO属于同一cache,且能覆盖到关键函数指针(通过检查Ar[m]和Ap[n]是否重叠)。
  • b. UAF:一是修改metadata,并将VO分配到可控区域,要求是VO与VULO属于同一cache;二是使SO与VULO重叠,通过SO修改VULO上的关键函数指针来劫持控制流,要求是SO与VULO属于同一cache,且能覆盖到关键函数指针(通过检查Ar[m]和Ap[n]是否重叠)。
  • c. Double-Free:一是使VO和SO重叠,修改VO中的关键指针,要求是VO/SO/VULO在同一cache,且SO与Ap[n]中函数指针重叠;二是使VULO和SO重叠,修改VULO中的metadata,要求是VULO和SO在同一cache,且SO和VULO中的metadata重叠。
Figure3-Pairing object.png

4.2 slab布局

问题:很容易根据database选取合适的object,但是可能还会分配/释放其他的数据对象,不能获得预期的slab布局。

(1)调整空闲槽——目标槽空闲

目标:将对象分配到目标空闲槽,eg,构造重叠的SO和VULO。

方法:a. 列出 free list chain上所有连续的空闲槽并编号(在LIFO链表中,从左到右)。b. 假定实际PoC中的syscall将关键对象分配到第i个,但是目标位置是j,若i<j,则在调用syscall之前分配(j-i)个对象来占据空闲槽(使实际的i后移);若i>j,则在触发漏洞之前分配(i-j)个对象(使目标j后移),再触发漏洞,释放申请的对象。c. 调用syscall,分配目标对象。

注意:a. 所选的syscall在申请/释放对象要没有副作用;b. 触发漏洞和slab布局之前要进行defragmentation[31,48] 反碎片化,避免网络连接、文件打开、页映射等无关操作对slab布局的影响。

(2)重组空闲槽——目标槽被占

目标:对于OOB漏洞,要使VULOi-1和VOi相邻,需进行slab重排。见Figure4。

步骤:a. 扩展PoC,在Syscallvulo后插入Syscallvo;b. 用ftrace插桩PoC,记录分配/释放的对象,假定总共申请了K个内核对象,VO实际在jth槽,预期在ith槽;c. 重排序步骤,先去碎片化,然后分配对象占据K个空闲槽,再逆序释放(交换第i和j个对象的释放顺序),最后按原先顺序执行,即可使VULO与VO相邻。

Figure4-Reorganize slab.png

5. 实现

(1)静态分析

准备:glove[18]将整个系统编译为LLVM IR。

实现:两个LLVM pass,基于LLVM6.0,总共2000行C++代码。

a. 识别对象和目标点:利用LLVM IR中的类型信息来追踪VO;利用调用内核I/O函数的CallInst(如copy_from_user())来识别SO。对于识别到的对象,记录其申请/释放点和所在的cache name,若对象包含函数指针,则识别其引用。

b. 构建调用图:改进KINT[43](利用静态域敏感的过程间污点分析,构建调用图)。采用两种剪枝方法,一是去掉和.init.text节中的函数有关的节点和边(系统启动后不会再调用);二是去掉不相关模块之间的bridging edges(通过KConfig文件中的标签"depends -> on"、"select",表明模块是相关的)。

(2)动态分析

实现:(a+b)—700行C++;c—200行python;d—400行C。

分析:由于对对象的释放和引用要和之前申请的相关联,所以KCOV[49]不适合用于本文的插桩。

a. GCC插件-插桩:用fuzz找到执行到目标点的路径,以识别能走到分配/释放点和函数指针引用点的syscall。

b. 扩展Syzkaller和Moonshine:另外增加了一些fuzzing模板。

c. GDB python脚本:目的是确定函数指针引用是通过VO引用的。在QEMU上运行内核,在函数指针引用点下断点,只要断下来,就单步执行,记录从断点到当前函数执行结束的路径,构造use-def chain,进行前向数据流分析,检查chain上每个函数指针引用,确定是从相应的VO引用的。

d. ftrace工具:对syzkaller产生的程序进行插桩,记录每个syscall的slab活动(记录syscall副作用)。

6. 实验

6.1 环境配置

内核版本:v4.15,对core kernel(defnoconfig定义的)和32和通用模块进行静态分析,建立database。fuzz时的编译选项加上KCOV。

fuzz时间:每个目标点fuzz 2h。

环境:3个VM,配置Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHZ CPU and 64GB memory

CVE选择标准:有公开PoC / 移植到v4.15很方便 / 触发条件不涉及硬件。共27个。

6.2 syscall识别评估

(1)比较调用图构造

对比:改进的KINT[43] vs 原型匹配方法[50]。结果见Table 1。

结果:a.排除通过syscall不可达的VO/SO对象数量,"# of v/s"—124/4 --> 104/4;b. 排除目标点不可达的syscall,"avg. syscall #"— 257 --> 68,减少动态分析的时间("avg. time" 34min --> 2min)。

注意:fuzz时间是2h,SLAKE发现目标点不可达并不意味着真的不可达,而是在2h内fuzz不到目标点。

Table1-result.png

(2)比较不同模块

a. 有些模块找不到有用的object;

b. SO数量少于VO,只有3个模块含有效SO,原因是内核一般将用户数据存于栈而非堆中。

(3)比较SLAKE和手动分析

手动分析syscall很难,换个角度,对比已有的exp中用到的syscall(10个),SLAKE全发现了,还发现额外22个含可用object的syscall。找到含VO/SO的syscall见Table 2。

Table2-object syscall.png

6.3 exp生成

(1)对比已公布的和SLAKE生成的exp

能够极大丰富内核漏洞的利用方式,对未公布exp的漏洞,SLAKE能找到合适的object,提升可利用性。结果见Table3。

(2)失败案例分析

a. CVE-2017-1000112 / CVE-2018-5703:其PoC显示只能覆盖VULO内的数据。

b. CVE-2017-2636 / CVE- 2014-2851 / CVE-2018-17182:没有合适的object可用。

c. CVE-2018-12714 / CVE-2018-16880 / CVE-2017-17052 / CVE-2018-10840:其PoC显示并不能自由写目标内存。

7. 讨论&未来工作

平台扩展——其他OS,如Windows、FreeBSD、Android。

其他分配器——如SLOB、buddy、ptmalloc。

其他对象识别方法——不只是利用copy_from_user识别SO,还有memcpy

其他利用方法——[16,21]。

自动化分析漏洞的能力。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335