• AFL模糊测试


    一、AFL简介

    AFL(American Fuzzy Lop)号称是当前最高级的Fuzzing 测试工具之一 是由安全研究员Michał Zalewski(@lcamtuf)开发的一款 基于覆盖引导(Coverage-guided)的 模糊测试工具,用于 挖掘可能存在的内存安全漏洞,如栈溢出、堆溢出、UAF、double free等。它 通过记录输入样本的代码覆盖率,从而调整输入样本以提高覆盖率,增加发现漏洞的概率
    • AFL 采用新型的编译时插桩遗传算法自动发现新的测试用例,这些用例会触发目标二进制文件中的新内部状态。这大大改善了模糊测试的代码覆盖范围。
    • AFL既可以对源码进行编译时插桩,也可以使用AFL的QEMU mode对二进制文件进行插桩,但是前者的效率相对来说要高很多。
      
    AFL的 优点是可以轻松部署,配置相对简单,测试效率相对较高。 原生的AFL仅适配于C/C++程序的测试,不过目前已经衍生出很多分支,用于适配其他语言的模糊测试,如针对JAVA程序的Kelinci等
       
    工作流程大致如下:
        ①从源码编译程序时进行插桩,以记录代码覆盖率(Code Coverage);
        ②选择一些输入文件,作为初始测试集加入输入队列(queue);
        ③将队列中的文件按一定的策略进行“突变”;
        ④如果经过变异文件更新了覆盖范围,则将其保留添加到队列中;
        ⑤上述过程会一直循环进行,期间触发了crash的文件会被记录下来。
    AFL变异的方式
    AFL是采用遗传算法,基于变异生成的测试用例,变异的主要类型有下面这几种:

    确定性变异:

    • bitflip:按位翻转,1变为0,0变为1;这一阶段还会按照不同的长度和步长进行多种不同的翻转,每次翻转1/2/4/8/16/32 bit,依次进行。

    • arithmetic:整数加/减算术运算

    • interest:把一些特殊内容替换到原文件中。所谓的特殊内容是AFL预设的一些比较特殊的数,比如可能造成溢出的数。

    • dictionary:把自动生成或用户提供的token替换/插入到原文件中。

    随机变异:

    • havoc:“大破坏”,是前面几种变异的组合

    • splice:“连接”,此阶段会将两个文件拼接起来得到一个新的文件,并对这个新文件继续执行havoc变异。

    二、AFL安装和使用

    利用AFL进行模糊测试的大概 过程:①插桩编译;②设置种子测试用例;③开始fuzz 。模糊测试对于软件测试的帮助很大,其不受限于被测系统的内部实现细节和复杂程度。

    2.1、安装

    AFL 自带定制版本的 gcc 和 clang 编译器,建议选择 LLVM 的 clang 编译器,可以加快 fuzz 的速度。
    下载AFL源码( GitHub - google/AFL: american fuzzy lop - a security-oriented fuzzer),解压后,编译安装:
    AFL使用afl-gcc编译
    make
    sudo make install  安装到系统目录
       
    AFL使用afl-clang编译
    cd llvm_mode
    make
    cd ..
    sudo make install 
      
    查看路径可以看到afl安装的文件:通过源码编译的方式安装程序,如果不指定--prefix,会将库安装在 /usr/local/lib目录下
    作用分别为
    • afl-gcc 和afl-g++ 分别对应的是gcc 和g++ 的封装
    • afl-clang 和afl-clang++ 分别对应clang 的c 和c++ 编译器封装À。
    • afl-fuzz 是AFL 的主体,用于对目标程序进行fuzz。
    • afl-analyze 可以对用例进行分析,通过分析给定的用例,看能否发现用例中有意义的字段。
    • afl-qemu-trace 用于qemu-mode ,默认不安装 ,需要手工执行qemu-mode 的编译脚本进行编译,后面会介绍。
    • afl-plot 生成测试任务的状态图
    • afl-tmin 和afl-cmin 对用例进行简化
    • afl-whatsup 用于查看fuzz 任务的状态
    • afl-gotcpu 用于查看当前CPU 状态
    • afl-showmap 用于对单个用例进行执行路径跟踪
      
    afl-fuzz指令:
    下面我们进行一个简单的AFL实验了解其使用流程。

    2.2、准备被测程序

    首先创建一个简单的test.c源文件,里面放入我们要测的c程序。
    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. int AFLTest(char *str)
    7. {
    8. int len = strlen(str);
    9. if(str[0] == 'A' && len == 6)
    10. {
    11. raise(SIGSEGV);
    12. //如果输入的字符串的首字符为A并且长度为6,则异常退出
    13. }
    14. else if(str[0] == 'F' && len == 16)
    15. {
    16. raise(SIGSEGV);
    17. //如果输入的字符串的首字符为F并且长度为16,则异常退出
    18. }
    19. else if(str[0] == 'L' && len == 66)
    20. {
    21. raise(SIGSEGV);
    22. //如果输入的字符串的首字符为F并且长度为66,则异常退出
    23. }
    24. else
    25. {
    26. printf("it is good!\n");
    27. }
    28. return 0;
    29. }
    30. int main(int argc, char *argv[])
    31. {
    32. char buf[100]={0};
    33. gets(buf);
    34. //存在栈溢出漏洞
    35. printf(buf);
    36. //存在格式化字符串漏洞
    37. AFLTest(buf);
    38. return 0;
    39. }

    2.3、使用 afl-gcc 插桩编译

    编译插桩是指在代码编译期间修改或新增代码,插桩是为了覆盖率而实行的方法

    用 AFL 编译目标源码,其目的在于插桩,让编译得到的程序,反馈路径覆盖。AFL 自带定制版本的 gcc 和 clang 编译器,建议选择 LLVM 的 clang 编译器,可以加快 fuzz 的速度。
      
    编译过程和普通gcc编译也是一样,除了使用的命令需要带上afl-前缀,因此
    afl-gcc -g -o test  test.c   # 针对c文件, -g选项为使用gdb调试所需,如果不调试就不需加此选项。 在linux下编译链接程序,如果不加-o参数,生成的binary代码的名字都是默认的a.out
    可以看到在编译过程中,编译器已经提示存在漏洞,不理会,用AFL去测试
    编译后会有插桩符号,使用下面的命令可以验证这一点: readelf -s ./test | grep afl
    注:
    针对c++文件,则使用 afl-g++ -g -o test  test.cpp
    对于一个C++程序,要设置: CXX=/path/to/afl/afl-g++.
    对于完整的项目,需要将编译器指定为 afl-gcc,然后再进行编译:
    1. 方法1
    2. CC="afl-gcc" CXX="afl-g++" ./configure --prefix="out_binary_Path"
    3. sudo make && make install
    4. 方法2:直接修改 Makefie 文件,修改编译器:
    5. CC = afl-gcc
    6. CXX = afl-g++
    7. ./configure --prefix="out_binary_Path"
    8. sudo make && make install

    2.4、准备种子语料库

    2.4.1、搜集种子语料库

    作为模糊测试,AFL需要提供初始的种子输入, 变异算法会根据此种子变异生成各种测试用例,喂给程序。但实际上,你完全可以提供任何无意义的输入作为种子,模糊测试也一般能达到效果,只不过效率会低一些而已,是否提供有意义种子?提供多少?无外乎在种子获取难度和测试的效率要求之间进行权衡而已。
    这里,借用 Freebuf 提供的资料,给出一些开源的语料库
    事实上很多程序也会自带一些案例,也可以作为测试用例。
       
    在这里我们生成一好一坏两个种子语料库:
    mkdir good-seeds bad-seeds
    echo '1+1' > good-seeds/any-seed
    echo 'this is a bad seed' > bad-seeds/any-seed

    2.4.2、精简语料库

    找到语料库之后,最好能够进行修剪, 合并重复用例,裁剪体积afl 推荐的每个用例体积小于 1KB,不然会影响 fuzz 的效率。
    2.4.2.1、去重
    afl-cmin 可以精简语料库,去掉可能重复的测试用例,可大大减少无用的 fuzz 用例
    afl-cmin -i input_dir -o output_dir -- /path/to/tested/program [params]
    更多的时候,我们是从文件中获取输入,因此,往往使用 @@ 替代 params(参数),即
    afl-cmin -i input_dir -o output_dir -- /path/to/tested/program @@
    2.4.2.2、裁剪体积
    afl-tmin  可以缩短文件体积,因为 afl 要求测试用例的大小最好小于 1KB ,因此最好将精简后的用例进一步缩小体积。afl-tmin 有两种工作模式, instrumented mode crash mode 。默认的工作方式是instrumented mode
    afl-tmin -i input_file -o output_file -- /path/to/tested/program [params] @@
    找一个引起crash的文件复制过来:any-seed文件
    1. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    2. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    3. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    4. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    5. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    6. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    7. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    8. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    9. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    10. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    11. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    12. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    13. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    14. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    15. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    16. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    17. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    18. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    19. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    20. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    21. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    22. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    23. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    24. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    25. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    26. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    27. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    28. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    29. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    30. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    31. A@@@@@DVV@@Z@@@@@@@@@@@@@@@@P@@@@@⚌⚌⚌@@@@@@@@@@@@P@@@@@⚌⚌@@@@@@@@@@⚌@@@@@@@P@@G@@.V@⚌@@@
    再次执行,可以看到种子从3.3kb减小到1kb
    由于 afl-cmin 一次性只能精简单个文件,如果用例特别多,需要手动花费很长时间,其实一条简单的 shell 脚本即可完成
    for i in *; do afl-tmin -i $i -o tmin-$i -- ~/path/to/tested/program [params] @@; done;

    2.5、开始测试

    在执行afl-fuzz前,如果系统配置为将核心转储文件(core)通知发送到外部程序,将导致将崩溃信息发送到Fuzzer之间的延迟增大,进而可能将崩溃被误报为超时,所以我们得临时修改core_pattern文件:  echo core >/proc/sys/kernel/core_pattern
      
    对于可以直接从stdin读取输入的目标程序来说,执行命令, afl-fuzz  -i good-seeds/ -o good-outputs -- ./test
    对从文件读取输入的目标程序来说,要用“@@”: afl-fuzz -i ./in/ -o ./out/ -Q ./readelf -a @@    # 开始fuzz, @@表示从in 文件夹中找elf作为输入 ,实际上是在执行readelf -a 文件名
    ctrl-C结束fuzz,共找到了6个crash,可以看到当前目录下已经多出了good-outputs目录,这是本次模糊测试的结果。
    process timing:展示的是fuzzer的运行时间、最近一次发现新路径的时间、最近一次崩溃的时间和最近一次挂起的时间。
    值得注意的是第2项(最近一次发现新路径的时间)。如果由于目标二进制文件或者命令行参数出错,那么其执行路径应该是一直不变的,所以如果从fuzzing开始一直没有发现新的执行路径,那么就要考虑是否有二进制或者命令行参数错误的问题了。对于此状况,AFL也会智能地进行提醒。
    overall result:运行的总周期数,总路径数,崩溃次数和挂起次数。
    总周期数可以用来作为何时停止fuzzing的参考 。随着不断地fuzzing,周期数会不断增大, 其颜色也会由洋红色,逐步变为黄色、蓝色、绿色 。一般来说,当其变为绿色时,代表可执行的内容已经很少了,继续fuzzing下去也不会有什么新的发现了。此时,我们便可以通过Ctrl-C,中止当前的fuzzing。
    cycle progress:fuzzer正在处理的测试样例的编号和由于超时放弃的的输入数量,从而得知fuzzer处理了多少样例,队列中还剩多少
    map coverage
    第一行显示的是已经命中了多少分支元组与位图可以容纳的数量的比例。左边的是当前输入,右边的是整个输入语料库的值。
    第二行显示的是二进制文件中元组命中计数的变化,如果对于所有尝试的输入,每个采用的分支都采用固定的次数。读数显示为1.00, 当设法触发每个分支的其他命中计数时,读数向8.00移动(8位映射命中每一位),但可能永远不会到达极限。
    这些值可以用于比较不同的模糊测试对于同一检测二进制文件的覆盖范围。
    stage progress:显示了正在测试的策略(AFL变异方式),进度,总执行次数和执行速度。 一般正常的执行速度应该在500以上。
    findings in depth
    这一部分的数据对一般的使用者用处不大,包括基于应用到代码的最小化算法获得的fuzzer最喜欢的路径数和真正获取更好的边缘覆盖率的测试用例数,还有超时和崩溃的计数器,注意这里的timeout和hang有所不同,timeout计数器包括了所有超过超时的测试用例,即使它们没有超过超时足够的幅度而分类为hangs(挂起)
    fuzzing strategy yields:用于追踪各种fuzzing策略所获得的路径和尝试执行的次数的比例,用于验证各种方法的有效性。
    path geometry
    第一个数据指的是fuzzing过程中达到的路径深度,通常用户提供的测试用例视为1级,传统模糊测试从中获得的测试用例视为2级,通过它们作为后续模糊测试回合的输入得到的结果为3级,以此类推。
    下一个数据pending指的是还有多少输入数据没有经过任何测试。pend fav时指fuzzer在这个队列中真正想到达的条目。接下来的是这个fuzzing部分找到的新路径数量和在进行并行化fuzzing时从其他fuzzer实例导入的路径数量 。
    最后一个数据可以衡量观测到痕迹的一致性,如果程序对相同的输入始终表现相同,则为100%,若数值较低但仍然显示为紫色,测试过程不太可能受到负面影响,而显示红色说明出现了问题,afl可能难以区分调整输入文件的有意义的效果和幻象效果

    2.6、fuzz结果分析

    crashes:导致目标接收致命signal而崩溃的独特测试用例
    queue:存放所有具有独特执行路径的测试用例。
    AFL输出文件:
    • crashes/README.txt:保存了目标执行这些crashes文件的命令行参数。
    • hangs:导致目标超时的独特测试用例。
    • fuzzer_stats:afl-fuzz的运行状态。
    • plot_data:用于afl-plot绘图。
      
    查看第1个crash,发现符合栈溢出漏洞的crash情况(最长输入100字符):
    查看第2个crash:发现符合首字符为A且字符串长度为6的异常退出情况:
    查看第3个crash:发现符合首字符为F且字符串长度为16的异常退出情况:
    查看第4个crash,发现符合栈溢出漏洞的crash情况(最长输入100字符):
    查看第5个crash,发现符合栈溢出漏洞的crash情况(最长输入100字符):
    查看第6个crash:发现符合输入的字符串的首字符为L并且长度为66的异常退出情况:
       
    AFL编译后的是一个普通的可执行文件,可以直接在命令行使用 ./test启动运行,然后此时你需要在终端进行输入,然后又会在终端获得输出:
       
    afl-plot 可以绘制更加直观的结果,利用的就是 fuzzer 生成的 plot_data 文件。当然,要使用 afl-plot ,需要先安装 apt-get install gnuplot

    三、并行fuzz测试

    在使用afl-fuzz时,每个进程只会占用一个CPU核心。如果我们的机器是多核处理器,我们可以通过进行分布式fuzz来提高fuzz速度。
    首先先看自己有多少内核: afl-gotcpu
    以上可以看出可以运行6~8个实例。
      
    首先指定主实例 -M 用于主实例,将 -S 添加到所有从属实例。注意, 这里-o跟的参数一定要保持一致,这个是用来同步各个fuzz进程的
    • 主实例:   afl-fuzz  -M master  -i  good-seeds/   -o good-outputs   -m none  --   ./test
    • 从实例1 afl-fuzz  -S slave1   -i  good-seeds/   -o good-outputs   -m none  --   ./test
    • 从实例2: afl-fuzz  -S slave2   -i  good-seeds/   -o good-outputs   -m none  --   ./test
    若分布式意外退出可以使用以下命令继续fuzz任务:
    • 主实例:   afl-fuzz  -M master   -i-   -o good-outputs  -m none  --   ./test
    • 从实例1 afl-fuzz  -S slave1    -i-   -o good-outputs   -m none  --   ./test
    • 从实例2: afl-fuzz  -S slave2   -i-   -o good-outputs  -m none  --   ./test
    运行后会在good_outputs文件夹会多出三个不同的文件夹master、slave1、slave2:

    这两种类型的Fuzzer执行不同的Fuzzing策略,前者进行确定性测试(deterministic ),即对输入文件进行一些特殊而非随机的的变异;后者进行完全随机的变异。

    可以看到这里的-o指定的是一个同步目录,并行测试中,所有的Fuzzer将相互协作,在找到新的代码路径时,相互传递新的测试用例,如下图中以Fuzzer0的角度来看,它查看其它fuzzer的语料库,并通过比较id来同步感兴趣的测试用例。

    afl-whatsup 可以查看每个fuzzer的运行状态和总体运行概况( 依靠读afl-fuzz输出目录中的fuzzer_stats文件来显示状态的,每次查看都要需要手动执行),加上-s选项只显示概况,其中的数据都是所有fuzzer的总和。

    四、黑盒 fuzz(无源码AFL测试)

    以上 fuzz 过程,依赖于我们有程序的源码,并且在编译过程中进行了插桩,但很多时候,我们并 没有源码,这时候就要靠 afl 提供的 qemu_mode 模式了( 只要在之前的命令的基础上加上-Q的参数即可  。原版本的 afl qemu 模式由于版本过老,已不能正常运行,推荐使用 github 上的   AFLplusplus  或者  afl-unicorn。AFLplusplus 更容易安装,而 afl-unicorn 针对 qemu 模式更加友好。

    4.1、qemu_mode模式安装

    无论是下载的哪个版本的 afl,根目录下都会有 qemu_mode 文件夹,进入此目录,运行以下脚本,如果没有出错,就代表 qemu_mode 成功了:
    cd qemu_mode
    sudo ./build_qemu_support.sh
    cd ..
    make install
      
    安装注意事项:

    4.2、示例

    >>> 继续使用上面简单c代码进行测试,但 这次采用gcc进行编译,而不是afl-gcc。将test.c编译为test2
    执行命令: afl-fuzz -Q -i good-seeds/ -o good-outputs  --  ./test2
    可以看出:同样的程序,在qemu 模式下比在源码编译插桩的模式下会慢很多。(通过观察stage progress下的exec speed)
          
    >>> 一个Fuzz实例
    测试readelf。 由于readelf的输入其实就是elf文件,因此需要在in目录下放一个输入elf。 按照流程创建文件夹和测试用的elf。 
    cd AFL/testcases/mytest
    mkdir in out
    cd in
    cp ../../others/elf/small_exec.elf  .    # afl目录中自带一些常用文件的testcase
    cd ..
    cp /usr/bin/readelf .    # 将readelf复制到mytest 目录下
    afl-fuzz -i ./in/ -o ./out/ -Q ./readelf -a @@    开始fuzz,@@表示从in文件夹中找elf作为输入,实际上是在执行readelf -a 文件名

    五、参考

  • 相关阅读:
    《JavaSE-第十章》之抽象类与接口
    JAVA应用导致 CPU 100% 占用问题排查
    C语言-atoi函数的使用和实现
    计算节点的网络地址(用16进制表示)
    【微信小程序】picker-view嵌入页面的滚动选择器(84/100)
    OSG编程指南<一>:OpenSceneGraph 概述
    如何将BilBil视频永久保存到本地电脑?一招解决
    Word处理控件Aspose.Words功能演示:在 Python 中将 Word 文档转换为 EPUB
    给定一个 N×3 的矩阵 matrix,对于每一个长度为 3 的小数组 arr,都表示一个大楼的三个数据,请返回整体的轮廓线数组。
    {“Code“:“InvalidParameterValue.TemplateParameterFormatError“
  • 原文地址:https://blog.csdn.net/leiwuhen92/article/details/132762772