会议论文分享-Security22-状态感知符号执行
Ferry: State-Aware Symbolic Execution for Exploring State-Dependent Program Paths
- 1.引言
- 2.问题陈述与分析
- 2.1.实现状态感知符号执行的挑战
- 2.2.真实程序的特征
- 2.3.Ferry的模型
- 2.3.1.程序状态的定义
- 2.3.2.状态描述变量的特征
- 3.Design
- 3.1.Overview of Ferry
- 3.2.状态描述变量识别
- 3.3.状态感知符号执行
- 4.算法
- 5.针对复杂真实程序的优化
- 5.1.移除闲置状态依赖变量
- 5.2.带有输入分区的快捷符号执行(SSE)
- 6.实验
- 6.1.覆盖率测试
- 6.2.状态依赖漏洞测试
- 6.3.深度状态探索
- 6.4.推断的SDVO准确率
- 6.5.Case study
- 6.6.性能baseline
- 6.7.Discussion
- 七.参考文献
1.引言
现有的符号执行方法和工具在程序实现的有限状态机模型中探索程序状态相关分支的能力非常有限。图1示例代码实现了一个状态机来解析视频输入。
现有技术的方法可以有效地探索第 666 行的分支,因为 box_type
的值在每轮循环都会重新从输入无条件加载。
然而,为了便于实现带状态的程序逻辑,真实世界的程序使用某些变量来存储程序的内部状态,条件语句可能依赖于内部状态而不是当前的程序输入。比如第 999 行条件取决于变量 saved_size
的值。
-
假如第一次循环进入了
encode("tx3g")
分支,那么此时saved_size
并没有被重新赋值,为 −1-1−1。 -
对
saved_size
的赋值在encode("trak")
分支中,即encode("trak")
分支的执行对encode("tx3g")
。
因此,作者将 saved_size
这种变量称之为state-describing variable(状态描述变量)。对于条件语句保护的分支,如果条件语句依赖于这些state-describing variable,那么这些分支称为state-dependent branches(状态依赖分支)。
示例第 161616 和 181818 行可能分别触发整数溢出和缓冲区溢出漏洞。在默认情况(saved_size = -1
)下漏洞并不会被触发。而在示例输入中:
-
示例输入序列由2个输入组成,每轮循环处理1个输入,每个输入在概念上都是一个data box。每个data box包含必要的元数据
box_size
和box_type
,分别描述其大小和类型,同时data box还包含可选的有效负载数据(负载在示例中没有提到)。 -
该程序实现了一个循环,在循环的不同迭代过程中,data box被依次处理。
-
第1轮循环对应
box_type
为trak
,box_size
为8,那么saved_size
被设置为8。 -
第2轮循环对应
box_type
为tx3g
,box_size
为0xFFFFFFF8
,此时saved_size
为正数,size
被设置为8。第 161616 行size + box_size
的值超过32位整数上限,发生溢出。
-
这种状态感知的程序逻辑打破了SOTA方法的假设。即程序独立地处理来自单个文件的输入的每个部分,并且可以忽略早期输入导致的状态变化对后期输入处理方式的影响。但是许多真实环境程序都包括了状态依赖分支,下表列出的程序包含数十甚至数百个状态依赖分支。
状态依赖分支会从2个方面降低路径搜索的效率:
-
由于缺乏对内部程序状态的了解,现有的方法无法生成探索大量程序状态的所需程序输入,导致对状态依赖分支的探索非常有限。
-
一个程序语句在不同的程序状态下可以有不同的行为(例如,在示例中,第16行默认情况下是不会触发溢出的,只有在程序状态发生变化时才会暴露漏洞),这意味着仅仅访问1次状态依赖分支是不够的。相反,应该在不同的程序状态下对它们进行全面检查。这就需要一种新的衡量标准来评估现有工具的状态探测能力。
为了解决上述问题,作者提出了状态感知(state-aware,我也不知道aware怎么翻译比较好)的符号执行框架ferry,ferry会自动识别状态描述变量,并使用它们引导符号执行和探索状态依赖分支。同时,作者根据ferry在测试真实环境程序遇到的困难提出了数种策略优化ferry以提高其效率和可扩展性。
2.问题陈述与分析
符号执行引擎的一个主要障碍是不了解程序的内部状态,这会导致对状态依赖分支的低效探索。对于图1中的示例,在忽略被注释的其它分支的情况下每轮循环存在3个不同的路径:
-
case encode("tx3g")
+saved_size < 0
-
case encode("tx3g")
+saved_size >= 0
-
case encode("trak")
但是对于符号执行,该示例可能有无限数量的符号状态,比如循环次数小于 m
的符号状态数最多包括 3∗(1+...+m)3 * (1 + ... + m)3∗(1+...+m)。其中就包括了循环 m
次每次都走 case encode("tx3g")
这个分支,那么 saved_size
一直没被重新赋值,这样的状态显然是无意义的且应该被修剪掉。
示例展示了一个简单的情况,真实环境中一个程序可能包含上千个状态依赖分支,且可能更复杂有嵌套情况。
2.1.实现状态感知符号执行的挑战
-
挑战1,程序状态推理:最关键的问题是如何推断给定程序的内部状态,不同于操作系统的状态,这些状态有充分的文档记录。通常情况下,应用程序的状态与它的实现有关,并且没有明确的规约。由于程序通常使用特定变量(即状态描述变量)跟踪其状态,通过识别状态描述变量可以推断程序状态。不幸的是,由于状态描述变量和无关变量之间的语义或结构差异很小,因此识别这些变量本身就是一个挑战。
-
挑战2,运行时程序状态识别:就算识别出程序中的状态描述变量,也很难确定当前状态是否被探索过(推测是指当前状态是否重复)。
2.2.真实程序的特征
作者对具有状态依赖分支的真实程序进行了调查,以了解其特征。具体来说,作者手动分析了AFL分析过的106个程序。结果显示91个有至少1个状态依赖分支。包含状态相关分支的程序被广泛用作软件系统的各个方面的基本组件,从网络数据传输到多媒体数据处理。更重要的是,它们中的许多是大型项目和系统的基石。例如,Chromium项目由几个具有状态依赖分支的库提供支持,包括libpng和libtiff。它们的特征被总结如下:
-
C1:它们从单个输入源接收一系列输入,输入源可以是1个
socket
或者1个文件。 -
C2:它们按顺序依次处理输入。这些程序不是一次处理整个输入序列,而是一次处理一个输入(在输入序列中)。图1是一个典型的示例,它包含一个输入处理循环,用于从文件中连续读取数据。在循环的当前迭代中处理的输入被称为当前输入(
current input
),而在先前迭代中处理过的输入被称作早期输入(early input
)。 -
C3:它们用一个或多个状态描述变量来维护程序状态。当状态描述变量的值与这些输入之间存在数据依赖时,程序状态会受到一些早期输入的影响。这些变量通过影响某些条件语句的分支来进一步改变程序行为。
作者没有试图有效地分析任何具有内部状态的程序,而是在本文中将目标程序的范围明确定义为具有上述三个特征的真实世界程序。
本文解决的问题就是对于具有上述特征的程序,如何解决第2.1节中的挑战,以便有效地探索依赖于状态的分支,如图1所示的分支?
2.3.Ferry的模型
2.3.1.程序状态的定义
程序中的状态可以由下列特征描述:
-
状态由一组状态描述变量描述。
-
当两个状态不同时,至少一个状态描述变量具有不同的值。
-
程序在不同状态下具有不同的行为(即采取不同的分支方向)。
自动识别状态描述变量是一项具有挑战性的任务。作者应对这一挑战的解决方案基于分析程序的特性:如第2.2节所述,每个程序都有一个外部数据源,它以这样的方式决定程序的执行,即早期输入可以影响某些状态描述变量的值,其进一步确定在处理当前输入时对某些条件语句采取的分支。
在执行期间,程序状态在处理输入序列期间发生变化。在本文中,作者将相关的状态变化事件分为三类:
-
一个新的状态描述变量被初始化。
-
某个状态描述变量的值被更改,这意味着它被分配了不同的值或其符号表达式的数据约束被更改。
-
一个状态描述变量被释放。
具体来说,输入序列对运行时程序状态的影响可以通过以下定义来具体指明:
-
首先,作者将把输入序列的一部分加载到存储单元的指令定义为输入加载指令(input loading instruction,图1中的
read_box_size()
和read_box_type()
就是这样的指令)。 -
其次,作者将初始化、释放或修改状态描述变量的值或数据约束的指令称为状态描述变量操作(state-describing variable operation,SDVO)指令。根据定义,执行SDVO指令肯定会导致状态转换。这里的修改并不局限于赋值操作,状态描述变量的约束条件变了也算修改。
-
第三,作者定义SDVO指令和输入加载指令之间的数据依赖关系如下:每当状态描述与输入加载指令间存在数据依赖关系时,作者称对应的SDVO指令数据依赖于输入加载指令。实现上,作者通过动态污点跟踪来捕获这种依赖关系。
被分析程序的一个内在特征是SDVO指令和输入加载指令之间广泛存在数据依赖性。Ferry利用这一特性来识别状态描述变量。
2.3.2.状态描述变量的特征
状态描述变量具有以下两个特征:
-
状态描述变量显式/隐式数据依赖于输入。
-
至少在一个条件分支语句中检查状态描述变量。
尽管作者的方法直接利用了第2.2节中确定的三个特征,但这项技术可能适用于具有上述特征的所有程序,这意味着:
-
对于基本状态描述变量的子集,其SDVO指令是数据依赖于至少一个输入加载指令。
-
如果状态描述变量的内容不同(即值不同),程序可能采取不同的分支来进行不同的行为。
3.Design
3.1.Overview of Ferry
框架整体概览如图2所示:
-
首先,基于状态描述变量和程序输入之间存在数据依赖性的insight,Ferry监控给定程序的执行,并识别状态描述变量。
-
其次,Ferry识别运行时程序状态,并驱动符号执行来探索大量程序状态。
-
此外,作者观察到真实世界程序的复杂性会影响Ferry的有效性。基于这一insight,作者的第三步通过引入两个优化进一步提高Ferry效率:缩减拥有闲置状态描述变量的状态(state-reduction of inactive state-describing variables)和快捷符号执行(shortcut symbolic execution)。
3.2.状态描述变量识别
在第2.3节中,作者确定了状态描述变量的两个特征,即它们数据依赖于输入(这个特征在以下段落中记为 InputDetermined
),并且它们在至少在一个条件语句(这个特征记为 BranchRelated
)中被检查,具有这些特征的变量是状态描述变量。
值得注意的是,变量的这些特征是全局的(不同状态共享),这意味着如果一个变量在一个执行路径中标记为 InputDetermined
,而在另一个执行路径中标记为 BranchRelated
,那么可以将其标记为状态描述变量。
状态描述变量的识别过程如下:
-
首先,作者应用动态污点分析从外部输入源来追踪
InputDetermined
变量。目标是找到依赖于输入序列的状态描述变量。-
作者将所有输入变量(在本例中,来自视频文件,例如
box_size
和box_type
)标记为Tanted,并跟踪它们在程序中的传播。与传统污点分析相比,作者的方法跟踪符号输入而不是具体输入的传播。具体来说,作者将污点信息记录为符号输入上的特定类型的数据约束,因此污点标记会随着符号执行的进行而自然传播,不会引入额外的开销。 -
如果一个变量接收到一个被污染的符号表达式,它将被标记为
InputDetermined
。在给定的示例中,box_size
、box_type
和saved_size
为InputDetermined
。 -
除了显式的数据依赖性之外,图3中描述的控制依赖也可以帮助识别状态描述变量。然而,动态污点分析通常不包括控制依赖。事实上,考虑到这种依赖性是一把双刃剑。尽管它扩大了覆盖范围,但许多不相关的变量(误报)可能会被错误地引入。因此,作者的分析只考虑了一阶控制依赖性,也就是说,一个变量
a
控制依赖于变量b
,而变量b
数据依赖于输入,那么a
会被标注为Tainted
。比如在图3中,state_var
会被标注为污点,因为其直接控制依赖于输入,而tmp_var
不会,因为其控制依赖于state_var
,而state_var
并不数据依赖于输入。
-
-
其次,如2.3所示,程序在不同状态下采取不同的分支方向。因此,对于程序中的每个条件语句,作者在检查相应条件时记录它访问的所有变量,并用
BranchRelated
标记它们。如果在条件语句中使用InputDetermined
变量,这意味着它也是BranchRelated
,作者将其标记为状态描述变量。在图1中,saved_size
在第 999 行条件语句被访问,而且又数据依赖于输入,因此它属于状态描述变量。 -
最后一步就是识别无效状态描述变量。变量具有活动持续时间,当状态描述变量被释放时会发生状态转换。比如在图4中,
opcode
是状态描述变量。如果它是堆栈上的局部变量,那么一旦函数返回,函数的局部堆栈就会失效。为了避免错误地识别具有此类过期变量的程序状态,Ferry引入了两种优化:-
如果释放的对象包含状态描述变量,则对
free
函数的调用被视为SDVO指令。 -
函数调用返回后,作者检查状态描述变量,并丢弃返回函数的栈帧中的变量。
-
此外,如果任何变量被丢弃,作者将返回指令视为SDVO指令,并检查是否引入了新状态。
-
3.3.状态感知符号执行
这一部分将解释如何使用已识别的状态描述变量来引导符号执行。如挑战2中所介绍的,很难确定某个状态是否已经探索过。为了应对这一挑战,作者的解决方案基于以下insight:程序中的状态转换取决于状态描述变量的约束。
符号执行引擎记录每个执行路径的符号输入上的约束,并确保满足相同约束的任何输入肯定会采用相同的执行路径。此外,程序状态信息被Ferry捕获为状态描述变量。因此,如果两个执行对每个状态描述变量具有相同的约束,则它们应该遵循相同的状态转换(也就是走过相同的路径)。
如2.3所述,在执行某些SDVO指令时会发生状态转换。在真实世界的程序中,在以下情况下,指令是SDVO指令。
-
初始化:一个新的状态描述变量被初始化。
-
数据约束更改:状态描述变量上的约束通过赋值进行更改或更新以采用特定的分支方向。
-
变量释放:状态描述变量的释放发生在其活动结束时。可能是
free
调用或者return
指令。
除了状态描述变量外,Ferry还记录最新状态转换发生的位置(即,它最后遇到的SDVO指令的地址).
如果两个执行路径的状态转换位置或对状态描述变量的约束不同,那么它们就换探索不同的程序路径。然后,一旦发生状态转换,Ferry将当前状态与探索记录进行比较。如果观察到新的未探索状态,作者将记录其SDVO指令地址和状态描述变量的约束。否则回滚符号执行以探索不同的程序状态。
4.算法
状态感知符号执行算法如下图所示,一个状态用4元组 (l,s,∏,Δ)(l, s, \prod, \Delta)(l,s,∏,Δ) 表示:
-
lll 表示当前执行指令的地址(对应klee中ExecutionState::pc)。
-
sss 存储当前执行路径对应的程序状态(对应
ExecutionState
的部分子集) -
KaTeX parse error: Undefined control sequence: \prob at position 1: \̲p̲r̲o̲b̲ 保存路径约束(对应klee中Executionstate::constraints)。
-
Δ\DeltaΔ 保存一个符号存储字典(对应klee中ExecutionState::symbolics),将运行时变量映射到具体值或符号表达式。
此外,作者还引入了一个状态变量 ,以及一个全局状态存储 Ω\OmegaΩ,它记录探索过的程序状态(包括这些状态对应的最近SDVO指令的地址和状态本身)。sss 会追踪3个变量集合:BranchRelated
, InputDetermined
, StateDescribing
。
- 红框部分为Ferry相比标准符号执行多出的部分。
- 蓝框里面的
updateState
函数的功能相比标准符号执行有了扩展。Ferry中update(s, v, e)
中s
为对应状态,v
为要赋值的变量,e
为值或者约束。
默认情况下,Ferry采用BFS状态搜索策略,pickNext
相当于 selectState()
。在算法中,只有被计算出未被探索过的状态会添加进 worklist
。
图5展示了图1示例用Ferry运行的过程,图中的环路表示执行完环路对应的指令后会出现重复状态。能够识别重复状态后符号执行的效率会更高。不同的状态的区别如下:
-
s6
和s8
的SDVO地址不同(L9
和L6
)。 -
s1
和s2
关于v1
(box_type
)对应的约束条件不同(值为tx3g
还是trak
)。 -
s11
和s2
相比多了变量v2
(box_size
) 的约束。
-
第一个状态描述变量是
box_type
。首先在第 444 行加载并被标记为InputDetermined
,然后在第 666 行被switch
指令访问然后被标记为BranchRelated
。然后被标记为stateDescribing
。因此,第 666 行是1个SDVO指令,第 666 行执行完毕后,fork出的2个状态分别记为s1
,s2
。如果s1
被执行过1遍,第2次执行第 666 行时再次fork,新fork的s1
会被识别为已被探索过,避免重复执行。 -
saved_size
是另一个状态描述变量,第 999 行的条件判断语句访问了它。然而,直到输入序列的内容流入其中(第 212121 行的赋值操作),它才被标识为StateDescribing
。因此,第 999 行的第一次执行不会引入新的程序状态。稍后,当任何执行路径到达第 212121 行时,saved_size
被标识为StateDescribeing
,因此引入了新的状态s3
。然后,对第 666 行的进一步执行可以进入分支“tx3g”
,因为引入了一个新的状态描述变量。在第 999 行的第二次执行中进一步更新对该存储器位置的约束。因此,引入了两种新状态(s6
和s7
)。
5.针对复杂真实程序的优化
真实程序的复杂性可能主要通过两种方式影响Ferry的有效性:
-
真实程序可能有数百甚至数千个状态描述变量,这导致状态描述变量跟踪的高开销。
-
真实程序可能在执行路径上有多个状态依赖分支,因此,Ferry可能会陷入探索早期状态依赖分支的困境,而无法探索后期的分支。
为了解决这些问题,作者提出了2种解决思路:
-
通过移除闲置变量减少对少用状态描述变量的不必要跟踪。
-
通过快捷符号执行(SSE) 探索更深的状态。
值得注意的是,这两种优化虽然不一定适用于每个程序,但并不影响基本算法。
5.1.移除闲置状态依赖变量
为了避免探索已经探索的程序状态,Ferry需要不断地将每个状态描述变量的约束(即所有可能值的集合)与探索历史进行比较,这会导致不可忽略的性能开销。为了缓解这个问题,作者提出了一种优化方法,它减少了要跟踪的状态描述变量数量。
作者没有跟踪所有状态描述变量,而是设置了数量限制,只关注最近访问的变量(即,重新赋值或被条件判断语句访问)。作者的研究表明,状态描述变量的访问频率不同。在表1列举的程序中,72%的状态描述变量被检查不超过5次,top 4%的状态描述变量占据了85%以上的变量访问。这个分布表明,对于程序中的许多状态描述变量,它们的值将在很长一段时间内保持不变。如果执行路径不访问状态描述变量,则其值保持不变,并且不会导致状态转换。
应仔细选择跟踪变量的数量。跟踪较低的数字可能会错误地忽略状态描述变量,导致不同的状态被识别为相同的状态(因此路径被错误地修剪)。高限制会增加要跟踪的变量数量,从而将时间浪费在约束求解上而不是路径探索上。
作者对表1中的7个程序进行了实验,试图找出不同数量的跟踪变量如何影响执行路径的数量。最后,作者发现跟踪3个变量有助于减少状态之间的比较,并达到深层程序状态,因此我们在下面的实验中将其设置为默认配置。
5.2.带有输入分区的快捷符号执行(SSE)
在真实程序中,到“深层”状态的执行路径由许多状态依赖分支来保护。与路径爆炸类似,程序状态的数量随着状态依赖分支数量的增加而快速增长。幸运的是,作者发现,除了试图覆盖所有这些分支,还可以将它们分成独立的组,这些组可以单独处理。
在真实程序中,开发人员不会在一个函数中处理整个输入序列,相反,输入序列的不同部分由不同的函数组处理。例如,图1示例中的输入处理循环仅解析每个 data box
的 box_type
和 box_size
。另一方面,有效载荷数据在第 181818 行被读入缓冲区 buf
,并由另一个函数处理。
因此,这些函数中的状态依赖分支也取决于输入序列的不同部分,我们可以根据输入序列中由它们所属函数处理的部分对这些分支进行分组。基于这一观察,可以通过有选择地提供具体的输入,绕过早期的状态依赖分支。
当开启SSE后,需要手动提供种子文件(seed file)以约束输入,给定种子,SSE按以下步骤运行:
-
首先,SSE通过符号仿真自动识别由不同组状态依赖分支处理的不同输入部分的边界。
-
然后,利用推断出的边界,SSE有选择地使某些输入分区符号化,以符号化的方式在状态感知的状态中执行相应的状态依赖分支组。
-
然后,它尝试通过动态移除相应输入部分上的约束来探索特定的状态相关分支组。
6.实验
Ferry基于angr框架实现,约束求解器用的是Z3,unicorn被用来加速SSE中具体文件内容的仿真。
实验过程包括:
-
首先在13个真实程序和Google FuzzBench 上和其它工具比较覆盖率。结果表明
-
与klee相比,Ferry能多覆盖38%的基本块以及42%的分支;与angr相比,Ferry能多覆盖42%的基本块以及47%的分支。
-
给定相同的输入种子,Ferry在开启SSE后覆盖率超过AFL,Angora和QSYM 3个fuzz工具。其中15%的基本块这3个fuzz工具都错过了。
-
-
在漏洞检测方面,作者构造了一个测试套件River。River由6个程序构成,包含160个手动注入的漏洞。这些漏洞必须在特定的上下文上触发(与状态依赖分支有关的漏洞)。与2个符号执行工具,3个fuzz工具相比,Ferry找出的漏洞比它们多40%,同时速度快2.4倍。
-
作者用LAVA-m数据集来评估Ferry在状态无关漏洞下的性能。在最坏的情况下,Ferry在BFS策略上的表现几乎与angr相同,只是它避免了探索一些重复的路径。
在符号执行中,如何驱动执行到达触发漏洞的分支,以及如何触发/利用漏洞(在通过符号执行到达相应的安全漏洞之后)是两个独立的问题。由于第2个问题在符号执行领域没有得到很好的解决,因此这项工作必须将其排除在范围之外。同时sanitizer和符号执行工具目前不能很好的结合,反而更容易引起严重的路径爆炸,因为它针对输入数据引入了更多的条件检查。
实验过程中,作者给每个程序设置的时间限制是6小时,并且重复3次实验取平均值。Ferry采用的搜索策略包括了BFS和DFS。SSE中用到的种子文件来自AFL测试用例(另一个下载地址)。
6.1.覆盖率测试
下表总结了覆盖率测试结果
6.2.状态依赖漏洞测试
如果漏洞触发路径至少包含1个状态依赖分支,那么这个漏洞是状态依赖漏洞。作者按下列3步构造漏洞数据集:
-
首先,确定每个相关程序的版本,减少搜索范围。将其版本设置为CVE数据库中报告漏洞最多的版本。
-
然后收集每个漏洞的信息,包括其代码位置和触发的输入序列。具体来说,通过三种方式收集漏洞详细信息:
-
找到CVE数据库中每个漏洞的参考链接 。
-
在Exploit数据库中搜索它们,该数据库提供了许多漏洞的POC。
-
找到修复漏洞的补丁并从中学习。
-
-
最后,手动过滤那些不依赖于程序状态的漏洞。
下表展示了收集到的15个漏洞以及各个工具的测试结果。但是符号执行器不能自动触发这些漏洞,因此作者将这些漏洞的触发位置替换为 assert(0)
,被替换的语句必须在特定状态下触发。这些漏洞包含堆/栈溢出,整数溢出,double-free,use-after-free,除0,未初始化的指针引用。
从结果来看,Ferry效果最好,开启SSE前覆盖了8个漏洞,开启SSE后全部覆盖。标准符号执行受到路径爆炸的影响会重复探索很多状态,Fuzz的效果受到输入种子的影响。
6.3.深度状态探索
作者提出了一个测试套件River,以帮助评估动态分析工具可以探索状态依赖分支的程度。River与其他数据集(如LAVA-M)的不同之处在于,它意味着评估工具探索“深层”状态的能力。River数据集具有以下特征:
-
所有插入的漏洞都属于状态依赖类型,这意味着它们只能由特定的输入序列触发。
-
漏洞分布在不同的状态深度上。
作者手动注释了所有插入的漏洞,并记录了它们的状态深度信息。每个漏洞被标注为二元组 (ID, depth)
,触发了该漏洞意味着该工具可以探索深度为 depth
的状态依赖分支。
River构建过程如下:
-
首先,使用Ferry来分析程序6个小时,并记录漏洞注入所需的信息,包括每个状态转换的代码位置,SDVO地址,以及路径约束。
-
在每个SDVO之后手动注入漏洞(这一步会忽略路径约束太复杂的SDVO)。
每个注入的漏洞为 assert(0 && state_depth && vul_id)
,这表示这些漏洞不会无条件被触发。
下图为测试结果,横轴为漏洞深度,纵轴某个工具累计找到的bug数量。(小于该深度的累计)
6.4.推断的SDVO准确率
这部分暂时略过。
6.5.Case study
libstagefright中的CVE-2016-3830漏洞:在所有已评估的符号执行引擎中,只有具有SSE的Ferry才能自动定位此漏洞。作者的手动分析指出困难在于:
-
该漏洞发生在AAC格式的音频解码器中,该解码器受到至少两个早期状态机的“保护”。
-
第一状态机初始化音频解码器并提取音频报头和音轨,第二状态机利用音频报头来配置解码器。
-
该漏洞存在于解码音轨的第三状态机中。实验表明,angr在第一状态机中遭受路径爆炸,如果禁用SSE,Ferry在第二状态机中遭遇严重路径爆炸。
-
-
该漏洞只能在第三状态机的深层程序状态下被利用。具体而言,在预期的有效负载大小
adtsHeaderSize
与存储在aac_frame_length
中的计算结果不匹配之后的状态下。
为了衡量SOTA符号执行算法的效率,作者通过手动将第三个状态机的入口点分配给angr,将此案例进一步应用于angr。评估显示,angr仍然未能找到该漏洞。
6.6.性能baseline
这一部分作者用Lava-M进行评估,Lava中注入的漏洞都是上下文无关的(不是状态依赖的),下表为实验结果。可以看到,Ferry在最坏的情况下和angr-BFS性能相同。
6.7.Discussion
这里,作者主要讨论Ferry失效的一些场景。Ferry在特定的程序逻辑上性能会受限(字符串搜索,压缩算法)。
-
一方面,对于符号执行器来说,它们是常见的挑战,因为这样的逻辑会产生复杂的路径约束,而这些约束会压倒约束求解器。
-
另一方面,这种程序逻辑会导致状态爆炸。
例如,压缩算法具有巨大的内部状态空间,对输入字节的任何更改都将导致不同的程序状态,并改变处理所有后续输入的方式。在这种情况下,Ferry遭受了状态爆炸(这进一步导致了路径爆炸)作者们的优化有助于缓解状态爆炸,但不能完全解决这个问题。
作为系统地处理具有状态依赖分支的程序以进行符号执行的第一次尝试,作者的技术适用于具有2.3中讨论的特性的程序。然而,它目前还不是一种通用方法。仍然阻碍符号执行引擎的一个主要挑战是如何识别任意程序中的状态描述变量。作者将此问题作为未来在Ferry上的工作。
七.参考文献
Ferry: State-Aware Symbolic Execution for Exploring State-Dependent Program Paths
相关文章:

会议论文分享-Security22-状态感知符号执行
Ferry: State-Aware Symbolic Execution for Exploring State-Dependent Program Paths1.引言2.问题陈述与分析2.1.实现状态感知符号执行的挑战2.2.真实程序的特征2.3.Ferry的模型2.3.1.程序状态的定义2.3.2.状态描述变量的特征3.Design3.1.Overview of Ferry3.2.状态描述变量识…...

吴恩达深度学习笔记(八)——卷积神经网络(上)
一、卷积相关 用一个ff的过滤器卷积一个nn的图像,假如padding为p,步幅为s,输出大小则为: [n2p−fs1][n2p−fs1][\frac{n2p-f}{s}1][\frac{n2p-f}{s}1][sn2p−f1][sn2p−f1] []表示向下取整(floor) 大部分深度学习…...

14 基数排序(桶排序)
文章目录1 基数排序基本思想2 基数排序的代码实现2.1 java2.2 scala3 基数排序总结1 基数排序基本思想 1) 基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort&#…...
汉明距离Java解法
两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。 给你两个整数 x 和 y,计算并返回它们之间的汉明距离。 例: 输入:x 1, y 4 输出:2 解释: 1 (0 0 0 1) 4 (0 1 0 0) ↑ ↑ 上…...

Netty服务端请求接受过程源码剖析
目标 服务器启动后,客户端进行连接,服务器端此时要接受客户端请求,并且返回给客户端想要的请求,下面我们的目标就是分析Netty 服务器端启动后是怎么接受到客户端请求的。我们的代码依然与上一篇中用同一个demo, 用io.…...

金三银四春招特供|高质量面试攻略
🔰 全文字数 : 1万5千 🕒 阅读时长 : 20min 📋 关键词 : 求职规划、面试准备、面试技巧、谈薪职级 👉 公众号 : 大摩羯先生 本篇来聊聊一个老生常谈的话题————“面试”。利用近三周工作午休时间整理了这篇洋洋洒洒却饱含真诚…...

搭建Hexo博客-第4章-绑定自定义域名
搭建Hexo博客-第4章-绑定自定义域名 搭建Hexo博客-第4章-绑定自定义域名 搭建Hexo博客-第4章-绑定自定义域名 在这一篇文章中,我将会介绍如何给博客绑定你自己的域名。其实绑定域名本应该很简单的,但我当初在这上走了不少弯路,所以我觉得有…...
lightdb-sql拦截
文章目录LightDB - sql 审核拦截一 简介二 参数2.1 lightdb_sql_mode2.2 lt_firewall.lightdb_business_time三 规则介绍及使用3.1 select_without_where3.1.1 案例3.2 update_without_where/delete_without_where3.2.1 案例3.3 high_risk_ddl3.3.1 案例LightDB - sql 审核拦截…...

二进制中1的个数-剑指Offer-java位运算
一、题目描述编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 1 的个数(也被称为 汉明重量).)。提示:请注意,在某些语言(如 Java&…...

学自动化测试可以用这几个练手项目
练手项目的业务逻辑比较简单,只适合练手,不能代替真实项目。 学习自动化测试最难的是没有合适的项目练习。 测试本身既要讲究科学,又有艺术成分,单单学几个 api 的调用很难应付工作中具体的问题。 你得知道什么场景下需要添加显…...

2023年保健饮品行业分析:市场规模不断攀升,年度销额增长近140%
随着人们健康意识的不断增强,我国保健品市场需求持续增长,同时,保健饮品的市场规模也在不断攀升。 根据鲸参谋电商数据显示,2022年度,京东平台上保健饮品的年度销量超60万件,同比增长了约124%;该…...

2023-02-17 学习记录--TS-邂逅TS(一)
TS-邂逅TS(一) 不积跬步,无以至千里;不积小流,无以成江海。💪🏻 一、TypeScript在线编译器 https://www.typescriptlang.org/play/ 二、类型 1、普通类型 number(数值型ÿ…...

SpringMVC创建异步回调请求的4种方式
首先要明确一点,同步请求和异步请求对于客户端用户来讲是一样的,都是需客户端等待返回结果。不同之处在于请求到达服务器之后的处理方式,下面用两张图解释一下同步请求和异步请求在服务端处理方式的不同:同步请求异步请求两个流程…...

MySQL(二)表的操作
一、创建表 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎; 说明: field 表示列名 datatype 表示列的类型 character set 字符集,如…...

SpringCloud - 入门
目录 服务架构演变 单体架构 分布式架构 分布式架构要考虑的问题 微服务 初步认识 案例Demo 服务拆分注意事项 服务拆分示例 服务调用 服务架构演变 单体架构 将业务的所有功能集中在一个项目中开发,打成一个包部署优点: 架构简单部署成本低缺…...

进一步了解C++函数的各种参数以及重载,了解C++部分的内存模型,C++独特的引用方式,巧妙替换指针,初步了解类与对象。满满的知识,希望大家能多多支持
C的编程精华,走过路过千万不要错过啊!废话少说,我们直接进入正题!!!! 函数高级 C的函数提高 函数默认参数 在C中,函数的形参列表中的形参是可以有默认值的。 语法:返…...

Chapter6:机器人SLAM与自主导航
ROS1{\rm ROS1}ROS1的基础及应用,基于古月的课,各位可以去看,基于hawkbot{\rm hawkbot}hawkbot机器人进行实际操作。 ROS{\rm ROS}ROS版本:ROS1{\rm ROS1}ROS1的Melodic{\rm Melodic}Melodic;实际机器人:Ha…...
Sass的使用要点
Sass 是一个 CSS 预处理器,完全兼容所有版本的 CSS。实际上,Sass 并没有真正为 CSS 语言添加任何新功能。只是在许多情况下可以可以帮助我们减少 CSS 重复的代码,节省开发时间。 一、注释 方式一:双斜线 // 方式二:…...
计算机启动过程,从按下电源按钮到登录界面的详细步骤
1、背景 自接触计算机以来,一直困扰着我一个问题。当我们按下电脑的开机键后,具体发生了哪些过程呢?计算机启动的具体步骤是什么? 计算机启动过程通常分为五个步骤:电源自检、BIOS自检、引导设备选择、引导程序加载和…...

LeetCode 刷题之 BFS 广度优先搜索【Python实现】
1. BFS 算法框架 BFS:用来搜索 最短路径 比较合适,如:求二叉树最小深度、最少步数、最少交换次数,一般与 队列 搭配使用,空间复杂度比 DFS 大很多DFS:适合搜索全部的解,如:寻找最短…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...