本文是对于模糊测试方面的小总结,计划三篇;第一篇概述;第二篇afl;第三篇Winafl。非大部头书,只提取关键信息。
本篇为第三篇:winafl,本篇中的内容大量引用Hardik Shah的公开演讲。

本篇的主要内容如下:

  • Winafl是什么
  • 使用DynamoRIO返回覆盖率信息
  • 模糊策略
  • 开始使用Winafl
    • 动手:使用VisualStudio编译示例C程序
    • 动手:找到Fuzz函数的偏移量
    • 动手:在调试模式下运行Winafl,检查一切正常
    • 动手:开始使用WinAFL
    • 动手:分析崩溃并找到根本原因
  • 开搞真实的商业应用程序
    • 动手:编写一个线束/测试程序来读取/解析MDB文件
    • 动手:分析MDB文件
    • 动手:用WinAFL模糊它
    • CVE-2018-8423和CVE-2019-0576分析
  • 总结

Winafl是什么?

  • 在FUzz的闭源代码程序所面临许多挑战
    • 无源码,仅有dll和exes
      • 比如:Gdi32.dll,gdiplus.dll, msrd3x40.dll
  • Winafl
    • Windows版本的afl(American Fuzzy Lop)
    • 由 Ivan Fratric 所维护
    • 使用 DynamoRIO(drrun.exe)来插桩和收集覆盖率
    • afl-fuzz.exe与充当drrun.exe客户端的winafl.dll进行通信
      • 信息流:afl-fuzz.exe <——> winafl.dll <——> drrun.exe
    • 需要写一种叫harness的程序
      • 它能从处理文件解析的DLL中调用函数
      • harness应该有一个函数,它接受文件名作为输入,打开它,然后进行进一步的处理
      • winafl将在内存模糊中使用这个函数
  • 一个简单的实例

image-20210602094353421

使用DynamoRIO返回覆盖率信息

  • afl-fuzz.exe是负责在linux上实现模糊测试的过程主进程

  • winafl.dll是一个客户端dll,它负责处理从dynamorio, pre_fuzz,

    post_fuzz之类传递过来的信息

  • 两者都通过IPC(Inter-Process Communication进程间通讯)进行通信

  • 注册各种事件的回调,比如基本块、模块的加载和卸载等

image-20210602095350741

  • 检查其模块是否为目标模块,然后使用符号/地址来搜索模糊函数

image-20210602095717769

  • 调用pre_fuzz处理程序以保存程序此时的状态
  • 执行函数并监控崩溃情况,不断更新覆盖率map
  • 调用post_fuzz处理程序并恢复状态
  • 一直循环到迭代次数

模糊策略

  • bitflip,按位翻转,1变为0,0变为1
    • 1/1,2/1,4/1,8/8 ….32/8
  • Byte Flip ,按字节反转
  • arithmetic,整数加/减算术运算
  • havoc,中文意思是“大破坏”,此阶段会对原文件进行大量变异
  • dictionary,把自动生成或用户提供的token替换/插入到原文件中
  • interest,把一些特殊内容替换到原文件中
  • splice,中文意思是“绞接”,此阶段会将两个文件拼接起来得到一个新的文件

该部分内容可参考官方文档: https://github.com/googleprojectzero/winafl/blob/master/afl_docs/technical_details.txt

开始使用Winafl

动手:让我们使用WinAFL

  • 编译
    • 使用 visual studio 编译目标二进制程序或者使用官方预编译好的二进制程序
  • 开启Page Heap堆页
    • 开启:gflags /p /enable readfile.exe
    • 验证:gflags /p
  • 对函数fuzz
    • 查找处理器图像函数的偏移量
      • 用 WinDBG
      • x ReadFile!ProcessImage
  • 确保程序得到DynamoRIO信息正确:
    • C:\fuzzingwork\DynamoRIO-Windows-7.1.0-1\bin32\drrun.exe -c winafl.dll -debug -target_module readfile.exe -target_offset 0x10a0 -fuzz_iterations 10 -nargs 1 – readfile.exe 1.img
      • Drrun.exe -> DynamoRIO 二进制程序
      • -c winafl.dll -> 用于与drrun通讯的客户端程序
      • -debug -> Winafl将生成调试日志
      • -target_module -> 你想要插桩&测量代码覆盖率的目标模块
      • -target_offset -> 在内存模糊中的你要fuzz的函数的偏移
      • -fuzz_iterations -> 你想要循环的次数
      • -nargs -> 参数的数量

动手:运行WinAFL开始Fuzzing

  • 命令行格式:

AFL-FUZZ.EXE AFL_ARGS INSTRUMENTATION_OPTIONS PROGRAM_NAME @@

image-20210602101900240

  1. afl-fuzz.exe参数
    • -M – Master模式
    • -S – Slave模式
    • -i -> 输入目录
    • -o -> 输出目录
    • -D -> DynamoRIO bin32/64 目录路径
    • -t -> 超时时间
  2. DynamoRIO的参数
    • -coverage_module -> 需要进行检测的dll/exe的名称
    • -target_module -> harness里可执行文件的名称。
    • -target_method or –target_offset -> 处理输入文件的偏移量或者函数名称。
    • -call_convention – -函数调用约定,比如 thiscall,stdcall,cdecl,fastcall等
  3. 程序参数,后面跟着@@

动手:WinAFL状态屏幕

image-20210602103105193

详细情况说明可看官方文档: https://github.com/google/AFL/blob/master/docs/status_screen.txt

动手:分析崩溃并找到根本原因

  • 使用Visual Studio
    • 调试源代码,运行崩溃文件,并跟踪执行流程,查找根本原因。
  • 使用windbg
    • 使用崩溃文件调试可执行文件并查找根本原因

开搞真实的商业应用程序

对MDB文件进行fuzz

  • Fuzz MDB 文件的harness

    • 使用CDao数据库对象
    • 打开MDB文件
    • 关闭它
    • 解析代码在msrd3x40.dll中
    • db.open将从这个dll中调用函数
    • 如果文件结构不正确,我们的程序将崩溃
    • 这个harness导致了13个CVE

    image-20210602103951576

  • 开始fuzz

    • 编译这个c文件
    • 从谷歌收集一些MDB文件
    • 用winafl来fuzz它

CVE-2018-8423和CVE-2019-0576分析

CVE-2018-8423

image-20210602104133063

image-20210602104749401

image-20210602104821596

  • 所以它被修复了,是吗?

image-20210602104933026

CVE-2019-0576

image-20210602105031369

image-20210602105110211

  • 它最终是如何解决的?

image-20210602105135986

在Windows下如何追踪分类Crash?

  • 人工手动一个个分析崩溃是非常困难的
  • 可以使用python + winappdbg 简单自动化
  • 编写自己的工具?
  • 使用bugid

总结

  • 模糊测试有助于全面理解软件安全
    • 帮助编写更好的代码
    • 可以帮助找到使用正常测试找不到的问题
    • 帮助保护软件的安全
    • 软件开发生命周期的一部分
  • 需要大量的艰苦的工作
    • 会面临各种零碎的问题,任何小问题都会导致不工作
    • 花费无数小时去分析和解决这些问题
    • 期望供应商进行后续跟进
    • 结果被拒绝
  • 但最终,这是值得的☺