欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

通过libFuzzer实现结构敏感型的模糊测试技术(上)

来源:本站整理 作者:佚名 时间:2019-03-11 TAG: 我要投稿

生成型Fuzzer通常以单一输入类型为目标,根据预定义的语法来生成输入数据,例如csmith(可以生成有效的C程序)和Peach(能够生成任何类型的输入,但需要将这种类型表示为语法定义形式)。
对于覆盖率导向的突变型Fuzzer(如libFuzzer或AFL)来说,其目标并不局限于单个输入类型,也不需要语法定义。因此,突变型Fuzzer通常比生成型Fuzzer更容易设置和使用。但是,由于缺少输入文法,所以对复杂输入类型进行模糊测试的时候,效率较低,因为任何经传统的突变(例如位翻转)而得到的输入,在解析的早期都会被目标API所拒绝,也就是说,生成了许多无效输入。
然而,通过适当的处理之后,也可以将libFuzzer转换为适用于特定输入类型的语法敏感(即结构敏感)型模糊测试引擎。
示例:压缩
下面,我们将通过一个简单的示例,来演示如何使用libFuzzer进行结构敏感型模糊测试的大致过程。
好了,我们先来看看模糊测试的对象:它接收Zlib压缩的数据,并对其进行解压处理,如果非压缩形式的输入中的前两个字节是“F”和“U”,就会崩溃。
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
  uint8_t Uncompressed[100];
  size_t UncompressedLen = sizeof(Uncompressed);
  if (Z_OK != uncompress(Uncompressed, &UncompressedLen, Data, Size))
    return 0;
  if (UncompressedLen
这是一个非常简单的测试目标,但是传统的通用Fuzzer(包括libFuzzer)实际上根本无法发现崩溃点。这是为什么呢?因为它们进行突变处理时,会对压缩数据进行操作,从而导致生成的所有输入对于解压缩都是无效的。
为此,我们必须借助于自定义mutator(又名libFuzzer插件)。所谓自定义mutator,其实就是具有固定签名的用户自定义函数,其执行以下操作:
· 根据指定的语言语法来分析输入数据(在我们的示例中,它会对压缩数据进行解压处理)。如果解析失败,它将返回符合语法的伪输入(这里,它将返回一个压缩字节序列Hi)。
· 让输入(在本例中为未压缩的原始数据)的解析表示形式发生突变。自定义mutator可以通过函数LLVMFuzzerMutate请求libFuzzer对原始数据的某些部分进行赋值。
· 对突变后的表示形式进行序列化(在我们的示例中,就是进行压缩处理)。
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
                                          size_t MaxSize, unsigned int Seed) {
  uint8_t Uncompressed[100];
  size_t UncompressedLen = sizeof(Uncompressed);
  size_t CompressedLen = MaxSize;
  if (Z_OK != uncompress(Uncompressed, &UncompressedLen, Data, Size)) {
    // The data didn't uncompress. Return a dummy...
  }
  UncompressedLen =
      LLVMFuzzerMutate(Uncompressed, UncompressedLen, sizeof(Uncompressed));
  if (Z_OK != compress(Data, &CompressedLen, Uncompressed, UncompressedLen))
    return 0;
  return CompressedLen;
}
现在,请运行该示例。首先,让我们在不使用自定义mutator的情况下编译该测试对象:
% clang -O -g CompressedTest.cpp -fsanitize=fuzzer -lz
% ./a.out
...
INFO: A corpus is not provided, starting from an empty corpus
#2      INITED cov: 2 ft: 3 corp: 1/1b lim: 4 exec/s: 0 rss: 25Mb
#2097152        pulse  cov: 2 ft: 3 corp: 1/1b lim: 4096 exec/s: 1048576 rss: 25Mb
#4194304        pulse  cov: 2 ft: 3 corp: 1/1b lim: 4096 exec/s: 1048576 rss: 25Mb
#8388608        pulse  cov: 2 ft: 3 corp: 1/1b lim: 4096 exec/s: 1198372 rss: 26Mb
#16777216       pulse  cov: 2 ft: 3 corp: 1/1b lim: 4096 exec/s: 1290555 rss: 26Mb
#33554432       pulse  cov: 2 ft: 3 corp: 1/1b lim: 4096 exec/s: 1342177 rss: 26Mb
#67108864       pulse  cov: 2 ft: 3 corp: 1/1b lim: 4096 exec/s: 1398101 rss: 26Mb
...
如您所见,这里的覆盖率( cov:2)并不会增加,因为目标中没有执行新的检测代码。即便使用Zlib,在模糊测试期间提供更多的覆盖率反馈,libFuzzer也不太可能发现崩溃点。
下面,再次运行该测试目标代码,但这次使用自定义mutator:
% clang -O -g CompressedTest.cpp -fsanitize=fuzzer -lz -DCUSTOM_MUTATOR
% ./a.out
...
INFO: A corpus is not provided, starting from an empty corpus
#2      INITED cov: 2 ft: 3 corp: 1/1b lim: 4 exec/s: 0 rss: 25Mb
#512    pulse  cov: 2 ft: 3 corp: 1/1b lim: 8 exec/s: 256 rss: 26Mb
#713    NEW    cov: 3 ft: 4 corp: 2/11b lim: 11 exec/s: 237 rss: 26Mb L: 10/10 MS: 1 Custom-
#740    NEW    cov: 4 ft: 5 corp: 3/20b lim: 11 exec/s: 246 rss: 26Mb L: 9/10 MS: 3 Custom-EraseBytes-Cus
#1024   pulse  cov: 4 ft: 5 corp: 3/20b lim: 11 exec/s: 341 rss: 26Mb
#2048   pulse  cov: 4 ft: 5 corp: 3/20b lim: 21 exec/s: 682 rss: 26Mb

[1] [2] [3]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载