文章目录
简介
这篇论文来自NDSS 2020,论文的目标是:给定一个补丁以及目标程序,SID自动确定补丁能否修补安全影响。(评估补丁)
A bug is a vulnerability if it has security impacts when triggered.
确定一个bug的安全影响对于攻击者和防御者来说都很重要。软件开发者要面对很多bug报告和提交的补丁,如何验证这些是个耗时耗力的工作。确定哪些bug是漏洞是很难的。如果开发者认为只是个bug而不是漏洞,那么这个bug的处理就会被延后。从另一方面来说,一个有公开报告的bug,要利用起来就容易得多。攻击者可能会利用这些bug去实现一些攻击。常规的方法是手工去验证这些bug的安全影响。但是手工分析的扩展性和可靠性都不咋地,可能会错过一些漏洞。
因此,文章提出了一种自动化的方法,SID。给定一个bug的补丁,能够确定bug的影响。然后软件开发者就可以高效地应用补丁到被影响的程序里。SID背后的思想是补丁的影响或者违反安全的操作可以建模为约束条件。
贡献:
- 对bug和补丁做了全面的研究。分析了bug和漏洞的差别,然后对常见的安全漏洞做了建模。
- 符号规则比较的方法去确定安全的影响。提出了SID去确定bug的安全影响。
- 找到了安全bug和未打过补丁的漏洞。
背景
为了更好理解bug的成因和安全影响,从而找到安全bug。作者分析了linux内核中现有的漏洞补丁。首先,作者展示了bug和漏洞的差别。然后分析了漏洞的成因和安全影响。基于这些数据,作者为漏洞补丁总结了一个模型。
General Bugs
如果一个bug触发的时候,会导致一些安全影响。那么这个bug可以称为是security bug。这也是security bug和general bug不一样的地方。下面的代码展示了general bug和vulnerability的区别。在这个例子里,如果没有第三行的检查,就是个漏洞了,因为会导致第九行的越界访问。相对而言,如果没有第六行的检查,那么并不会引入任何安全影响,因此它只是一个general bug。更多关于安全检查的定义和检查,可以查看前人的工作。【Check it again: Detecting lacking-recheckbugs in os kernels.】
近三年,NVD数据快显示linux内核大约有800个漏洞,但是只有一小部分包含合法git-commit信息的补丁。因此,作者选择了其中的100个分析。得到下表的结果。
本研究中,作者将从bug的安全影响来区分他们。传统的漏洞分类侧重于漏洞的安全影响,而不是root cause。比如,缺少边界检查是一个bug,由于缺少边界检查导致的越界访问是安全影响。因此,为了确定安全影响,我们需要分析补丁的影响。而且,我们基于违反安全规则的操作来定义安全影响,比如越界访问、UAF。而不是其导致的利用,比如控制流劫持,信息泄露。这与sid的目标一致,确定一个bug是如何违反安全规则。如何利用这些操作来实现利用,不是本文的目的。
补丁模型及其组件
给定一个补丁,要确定其影响,我们首先需要识别补丁中和安全影响相关的组件,从而构建补丁模型。根据我们分析现有漏洞补丁的经验,我们认为这三个关键组件可以确定安全影响。
- Security Operations:安全操作用于修补至少一个安全影响。
- Critical Variables:关键变量是一些非法值或者状态会导致安全影响的变量。比如,一个检查边界的变量就是关键变量。
- Vulnerable Operations:常见的vulnerable operations包含缓冲区和数组操作,读或写操作,包含关键数据结构的指针操作,比如inodes,文件。以及资源释放操作。
假设:
- 提供的补丁可以正确修补bug
- 确定table3里所有的常见安全影响(目前并不包含空指针解引用,因为这个漏洞很难在内核中利用)
- 补丁修复的漏洞是可利用的
Overview
给定bug和补丁,把打上补丁的和没打上补丁的程序编译成llvm的IR。对于Patched Version,用静态分析找到security operations、critical variables以及vulnerable operation。对于unpatched version,只需要找到critical variables和vulnerable operation。接着,收集security operations、安全规则以及路径的约束条件。求解,如果不可解,则是unsolvable。
implementation
在LLVM上实现了多个pass实现找到安全检查,符号执行和数据流分析。SID总共代码是5600行的C++和1.2k的python。
预处理
由于漏洞操作可能和补丁不在同一个文件。作者使用静态分析去自动提取补丁依赖的文件。
- 首先提取补丁代码和变量
- 对补丁代码使用控制依赖分析,对相关变量使用污点分析,同时前向和后向进行,来识别所有依赖的文件
- 大多数情况下,补丁和漏洞操作在同一文件里。
没打过补丁的版本只要用补丁前git commit版本就可以了。
识别安全操作
通过分析git log里的补丁代码,SID可以知道一个补丁是否包含安全操作。对于不同类型的安全影响,相应的安全操作也不一样。安全操作如下:
- Bound checks:用两种标准来检查bound checks。
- 使用条件语句,并且比较指令的操作符是=,>,<,<=,>=,并且两个操作数都得是int或者unsigned类型
- 条件语句的分支必须会导致error handling。
- Pointer nullification:很容易检测出来,只要null被赋值到指针即可。
- Initialization:store指令,对个变量进行赋值为0的操作,或者memset函数用0作为参数。
- Permission checks:收集了常用的权限函数,比如afs_permission,ns_capable(),然后如果条件语句的返回值是这些函数,就认为是perimission check。
识别vulnerable operations
首先,提取关键变量。基于关键变量的使用,使用数据流分析来是被vulnerable operations。
- out of bound access: 识别使用关键变量访问数组或者buffer的指令作为vulnerable operations。同时,也认为使用关键变量作为输入的常见读,写函数(memcpy)也是vulnerable operations。
- UAF,DF:识别所有的关键变量指针解引用操作
- 未初始化使用:对未初始化变量进行常见操作的也是vulnerable operations。包含指针解引用,函数调用,内存访问,位操作,算术操作。这些操作的目标是关键变量。
- permission bypass:从permission check里提取的关键变量,我们保守地认为对这些关键变量的操作是vulnerable operations。
映射patched 和unpatched version
首先,提取patched 和unpatched version里的vulnerable operations。vulnerable operations一定是匹配的。如果vulnerable operations匹配上了,就对比控制流,确保两个切片是一样的,除了补丁引入的部分。
基于这两个步骤,sid可以在patched和unpatched两个版本之间映射切片。
约束的符号执行引擎
SID使用under-constrained 符号执行去分析patched和unpatched的代码。类似UC-KLEE,SID的符号执行可以从函数的任一点出发。特别在于,SID只执行静态分析收集的切片。由于从这些切片收集的约束并不完整,他们是under-conostrained的,也就可能导致误报。然而,sid的主要目标是在较低的误报率下确定安全影响。如何收集更多的约束,请看论文的discussion部分。
评估
从accuracy,effectiveness,scalability来评估SID。具体的结果可以去看看论文。
相关工作
从bug中找到漏洞
先前的工作使用监督学习和无监督学习,利用补丁的文本信息去区分漏洞和bug的区别。Tyo( Empirical analysis and automated classification of security bug reports)论文里提到朴素贝叶斯和支持向量机的性能最好。然而这些工作不能解决没有描述的补丁或者描述不准确的补丁。
另外,这些工作主要是从bug里找漏洞,并不能确定bug的安全影响或者定位到导致安全影响的漏洞操作。
测试漏洞的可利用性
这里介绍的都是AEG的工作。SID与这些工作不同的地方是确定bug的安全影响。
评估bug的严重性
Mell提出了CVSS来对漏洞危害进行评分。CVSS需要人工对漏洞进行评分,主要是基于漏洞的confidentiality,integrity和availability。然而,Munaiah指出,CVSS有失偏颇。比如,它在评估漏洞危害的时候,并不把代码执行和提权认为是一个严重的因素。其他分析漏洞危害的技术都是基于bug 报告,而这并不能解决补丁没有描述或者描述不准确的情况。
符号执行
提到了klee和uc-klee。klee只能从程序entry出发去符号执行。uc-klee主要是去看补丁是否引入了新的漏洞。
其他可能有用的资料
如何缓解符号执行的路径爆炸:
- 将LLVM IR的循环变成if 语句
- Fitness-guided path exploration in dynamic symbolic execution.
- Precise and Scalable Detection of Double-Fetch Bugs in OS Kernels
- 大于150个基本块的切片,自动省略
- Under-constrained symbolic execution: Correctness checking for real code.
静态分析里如何识别非直接跳转目标:
- 使用结构体来匹配函数目标。
- Detecting missing-check bugs via semantic and context-aware criticalness and constraints inferences.
- Fine-Grained Control-Flow Integrity for Kernel Software.
- Pex: a permission check analysis framework for linux kernel
总结
现阶段同类型的工作都是使用补丁的描述以及文本信息,这些信息可能并不准确,会影响后续的结果。
所以还是从代码出发,去自动化地确认漏洞的安全影响。