zoukankan      html  css  js  c++  java
  • Compositional Fuzzing Aided by Targeted Symbolic Execution

    题目:Compositional Fuzzing Aided by Targeted Symbolic Execution

    作者:Saahil Ognawala, Fabian Kilger, Alexander Pretschner

    单位:Faculty of Informatics, Technical University of Munich,Boltzmannstr. 3, 85748 Garching, Germany

    邮箱: saahil.ognawala@tum.de (Saahil Ognawala)

    出版:preprint

    背景:

    当前的基于覆盖的fuzz技术,可以有效地找到浅层的bug,但是无法在更深层次的程序中实现高覆盖率,找到需要满足很多分支条件的复杂bug。

    白盒技术,比如符号执行/混合执行或者白盒模糊,因为路径爆炸问题,导致执行在浅层分支就卡住。

    组合分析是一种减轻符号执行中的路径爆炸问题的技术,通过分析系统的各个组件,修剪程序中不会触发组件漏洞的路径。
    相比传统符号执行,组合分析能够覆盖程序的更多部分,并且发现了程序中的更多漏洞。

    但是目前还没有将组合分析用于fuzz的工作。

    目标:

    通过提高单一函数的覆盖率来提高模糊器的漏洞检测能力。我们将单一函数定义为参数不为空的函数,即参数是int a等,不可以是void。 我们的中心前提是,提高单一函数的覆盖率可以发现更多的漏洞。 然后,采用导向符号执行来对由模糊测试发现的漏洞执行可达性分析,以确认漏洞是否在从更高级别的调用上下文中可达。

    方案:

    在本文中,我们介绍Wildfire,一种新颖的开源组合模糊框架,实现了用于fuzz大型真实程序的组合分析方法。

    首先,使用自动生成的种子输入来fuzz单一函数(覆盖程序调用图的所有深度的函数);

    然后总结了fuzzer在单一函数中发现的漏洞,并用摘要进行函数替换;

    最后,使用导向符号执行来确定单一函数中的漏洞是否可以由其Caller(调用)函数触发,重复迭代直到顶级函数,例如main,完成利用这些漏洞的可达性确认。

    Contribution:

    1.提出了一个新颖的结合fuzzing和targeted符号执行的compositional fuzzing技术,用来找到程序中的漏洞。

    2.设计一个fuzzing driver,可以自动生成种子(driver的作用就是将种子中数据取出,传递给函数参数)

    3.框架的设计与实现可以有效地使用多核并行化,使得在寻找大规模程序漏洞的时候更加scalable和efficient。

    4.实验证明,Wildfire相比SE和fuzz可以找到更多的漏洞,有更高的覆盖和更低的时间消耗。可以复现开源库中几乎所有的可利用漏洞,并且发现新的漏洞。

    5.Wildfire已经被开源实现,作为第一个混合fuzz和SE的compositional分析工具,可以分析C程序。

    Design

    Overview

    Wildfire的workflow如下:

    1.Instrumentation and compilation.

    将源码编译成LLVM IR。

    2.Generating fuzzing drivers.

    为了fuzz程序中的单独函数,Wildfire需要生成fuzzing driver,作为单独函数的wrapper:

    1.给定参数列表,为函数生成种子输入(seed-arguments)

    2.将fuzzer生成的输入正确分配给函数参数。

    2.1-Seed-argument Generation

    静态地为单独函数生成种子参数。

    两种方法:

    1)生成两个字节流{一个空流和一个由英文字母中的随机字符组成的流,[a-z]}。对于指针类型的参数,具有空字节流的缓冲区相比于非空字节流更可能导致函数崩溃。

    2)生成包含与函数参数相等数目分隔符的字节流(分隔符确定字节流中提取某参数的开始和结束)。

    2.2-Argument Extraction

    由fuzzer提供的输入(种子参数)是字节流。我们需要从该字节流中提取字节分配给函数参数。分两种情形: 非指针和指针数据类型。我们将忽略具有双指针或多指针的参数的任何函数-limit。

    算法1: 提取非指针类型参数,例如int或char。ExtractFixedSizedArgument函数只是将typeSize字节数从字节流复制到参数,并将其转换为所需类型。如果要消耗的流中不足typeSize字节数,则使用空字符字节填充流。

    算法2: 提取指针类型的参数,基于字节流中的特殊分隔符(假设为 //),它将字节流分割以分配给动态大小的参数类型。对于每个指针类型参数,ExtractDynamicSizedArgument将输入字节流复制到t,直到遇到第一个分隔符,或者到达字节流结束。辅助函数LookForDelimiter返回剩下的字节流中的第一个分隔符位置,或者流的结尾.RoundDown将给定的大小舍入为typeSize的倍数。

    note:对于算法2,

    如果说接收的是指数型参数,那么分隔符是//,首先在remData中找到//的位置,如果找到返回该位置,否则返回remData的结尾位置,记为givenSize。

    如果是指针,并不知道这个是几重指针,那么将需要RoundDown来对givenSize进行除以typeSize下取整,得到bufSize。取remData中的前bufSize数据到t中。然后如果bufSize小于等于remSize,就把givenSize之后的remData部分放回remData中(就是//之后的部分),否则将remDat置为空。

    3.Generating test-cases with fuzzing.

    将fuzzer应用于单一函数,生成种子参数。 Fuzzer的目标是上面生成的驱动程序(被包装后的单独函数),它可以由fuzzer直接执行。 对于所有单一函数,此步骤可以并行。
    对于所有单独函数,此步骤的输出是一个list Tf,包含由函数f的fuzzer生成的所有测试用例。

    Tf = {t1 , t2 , . . . tn}, (1)

    其中n是fuzzer生成的唯一测试用例的数量。 如果函数f接受m个参数,那么,

    ti =<Ii1 , Ii2 , . . . Iim>, (2)

    其中Iik是第k个参数。

    4.Generating crash reports.

    通过在轻量级的程序版本(a lightweight compiled object?)上重放由fuzzer生成的测试用例,获取单独函数的模糊测试报告,包含函数参数和崩溃执行的堆栈跟踪等详细执行信息。

    步骤:

    1-使用 -cmin 和 -tmin 最小化测试用例集合.

    2-将测试用例集传递给编译对象的检测版本,检测缓冲区溢出,空指针解引用和其他索引越界内存操作等漏洞

    输出:

    1-导致程序崩溃的所有测试用例(参数)的列表Tf'。

    2-单一函数所报告崩溃的堆栈跟踪。

    带有参数ti的函数f0,其崩溃执行的堆栈跟踪Sf0,是一个有序集合。

    其中fi调用了fi+1,L返回可能有漏洞的函数名和指令(行号)。

    5.Summarizing functions.

    用触发漏洞的参数赋值集替换vulnerable函数中的路径集。
    对于vulnerable function f0,其参数列表P:

    P=<p1,p2,...pm>, (4)

    其中pi是f0的第i个参数。为f0生成的摘要fsummary如Algorithm 3所示。


    P==ti定义为

    P≠ti就是取反。

    函数摘要原理:将形式参数与触发漏洞的具体参数值进行比较。对于指针数据类型,需要使用memcmp比较分配的内存内容。

    1-当找到P的匹配等于ti时,Wildfire会报告断言错误,说明f中的漏洞可以从f的调用函数触发。

    2-如果没有断言错误,就调用原始函数f继续处理。

    limit-由于Fuzzer仅生成具体输入而不是一般路径约束,所以只能匹配参数的具体值。(有漏报)

    6.Determining Feasibility of Reported Vulnerabilities

    使用堆栈跟踪匹配和目标符号执行确定已发现漏洞的可行性分析,以递归方式生成触发漏洞的具体参数,直到main函数或API。

    原理:如果函数f中的漏洞可以从调用f的函数中利用,并且可以从调用调用f函数的函数中利用……直到接口函数,那么函数f中的漏洞是被确认可利用的。

    Phase 1: Stack-trace Matching
    根据第四步的崩溃报告,可以获得单独函数崩溃的堆栈跟踪。 如果堆栈跟踪Sfb是Sfa的有序子集,则fb中的漏洞可以被fa利用,即匹配到Sfa和Sfb。函数fa的崩溃是由于调用了函数fb,并传递给fb中参数,触发了fb中的vulnerable指令,导致崩溃。

    Phase 2: Targeted Symbolic Execution
    如果没有为Sfa找到这样的匹配堆栈跟踪,可能是因为fuzzer无法生成触发所述路径的测试用例,而不是因为这样的路径不存在。

    这种情况下,Wildfire利用符号执行来调用vulnerable函数,有针对性地检测phase1中找不到匹配堆栈跟踪的vulnerable函数。

    该阶段将函数摘要替换函数体,从所有的父函数到vulnerable函数进行有针对性的符号执行。再次考虑一个易受攻击的函数fa,第1阶段没有找到任何匹配的堆栈跟踪。使用目标搜索策略时,将忽略所有无法到达目标的分支(静态分析)。

    Wildfire依次应用阶段1和阶段2,直到达到main函数或库的API函数。 此阶段的输出是漏洞报告列表,每个漏洞报告都包含易受攻击的指令,函数和函数链,通过这些可以利用这些漏洞。

    Implementation

    AFL for Fuzzing.

    ASAN for Generating Crash Reports.

    获取由非法内存相关操作(如缓冲区溢出或后续使用)引起的崩溃报告。

    KLEE22 for Symbolic Execution.

    符号执行工具是KLEE22,它以程序中的任意函数调用为目标,进行路径探索。

  • 相关阅读:
    String 类的常用方法都有那些?
    ArrayList、LinkedList、Vector 的区别。
    1.JDK,JRE,JVM三者关系
    ==与equals的区别
    [LeetCode#22]Generate Parentheses
    [LeetCode#20]Valid Parentheses
    [LeetCode#2]Add Two Numbers
    [LeetCode#1] Two Sum
    [LeetCode#9] Palindrome Number
    [LeetCode#7]Reverse Integer
  • 原文地址:https://www.cnblogs.com/linkJ/p/13591703.html
Copyright © 2011-2022 走看看