基于隐式模式的输入验证漏洞挖掘技术研究

2018-10-18 06:21◎侯
三门峡职业技术学院学报 2018年3期
关键词:控制流事务语句

◎侯 枫 赵 倩

(三门峡职业技术学院 信息传媒学院,河南 三门峡 472000)

Android应用程序输入接口,只提供静态权限检查保护机制,不进行输入验证。若防范措施不严密,容易导致混淆代理漏洞(Confused Deputy Attack)和拒绝服务漏洞。如何挖掘Android环境下输入验证漏洞是笔者主要讨论的问题。

目前输入验证漏洞挖掘通过先验知识,预定义某特定类型漏洞模式,通过模式匹配在执行代码上进行漏洞挖掘[1]。挖掘输入验证漏洞难点是难以给出漏洞通用模式。为更好检测与程序逻辑相关漏洞,破解难点,笔者提出针对Android应用输入验证漏洞基于源代码分析静态挖掘方案。方案使用后向程序切片算法在控制流图上提取事务切片和约束切片,通过频繁模式挖掘获得切片级隐式安全规范,验证规范并将违规现象报告为可疑漏洞,根据收集的路径约束条件推断输入取值范围,自动化生成测试用例并在虚拟机上半自动的验证漏洞报告。

1 输入验证漏洞建模

传统的漏洞挖掘方案都是经过大量漏洞细节的人工分析,建立一个固定的漏洞模型,然后从代码实现中查找符合该漏洞模型的代码行为。由于无法对输入验证漏洞用一个统一标准漏洞模型描述,因此“漏洞建模-模型检测”的检测模式不甚理想。由于Android功能设计中代码存在大量重复片段,抽取重复片段的行为模式得到该程序应该遵守的规范,不符合规范行为即为可疑漏洞[2]。为能提取出此类行为模式,需对输入验证漏洞进行形式化的建模。

定义事务。事务(Transaction)是包含一个核心语句及其所有数据依赖语句的语句集合。从定义可以看出,事务具有原子性,整个事务是一个不可分割的功能片段,所有语句一起完成某个特定的功能。一个事务通常用最后一条语句明确执行某个功能,其他语句只是为该中心语句准备所需的数据。

事务通过一个四元组T<s,Ds,CS,Dv>定义,其中s是整个事务的核心语句,Ds是事务所有依赖语句集合,CS是事务所有约束集合,Dv是事务所有依赖变量集合。

形式化定义如下,其中REF(si)是语句si所有依赖变量,DEF(si)是语句si中被赋值变量:

●s=o.fun(p1,p2,...,pn)

●Ds={s1,s2,...,sn},s1,s2,...,sn是顺序执行的语句,sn就是核心功能语句 s,则对于(i∈[2,n]),存在 sj,j∈[1,i),DEF(sj)F(si)

●CS={cs1,cs2,...,csn},其中csi是事务T的约束(随后定义)

●Dv={v|v∈{o,p1,p2,...,pn}ⅴv∈REF(si),si∈Ds}

定义约束。约束(Constraint)是一个事务可以被顺利执行所需满足的一个路径条件语句,代表着对这个事务执行过程中变量或者环境的验证行为。一个事务通常会有多个约束,只有这些约束都得到满足的时候,一个事务才能执行完成。一个条件语句是一个事务约束的充要条件,是该约束在控制流图上到达该事务路径上的分支节点。

约束通过一个三元组T<s,Ds,Dv>定义,其中s是整个事务核心语句,Ds是事务所有依赖语句集合,Dv是事务所有依赖变量集合。形式化定义如下:

●s=o1.fun1(p1,p2,...,pn)relop o2.fun2(q1,q2,...,qn),relop是关系运算符

●Ds={s1,s2,...,sn},s1,s2,...sn是顺序执行的语句,sn就是约束条件语句s,则对于si(i∈[2,n]),存在sj,j∈[1,i),DEF(sj)REF(si)

●Dv={v|v∈{o,p1,p2,...,pn}ⅴ v∈REF(si),si∈ Ds}

定义输入验证漏洞。输入验证漏洞是一个事务缺少必要约束而导致。给定事务T<s,Ds,CS,Dv>和安全规范集合SR{s|sis necessary constraint},T存在输入验证漏洞。当且仅当:

从定义知,挖掘输入验证漏洞关键在于如何提取安全规范集合SR,及判定一个约束对于一个事务是否是必要的。为能从源代码中提取出事务和约束,使用后向程序切片技术(backward slicing)[3]细分程序逻辑,从某个程序点P出发,逆向遍历重构控制流图并收集所有和程序点P存在数据依赖关系的语句和分支谓词,进而提取事务切片和约束切片。

2 系统设计

通过预处理、程序切片、漏洞检测及漏洞验证设计基于隐式模式掘的漏洞挖掘流程。如图1所示。

2.1 预处理

对Java源代码进行解析,获取抽象语法树 (Abstract Syntax Tree)和控制流图、系统依赖图(System Dependence Graph)[4]。为方便精确分析数据流,将复杂语句变成三地址模式静态单赋值 (Static Single-Assignment)语句。每一条静态单赋值语句只给一个变量赋值一次,根据manifest.xml文件重构控制流图。

图1 基于隐式模式的漏洞挖掘流程

2.2 程序切片

利用后向切片技术,将某一安全敏感语句识别为切片中心语句,以它为起点,收集数据依赖语句作为事务切片。将路径分支语句识别为切片中心语句,通过程序切片技术获得约束切片。

2.3 漏洞检测

用事务切片和切片代表程序逻辑的抽象,在切片级别进行漏洞检测。首先,依据中心语句不同将事务切片进行分类;提取同一类事务中出现频繁的约束切片为隐式安全规范,并应用到该类事务中,不满足规范切片识别为可疑安全漏洞。

2.4 漏洞验证

通过半自动漏洞验证模块对原始漏洞报告进行验证。在一台Android虚拟机上验证简单输入漏洞;对于复杂漏洞,输入求解过程结果不理想,但一定程度上能辅助人工分析并生成最终报告,报告中包含受影响的切片和修复方案。

3 系统实现

在系统设计基础上实现基于隐式模式的漏洞挖掘各个模块细节。

3.1 预处理

在实现系统设计中预处理功能外,需增加针对异常抛出Assert语句和Service Hook API的处理,以方便收集更多种类约束。

Assert语句。Java语言中Assert语句是断言式语句,帮助开发者动态验证特定程序点是否满足预设条件[5]。若不满足,Assert语句抛出AssertionError异常,Catch语句捕获异常,否则控制流直接结束函数或程序。为处理该情况,将Assert语句条件表达式转变为IF语句,使其成为后续所有语句的隐式约束。

Service Hook API。Service HookAPI用于动态细粒度验证访问者权限,用于保护某个Service组件方法。在调用时检查调用者权限,权限不够则抛出异常。Service Hook作为静态权限机制补充,需将其识别为约束,处理方法同Assert语句。

3.2 程序切片

程序切片采用的提取算法,能同时提取事务切片和约束切片。算法思路是从函数最后一条语句(通常是return语句)开始,逆向遍历控制流图,将所有安全敏感函数调用语句识别为切片中心语句,利用后向切片算法提取事务切片。从安全敏感函数调用语句开始,逆向遍历控制流图,收集所有数据依赖,直到控制流图入口点止。获得包含一个切片中心语句和所有数据依赖语句的完整事务切片。

带着这样的问题,我梳理了自己30年的语文教学,研究了于漪、钱梦龙等一大批语文教学名家的教育实践,尤其是他们的课堂教学,惊喜地发现:新课改从理念到实践,不是凭空而来的,也不像有些人所理解的是从西方引进的(其他学科或许可以引进,但母语教学是不能引进的),而是在继承中发展的。新课程的很多理念在这一批教育名家的课堂上早就有了充分的体现。

切片示例:图2是从函数stk.BootCompletedReceiver.onReceive()中提取事务切片和所有相关约束切片。第4条语句是敏感API context.startService(),该API启动组件间通信service组件。本示例列出该事务切片包含的1条约束,该约束检查action变量是否等于某个确定值,而其数据依赖关系最后都指向输入函数参数(即 Intent)。

图2 事务切片和约束切片示例

3.3 漏洞检测

从程序切片中提取隐式安全规范是破解预先不能提供统一漏洞模式和安全规范的有效算法。通过事务分类、提取隐式安全规范和验证安全规范等流程将提取事务切片按切片中心语句是否相等划分为不同类别,频繁挖掘各事务类别所有约束切片,在满足安全规范的事务类别中检测可疑违规行为。如果某事务切片缺少某相关联安全规范,认为该事务切片存在可疑漏洞。

3.3.1 事务分类

相似事务具有相似约束,先利用切片中心语句的相等性对事务切片进行分类。给定两个事务切片中心语句o_1.fun_1(p_1,p_2,…,p_n)和o_2.fun_2(q_1,q_2,…,q_n),两个中心语句相等条件是o1和o2实例化自同一个类或继承自同一个父类的两个子类,且两个函数名相等,参数也相同。

形式化定义如下:给定o1的类O1,o2的类O2,符号“<”代表类的继承关系,px的类Px和qx的类Qx,那么

这里将Android组件间通信API族(startActivity(),startService(),sendBroadcast()等)统一识别为相等切片中心语句[6]。

3.3.2 提取隐式安全规范

抽取该事务类别所有约束切片,汇总到约束切片集合中,提取多于N次出现的约束切片作为安全规范。采用约束切片中心语句相等性代表约束切片相等性,给定两个约束切片中心语句o1.fun1(...)relop o2.fun2(...)和 o1’.xfun1’(...)relop’o2’.fun2’(...)其中 relop 是关系运算符(<,<=,=,<>,>,>=等),o.fun(...)为 Null,或者 relop和o2.fun2(...)均为空,这样所有约束切片语句可化成如上形式。

注意,为尽量收集更多约束信息,约束切片出现频数N的阈值设为1,会导致一定程度提高误报率,若提高阈值会降低误报率,但会升高漏报率。综合考虑选择阈值为1。

利用已提取安全规范验证事务分类中规范并检测可疑违规行为[7]。如果一个事务和一个安全规范存在相关性,该事务约束切片不包含该安全规范,那么该事务由于缺失该安全规范存在安全漏洞。检测事务和安全规范相关性的判定标准是:变量数据类型是判定两个依赖变量集相等性的根据,当一个事务依赖变量集(Dependence Variables)包含提取安全规范的依赖变量集时,认为该事务和安全规范存在相关性。如一个事务依赖变量集为 {Intent,Message,SmsMessage,Context},安全规范依赖变量集为{Context,Intent,String,int},去掉基础类型后,由于{Context,Intent}?{Intent,Message,SmsMessage,Context},那么就认为该安全规范与该事务是相关的。

3.4 漏洞验证

由于输入验证漏洞敏感API不一定是系统API,对它调用不经过ActivityManagerService仲裁,所以不能完备监控此类调用。因此,设计一个自动化漏洞验证模块,选择使用静态插桩方法监控API调用。如图3所示,使用Soot修改目标APK二进制代码,插入一条新语句在被关注API调用语句前,记录API调用信息和上下文信息到系统日志中,重新打包APK并安装到Android虚拟机或物理机中。

同时使用简单约束求解器推断输入,利用代码发送到目标Android机器中,再使用logcat监控系统日志,发现API调用信息或者app崩溃信息及时记录,并输出验证报告。如果监控到预期行为,将该可疑漏洞标记为“Confirmed Vul”,否则标记为“False Alarm”。如果不存在可执行文件(.apk)或漏洞输入条件无法求得,那么将其标记为“Unconfirmed Alarm”。

图3 基于静态插桩的漏洞验证

4 实验结果及分析

选取packages/apps和packages/providers中应用源码在不同版本Android原生系统进行测试,测试集详情见表1。

表1 测试集汇总

在App上应用算法得到相应可疑漏洞报告,通过人工审核源代码并编写利用代码的方式来验证这些漏洞。验证结果见表2。其中列“Apps”是存在漏洞app包名,列“Vulnerable Component”是存在该漏洞组件名,×表示该版本不存在App(NFC功能在Android2.3之后才引入),表示无漏洞。

实验表明,设计工具共检测到36个未公开输入验证漏洞,均为拒绝服务漏洞,这些漏洞通过合适场景能造成严重破坏;Android版本迭代更新若干年,拒绝服务漏洞数量细微变化造成的损失并没有引起程序员足够重视。

表2 检测到的输入验证漏洞

5 结语

为检测和程序逻辑相关、难以提取统一模式输入验证漏洞,本文提出基于隐式模式挖掘,用于发现源代码中隐含安全规范并检测漏洞。该技术应用后向程序切片技术提取程序逻辑,抽取独立功能代码片段为一个事务切片,抽取一个路径约束条件和相关语句代码片段为一个约束切片,在切片级别上进行事务切片分类,在类别内采用频繁模式挖掘,提取隐式安全规范检测漏洞。在Android2.2、4.0.3、4.4.2和5.0等版本上实现一个原型系统,检测出36个拒绝服务漏洞,充分验证该方案不仅能从源代码中有效提取隐式安全规范并挖掘漏洞,同时通过自动化样本生成和自动化验证显著降低误报率。

猜你喜欢
控制流事务语句
基于分布式事务的门架数据处理系统设计与实现
抵御控制流分析的Python 程序混淆算法
工控系统中PLC安全漏洞及控制流完整性研究
抵御控制流分析的程序混淆算法
重点:语句衔接
河湖事务
基于控制流隐藏的代码迷惑
如何搞定语句衔接题
SQLServer自治事务实现方案探析
移动实时环境下的数据一致性研究