本文是对于模糊测试方面的小总结,计划三篇;第一篇概述;第二篇afl;第三篇Winafl。非大部头书,只提取关键信息。
本篇为第一篇:概述。

总览

  • Part 1

    • 漏洞 、 模糊测试过程 、 crash分类 、 根本原因分析(RCA)
  • Part 2

    • 使用 AFL 在 linux 上进行模糊测试
  • Part 3

    • 使用 WinAFL 在Windows上进行模糊测试

Part 1 总览

  • ​ 漏洞
    • 不同类型的漏洞
      • 整数溢出
      • 栈/堆溢出
      • 越界读写 (OOB)
      • 释放后使用/双重释放(UAF/DF)
    • 人工识别C程序中的漏洞
  • 什么是模糊测试?
    • 模糊测试的需求
    • 模糊测试的种类
    • Fuzz一个程序的具体过程
  • Crash分析
    • Crash追踪
    • 根本原因分析(RCA)
  • 向供应商/漏洞赏金报告问题

漏洞

  • 软件里的漏洞

    • 例如:如果将长度大于1000字节数据的URL get请求发送到Web服务器,服务器可能会崩溃
  • 可用于执行各种恶意的活动

    • 远程执行代码——有人可以远程的执行恶意代码,危害性十足

    • 拒绝服务–可能会使软件或整个系统崩溃

    • 特权升级–从本地帐户到管理员帐户

      以上三种都可转换为可利用的Exploits

  • 在恶意网络攻击中使用它们会造成何种危害?

    • 导致系统受损,勒索软件,特洛伊木马,僵尸网络,比特币矿工,数据盗窃等
    • 行业影响–数据盗窃,生产力损失
  • 常见漏洞类型

    • 整数溢出/下溢,栈/堆溢出,超出范围的读/写,释放后使用,双重释放可以转换为漏洞利用

不同类型的漏洞

先说溢出,是指计算机进行运算产生的结果若超出机器所能表示的范围。

溢出有上溢出和下溢出之分,对整型数来说,从正方向超过了数的表示范围,称为上溢出(overflow),从负方向超过了数的表示范围,称为下溢出(underflow)。

就像往水桶里装水,水满则溢,变量也是这样,如果要存储的值超过了变量所能提供的位数,就会出现溢出。

整数溢出(上溢)

  • ​ 它是什么?

    • 整数 这一数据类型中的弱点,即它们存储数据的方式。
    • 例子:
      • unsigned int j
      • int i
      • int整数的大小为 4 字节,一个字节 8 bit
      • MAX 值 : 11111111111111111111111111111111
      • 2^32
      • Signed vs unsigned?
        • MSB(most significant bit 最高有效位)是适用于有符号(signed)整数的
        • 1 = 00000000000000000000000000000001
        • -1 = 10000000000000000000000000000001
        • 有符号整数最大值为 int = **0x7**FFFFFFF
        • 无符号整数最大值为 int = **0xF**FFFFFFF
    • 在这种情况下会发生什么?
      • int i
      • unsigned int j
      • j = 0xFFFFFFFF + 1
        • 结果将变为0,进位1位将被截断
      • i= 0x7FFFFFFFF + 1
        • 结果将变为-0x80000000(负数)

    image-20210302133250527

    ​ 整数溢出,由于进位会被截断,因此数量非常少;在该案例中直接变成0.

image-20210302140338356

在1961行MP4_GET4BYTES函数读取.mov file的长度,苹果的quicktime会将这个值存储在i_len变量里面随后分配一块内存。

问题出在1965行之中,如果我们“精巧”地构造mov文件使其i_len恰好为0xFFFFFFFF,则malloc(i_len+1)就会恰好整数溢出为0,变成分配0空间。它不会报错,但是不会分配所需的内存。配合1966行不断地循环赋值,这些都会存储在缓冲区之中,可能导致代码执行。

整数溢出(下溢)

  • 它是什么?

    • int 的大小 = 4 bytes
    • Signed vs unsigned?
      • signed int 范围 = -0x80000000 to 0x7FFFFFFF
      • unsigned int 范围 = 0 to 0xFFFFFFFF
  • 在这种情况下会发生什么?

    • int i;
    • i = -0x80000000 –1 = 0x7FFFFFFF
    • i = 尽可能高的正数

    image-20210302160017572

整数下溢后,数量变为非常大,由负数(-)变为正数(+)

image-20210302160250715

栈/堆溢出

栈溢出
  • 本地变量存储在栈中
  • 栈是有限尺寸
  • 溢出局部变量,可损坏堆栈上的其他数据。
  • 例子:

image-20210302160714386

image-20210302160746496

堆溢出
  • 动态内存分配
  • 从堆中分配
  • 堆中的溢出会损坏堆中的其他数据
  • 例子:

image-20210302161027982

越界读写

栈越界读写
  • 超出堆栈内存允许限度的内存访问或编写操作
  • 可能导致地址的违法访问
  • 例子:

image-20210302161342372

image-20210302161403579

堆越界读写
  • 超出堆内存允许限度的内存访问或书写操作
  • 可能导致地址的违法访问
  • 例子:

image-20210302161549838

UAF 与 Double free 漏洞

Use After Free
  • 释放后使用内存
  • 可能导致程序崩溃或意外行为
  • 例子:

image-20210302161823661

image-20210302161841850

Double Free
  • 多次(两次?)释放分配的内存
  • 可能导致程序崩溃
  • 例子:

image-20210302161941109

尝试一下:自己动手识别漏洞

image-20210302162319575

追踪BUG 与 模糊测试

追踪BUG

  • 手动代码审核
    • 需要大量的时间,非常缓慢
    • 无法覆盖所有代码路径
    • 代码基数大,单人无法充分进行审核
    • 不是很有成效
    • 重要的BUG可能会被粗心错过
    • 无法涵盖所有场景
  • 自动化
    • 自动错误查找,非常快
    • 可以覆盖大多数代码路径
    • 无需担心代码的大小
    • 可以由个人完成
    • 可以自动进一步归类统计有关崩溃、问题,并通知相关人员

什么是模糊测试

  • 程序中的自动错误查找过程

    1. 向程序馈送输入
    2. 实时监控程序的崩溃(crashes)状态
    3. 保存崩溃测试案例
    4. 不断生成新的测试案例
    5. 转到步骤1

    image-20210302163409721

模糊测试Fuzzer的分类

愚蠢的Fuzzer

  • 完全随机的输入
  • 无需了解文件格式/网络协议
  • 可能需要很多时间(取决于你的运气)
  • 例子:radmasa

改良后的Fuzzer

  • 根据预先定义的结构创建输入
  • 需要了解文件格式
  • 需要了解网络协议
  • 例子:peach,sulley

覆盖引导的Fuzzer

  • 使用界面监控程序流
  • 无需了解文件格式
  • 变异文件并检查新代码路径覆盖/崩溃
    • 发现新代码路径——>添加到队列
    • 崩溃——>保存输入
  • 例子:AFL, WinAFL, HonggFuzz, libfuzzer

覆盖率与插桩

基本块和覆盖率计算

Basic block

  • 没有分支的连续代码行
  • 入口点–控制进入此基本块
  • 退出点-控制转到另一个基本块

image-20210302212900999

Code Coverage

image-20210302170801857

插桩

如何跟踪运行中的程序执行过程?

  • 基本方法-添加打印定义的代码和解试

image-20210302213213951

  • 无法提供太多数据
  • 需要人工的工作

如果源代码可用

  • 在编译时插桩
  • 在编译过程中加入插桩代码

image-20210302213616983

  • 可以自动化执行,如实时的覆盖测量,避免人工耗费精力

如果源代码不可用

  • 在运行时插桩
  • 在运行时添加插桩代码

image-20210302213849984

以AFL为例的插桩详细

image-20210302214600718

Fuzz过程

覆盖率引导的模糊测试过程

image-20210302215452140

语料库收集

语料库精简

  • 有一个特别大的语料库是好事还是坏事?
    • 什么样的文件尺寸算是特别大?
      • 位翻转操作(Bitflip/byteflip)将需要大量时间
      • 10MB = 10485760 Bytes
    • 如果许多文件触发相同的代码路径怎么办?
      • 模糊测试将花费不必要的周期时间来运行它们
  • 需要最小化输入语料库
    • 筛选出不会导致新路径的文件,删掉他们
    • 筛选出大的文件,删掉他们
  • 怎么做?
    • afl-cmin–iinput –o mininput–./program @@

Crashes——>探寻根因——>确认漏洞

根因分析(Root cause analysis RCA)

  • 我们发现了一个崩溃——现在要干什么?
    • 文件中的哪个字段函数部分?
    • 该字段函数的价值?
    • 程序中的哪个条件触发的?

1——2个Crash

  • 人工分析

成百上千的Crashes?

  • 如何分析分类它们?

    • Crashwalk, atriage, afl-collect,BUGid…

向供应商/或Bug 赏金机构报告

  • 首先向供应商报告
  • 大部分供应商有一个类似于 security@vendor.com的安全邮箱
  • 不要公开披露自己的发现
  • 你可能会因为crash而得到奖励,或者CVE编号