漏洞挖掘场景下的污点分析技术分析

1、污点分析基本原理

污点分析是一个泛概念,它在不同的应用领域都可以发挥良好的作用,本文的讨论重点将聚焦在“面向自动化漏洞挖掘的污点追踪技术”,以漏洞挖掘fuzz这个场景为着眼点,详细阐述污点跟踪与分析的概念。

0x1:污点分析定义

污点分析可以抽象成一个三元组<sources,sinks,processor>的形式,其中

  • source 即污点源,代表直接引入不受信任的数据或者机密数据到系统中
  • sink 即污点汇聚点,代表直接产生安全敏感操作(违反数据完整性)或者泄露隐私数据到外界(违反数据保密性)
  • processor 即数据流处理,代表整个数据传输和处理的过程(例如加密、编码处理),外部输入的数据经过processor处理后会得到一个适合软件核心模块处理的数据形式.

污点分析就是分析程序中由污点源引入的数据,在经过数据流处理后,传播到污点汇聚点后,是否符合预设的策略。这里的策略是一个泛概念,例如:

  • 污点直接被传入了危险的函数中(例如eval)
  • 污点未经编码和转义处理,传入了输出函数中(例如xss漏洞)

在漏洞挖掘中,processor往往指代一个“无害化处理模块”,例如html转义等。

0x2:识别污点源和汇聚点

识别污点源和污点汇聚点是污点分析的前提。目前,在不同的应用程序中识别污点源和汇聚点的方法各不相同,这其实是一个泛概念,在不同的场景下,污点源和汇聚点污点分析会表现出不同的形式,这里的场景例如:

  • 不同的系统模型
  • 编程语言之间的差异
  • 待跟踪分析的对象的差异

以 Web 应用程序漏洞检测为例,污点源及其关键属性如下:

 

对于污点汇聚点来说,可以从概念上大致分为3类:

  • 使用启发式的策略进行标记。例如在webshell检测中,将来自程序外部输入的数据统称为“污点”数据,保守地认为这些数据有可能包含恶意的攻击数据 
  • 根据具体应用程序调用的 API 或者重要的数据类型,手工标记源和汇聚点。例如在webshell检测中,将file_get_contents这一类危险函数的执行结果标记为污点,继续后续的跟踪
  • 使用统计或机器学习技术自动地识别和标记污点源及汇聚点.

0x3:污点传播分析

讨论完污点源和汇聚点污点分析之后,我们来讨论污点传播分析。

污点传播分析就是分析污点标记数据在程序中的传播途径。按照分析过程中关注的程序依赖关系的不同, 可以将污点传播分析分为以下两种:

  • 显式流分析
  • 隐式流分析

1、显式流分析

污点传播分析中的显式流分析就是分析污点标记如何随程序中变量之间的【数据依赖关系】传播

以上图所示的程序为例,变量 a 和 b 被预定义的污点源函数 source 标记为污点源。

假设 a 和 b 被赋予的污点标记分别为taint_a 和 taint_b。

由于第 5 行的变量 x 直接数据依赖于变量 a,第 6 行的变量 y 直接数据依赖于变量 b,显式流分析会分别将污点标记 taint_a 和 taint_b 传播给第 5 行的变量 x 和第 6 行的变量 y。

又由于 x 和 y 分别可以到达第 7 行和第 8 行的污点汇聚点,在污点汇聚点,我们就可以按照预设的策略得出结论,例如上图所示的代码存在的信息泄漏问题。 

2、隐式流分析

污点传播分析中的隐式流分析是分析污点标记如何随程序中变量之间的【控制依赖关系】传播,也就是分析污点标记如何从条件指令传播到其所控制的语句

在上图所示的程序中,变量 X 是被污点标记的字符串类型变量,变量 Y 和变量 X 之间并没有直接或间接的数据依赖关系(显式流关系),但 X 上的污点标记可以经过控制依赖隐式地传播到 Y。

具体来说,由第 4 行的循环条件控制的外层循环顺序地取出 X 中的每一个字符,转化成整型后赋给变量 x,再由第 7 行的循环条件控制的内层循环以累加的方式将 x 的值赋给 y,最后由外层循环将 y 逐一传给 Y。

最终,第 12 行的 Y 值和 X 值相同,程序存在信息泄漏问题。

但是,如果不进行隐式流污点传播分析,第 12 行 的变量 Y 将不会被赋予污点标记,程序的信息泄漏问题被掩盖。

3、欠污染和过污染问题

隐式流污点传播一直以来都是一个重要的问题,和显式流一样,如果不被正确处理,会使污点分析的结果不精确。

  • 由于对隐式流污点传播处理不当导致本应被标记的变量没有被标记的问题称为欠污染(under-taint)问题
  • 由于污点标记的数量过多而导致污点变量大量扩散的问题称为过污染(over-taint)问题

欠污染和过污染问题,都会导致在汇聚点污点检测的时候产生误报或者漏报,这也是目前隐式流问题研究的重点。

0x4:无害处理

污点数据在传播的过程中可能会经过无害处理模块,无害处理模块是指污点数据经过该模块的处理后,数据本身不再携带敏感信息或者针对该数据的操作不会再对系统产生危害。换言之,带污点标记的数据在经过无害处理模块后,污点标记可以被移除。

正确地使用无害处理可以降低系统中污点标记的数量,提高污点分析的效率,并且避免由于污点扩散导致的分析结果不精确的问题。

1、加密处理

在应用代码开发过程中,为了防止敏感数据被泄露(保护保密性),开发者通常会对敏感数据进行加密处理。此时,加密库函数应该被识别成无害处理模块。这一方面是由于库函数中使用了大量的加密算法,导致攻击者很难有效地计算出密码的可能范围。另一方面是加密后的数据不再具有威胁性,继续传播污点标记没有意义。

2、输入验证

此外,为了防止外界数据因为携带危险操作而对系统关键区域产生危害(保护完整性),通常会对输入的数据进行验证。此时,输入验证(input validation)模块应当被识别成无害处理模块。

3、输入转义

例如,为了防止代码注入漏洞,PHP 提供的 htmlentities 函数可以将特殊含义的 HTML 字符串转化成HTML实体(例如,将’<’转化成’<’)。输入字符串经过上述转化后不会再携带可能产生危害的代码,可以安全地发送给用户浏览器渲染。

一些开源系统(例如owasp)还提供了额外的输入验证工具,比如ScriptGard、CSAS、XSS Auditor、Bek,这些工具也应被识别成无害处理模块。

Relevant Link:     

https://github.com/Z3Prover/z3
https://rise4fun.com/z3/tutorial/guide

 

2. 污点传播分析中的流追踪原理分析 

污点传播分析是当前污点分析领域的研究重点。与程序分析技术相结合,可以获得更加高效、精确的污点分析结果。

根据分析过程中是否需要运行程序,可以将污点传播分析分为:

  • 静态污点分析
  • 动态污点分析

本节主要讨论如何使用动/静态程序分析技术来解决污点传播中的显式流分析和隐式流分析问题。

0x1:污点传播中的显式流分析

1、静态分析技术解决显式流分析问题

静态污点传播分析(简称静态污点分析)是指在不运行且不修改代码的前提下,通过分析程序变量间的数据依赖关系来检测数据能否从污点源传播到污点汇聚点。

静态污点分析的对象一般是程序的源码或中间表示。可以将对污点传播中显式流的静态分析问题转化为对程序中静态数据依赖的分析:

  • 首先,根据程序中的函数调用关系构建调用图(call graph,简称CG)
  • 然后,在函数内或者函数间根据不同的程序特性进行具体的数据流传播分析。常见的显式流污点传播方式包括:
    • 直接赋值传播
    • 通过函数(过程)调用传播
    • 通过别名(指针)传播

以下图所示的 Java 程度为例:

第 3 行的变量 b 为初始的污点标记变量,程序第 4 行将一个包含变量 b 的算术表达式的计算结果直接赋给变量 c。由于变量 c 和变量 b 之间具有直接的赋值关系,污点标记可直接从赋值语句右部的变量传播到左部,也就是显式流污点传播方式中的直接赋值传播。

接下来,变量 c 被作为实参传递给程序第 5 行的函数 foo,c 上的污点标记也通过函数调用传播到 foo 的形参 z,z 的污点标记又通过直接赋值传播到程序第 8 行的 x.f。由于 foo 的另外两个参数对象 x 和 y 都是对对象 a 的引用,二者之间存在别名,因此,x.f的污点标记可以通过别名传播到第 9 行的污点汇聚点,程序存在泄漏问题。

2、静态分析技术的主要研究问题

目前,利用数据流分析解决显式污点传播分析中的直接赋值传播和函数调用传播已经相当成熟,研究的重点是如何为别名传播的分析提供更精确、高效的解决方案。

由于精确度越高(上下文敏感、流敏感、域敏感、对象敏感等)的程序静态分析技术往往伴随着越大的时空开销,追求全敏感且高效的别名分析难度较大。又由于静态污点传播分析关注的是从污点源到污点汇聚点之间的数据流关系,分析对象并非完整的程序,而是确定的入口和出口之间的程序片段。这就意味着可以尝试采用按需(on-demand)定制的别名分析方法来解决显式流态污点分析中的别名传播问题。

3、动态分析技术解决显式流分析问题

动态污点传播分析(简称动态污点分析)是指在程序运行过程中,通过实时监控程序的污点数据在系统程序(例如zend沙箱)中的传播来检测数据能否从污点源传播到污点汇聚点。

动态污点传播分析首先需要为污点数据扩展一个污点标记(tainted tag)的标签并将其存储在存储单元(内存、寄存器、缓存等)中,然后根据指令类型和指令操作数设计相应的传播逻辑,传播污点标记.

动态污点传播分析按照实现层次被分为基于硬件、基于软件、以及混合型的污点传播分析这3类。

1)硬件

基于硬件的污点传播分析需要定制的硬件支持,一般需要在原有体系结构上为寄存器或者内存扩展一个标记位,用来存储污点标记,代表的系统有 Minos、Raksha等。

2)基于软件

基于软件的污点传播分析通过修改程序的二进制代码来进行污点标记位的存储与传播,代表的系统有 TaintEraser、TaintDroid等。

基于软件的污点传播的优点在于不必更改处理器等底层的硬件,并且可以支持更高的语义逻辑的安全策略(利用其更贴近源程序层次的特点),但缺点是使用插桩(instrumentation,在保证被测程序原有逻辑完整性的基础上在程序中插入一些探针)技术,或代码重写(code rewriting)技术,修改程序往往会给分析系统带来巨大的开销。

相反地,基于硬件的污点传播分析虽然可以利用定制硬件降低开销,但通常不能支持更高的语义逻辑的安全策略,并且需要对处理器结构进行重新设计。

3)混合型

混合型的污点分析是对上述两类方法的折中,即通过尽可能少的硬件结构改动以保证更高的语义逻辑的安全策略,代表的系统有 Flexitaint、PIFT等。

4、动态分析技术的主要研究问题

目前,针对动态污点传播分析的研究工作关注的首要问题是如何设计有效的污点传播逻辑,以确保精确的污点传播分析

动态污点传播分析的另一个研究重点是如何降低分析代价

如前所述,传统的基于硬件的动态污点传播分析技术需要定制硬件的支持,而基于软件的技术由于程序插桩或代码重写会带来额外的性能开销。

为控制分析代价,一类研究工作采用的思路是有选择地对系统中的指令进行污点传播分析。例如,

  • LIFT提出的快速路径(fast-path)优化技术通过提前判断一个模块的输入和输出是否是具有威胁,如果没有威胁,则无需进行污点传播。以此来降低需要重写的代码的数量
  • 合并检查(merged check)优化技术将多个基本块合并成 1个进行检查,以降低检查次数

快速切换(fast switch)优化利用活性分析消除一些之后不活跃的条件寄存器的 save 和 restore 操作,以减少需要分析的指令数量。

PIFT系统提出了基于预测的污点跟踪(传播)方式,他们设计统计实验观察到CPU 指令流中 load 和 store 指令存在一些特殊性质,例如:

  • load 指令与其子序列中 store 指令距离接近
  • load 指令之后的 store 指令个数不多
  • 连续的 load 指令之间的距离是均匀的

基于此,提出了基于预测的只跟踪 load 和 store指令的策略,即:如果load指令的操作数是污点数据,那么将其一定距离内的store指令的目的地址标记成污点数据。该方法减少了跟踪其他复杂CPU指令的开销。

另外一类降低分析代价的思路是,使用低开销的机制代替高开销机制

例如,SHIFT将动态污点分析转化成延迟例外(deferred exceptions)处理的问题。

延迟例外是指在例外发生后,将例外标记在相关的指令中,之后再通过检测指令检测出被标记指令中的例外并处理例外,这种机制与污点标记传播的机制类似。

SHIFT将污点传播分析实现在支持投机执行(speculative execution)的处理器中,既不需要改变计算机处理器本身,又可以充分利用该处理器高速处理延迟例外的优势,从而达到降低动态污点分析开销的效果。

0x2:污点传播中的隐式流分析

污点传播分析中的隐式流分析就是分析污点数据如何通过控制依赖进行传播,如果忽略了对隐式流污点传播的分析,则会导致欠污染的情况。如果对隐式流分析不当,那么除了欠污染之外,还可能出现过污染的情况。

与显式流分析类似,隐式流分析技术同样也可以分为静态分析和动态分析两类。

1、静态分析技术解决隐式流分析问题

静态隐式流分析面临的核心问题是精度与效率不可兼得的问题

精确的隐式流污点传播分析需要分析每一个分支控制条件是否需要传播污点标记。但是路径敏感的数据流分析往往会产生路径爆炸问题,导致开销难以接受。

为了降低开销,一种简单的静态传播(标记)分支语句的污点标记方法是将控制依赖于它的语句全部进行污点标记(暴力分支穷举),但该方法会导致一些并不携带隐私数据的变量被标记,导致过污染情况的发生。

过污染会引起污点的大量扩散,最终导致用户得到的报告中信息过多,难以使用。

2、动态分析技术解决隐式流分析问题

动态隐式流分析关注的首要问题是如何确定污点控制条件下需要标记的语句的范围

由于动态执行轨迹并不能反映出被执行的指令之间的控制依赖关系,目前的研究多采用离线的静态分析,辅助判断动态污点传播中的隐式流标记范围。

Clause等人提出,利用离线静态分析,得到控制流图节点间的后支配(post-dominate)关系,来解决动态污点传播中的隐式流标记问题。

例如,如下图所示,

程序第 3 行的分支语句被标记为污点源,当document.cookie 的值为 abc 时,会发生污点数据泄露。

根据基于后支配关系的标记算法,会对该示例第 4 行语句的指令目的地,即 x 的值进行污点标记。

动态分析面临的第 2 个问题是由于部分泄漏(partially leaked)导致的漏报。部分泄漏是指污点信息通过动态未执行部分进行传播并泄漏

Vogt等人发现,只动态地标记分支条件下的语句会发生这种情况。

仍以下图左边为例:

当第 3 行的控制条件被执行时,对应的 x 会被标记。此时,x 的值为 true,而 y 值没有变化,仍然为 false。

在后续执行过程中,由于第 9行的污点汇聚点不可达,而第 12 行的汇聚点可达,动态分析没有检测到污点数据泄漏。

但攻击者由第 11 行 y 等于 false 的条件能够反推出程序执行了第 3 行的分支条件,程序实际上存在信息泄漏的问题。

这个信息泄露是由第 6 行未被执行到的 y 的赋值语句所触发的。因此,y 应该被动态污点传播分析所标记。为了解决部分泄漏问题,Vogt等人在传统的动态污点分析基础上增加了离线的静态分析,以跟踪动态执行过程中的控制依赖关系,对污点分支控制范围内的所有赋值语句中的变量都进行标记。

具体到上图所示的例子,就是第 4 行和第 6 行中的变量均会被污点标记。但是要注意的是,这种方法可能会产生过污染的情况。

动态分析需要解决的第 3 个问题是如何选择合适的污点标记分支进行污点传播

鉴于单纯地将所有包含污点标记的分支进行传播会导致过污染的情况,可以根据信息泄漏范围的不同,定量地设计污点标记分支的选择策略。

以下图右边所示的程序为例,

第 2 行的变量 a 为初始的污点标记变量。

第 5 行、第 7 行、第 9 行均为以 a作为源操作数的污点标记的分支。

如果传播策略为只要分支指令中包含污点标记就对其进行传播,那么第 5 行、第 7 行、第 9 行将分别被传播给第 6 行、第 8 行、第 10 行,并最终传播到第 12 行的污点汇聚点。

如果对这段程序进行深入分析会发现,3个分支条件所提供的信息值(所能泄露的信息范围)并不相同,分别是

  • a 等于 10
  • a 大于 10 且小于或等于 13(将 w 值代入计算)
  • a 小于 10

对于 a 等于 10 的情况,攻击者可以根据第 12 行泄漏的 x 的值直接还原出污点源处 a 的值(这类分支也被称为能够保存完整信息的分支)。

对于 a 大于 10 且小于或等于 13 的情况,攻击者也只需要尝试 3 次就可以还原信息。

而对于 a 小于 10 的情况,攻击者所获得的不确定性较大,成功还原信息的几率显著低于前两种,对该分支进行污点传播的实际意义不大。

Bao等人只将严格控制依赖(strict control dependence)识别成需要污点传播的分支,其中,严格控制依赖即分支条件表达式的两端具有常数差异的分支。但是,Bao 的方法只适用于能够在编译阶段计算出常数差异的分支。

Kang 等人提出的 DTA++ 工具使用基于离线执行踪迹(trace)的符号执行的方法来寻找进行污点传播的分支,但该方法只关注信息被完整保存的分支,即图中第 5 行的 a==10 会被选择污点传播,但是信息仍然能够通过另一个范围(第 7 行的分支)而泄露。

Cox 等人提出的 SpanDex 的主要思想是:动态地获得控制分支中污点数据的范围,根据数据的更改以及数据间的依赖关系构建一个基于操作的有向无环图(OP-DAG),再结合一个在线的约束求解器(CSP solver)确定隐式流中传播的隐私数据值的范围,通过预先设定的阈值,选择是否对数据进行污点传播。该方法对图中所示例子中的第 5 行、第 7行的分支进行污点传播。但是目前,该方法只能求解密码字符的范围,暂不支持对复杂操作(位、除法、数组等操作)的求解。

Relevant Link:

https://github.com/gmu-swe/phosphor
http://www.jsjkx.com/CN/article/openArticlePDF.jsp?id=224 
https://www.k0rz3n.com/2019/03/01/%E7%AE%80%E5%8D%95%E7%90%86%E8%A7%A3%E6%B1%A1%E7%82%B9%E5%88%86%E6%9E%90%E6%8A%80%E6%9C%AF/

 

posted @ 2020-06-03 17:23  郑瀚Andrew  阅读(5393)  评论(0编辑  收藏  举报