@ -82,16 +82,16 @@
< meta name = "description" content = "接触这个词语已经有一年了, 但还没有学习过更没有上手实践过, 正好趁这个机会好好弄弄AFL。提起模糊测试, 我们总会联想起这样或那样的专业术语——测试用例、代码覆盖率、执行路径等等, 你可能和我一样一头雾水, 这次我们就来看个明白 0x01 模糊测试首先, 模糊测试( Fuzzing) 是一种测试手段, 它把系统看成一个摸不清内部结构的黑盒, 只是向其输入接口随机地发送合法测试用例, 这些用例并不是开发者所预期的输入" >
< meta name = "keywords" content = "AFL,模糊测试" >
< meta property = "og:type" content = "article" >
< meta property = "og:title" content = " AFL初探 ">
< meta property = "og:title" content = " 模糊测试与 AFL">
< meta property = "og:url" content = "https://cool-y.github.io/2019/07/01/AFL-first-learn/index.html" >
< meta property = "og:site_name" content = "混元霹雳手" >
< meta property = "og:description" content = "接触这个词语已经有一年了, 但还没有学习过更没有上手实践过, 正好趁这个机会好好弄弄AFL。提起模糊测试, 我们总会联想起这样或那样的专业术语——测试用例、代码覆盖率、执行路径等等, 你可能和我一样一头雾水, 这次我们就来看个明白 0x01 模糊测试首先, 模糊测试( Fuzzing) 是一种测试手段, 它把系统看成一个摸不清内部结构的黑盒, 只是向其输入接口随机地发送合法测试用例, 这些用例并不是开发者所预期的输入" >
< meta property = "og:locale" content = "zh-Hans" >
< meta property = "og:image" content = "https://image.3001.net/images/20181207/1544168163_5c0a22e3eedce.jpg" >
< meta property = "og:image" content = "http://lcamtuf.coredump.cx/afl/afl_gzip.png" >
< meta property = "og:updated_time" content = "2019-07-09T09: 10:56.248 Z">
< meta property = "og:updated_time" content = "2019-07-09T09: 27:22.887 Z">
< meta name = "twitter:card" content = "summary" >
< meta name = "twitter:title" content = " AFL初探 ">
< meta name = "twitter:title" content = " 模糊测试与 AFL">
< meta name = "twitter:description" content = "接触这个词语已经有一年了, 但还没有学习过更没有上手实践过, 正好趁这个机会好好弄弄AFL。提起模糊测试, 我们总会联想起这样或那样的专业术语——测试用例、代码覆盖率、执行路径等等, 你可能和我一样一头雾水, 这次我们就来看个明白 0x01 模糊测试首先, 模糊测试( Fuzzing) 是一种测试手段, 它把系统看成一个摸不清内部结构的黑盒, 只是向其输入接口随机地发送合法测试用例, 这些用例并不是开发者所预期的输入" >
< meta name = "twitter:image" content = "https://image.3001.net/images/20181207/1544168163_5c0a22e3eedce.jpg" >
@ -129,7 +129,7 @@
< title > AFL初探 | 混元霹雳手< / title >
< title > 模糊测试与 AFL | 混元霹雳手< / title >
@ -325,7 +325,7 @@
< h1 class = "post-title" itemprop = "name headline" > AFL初探 < / h1 >
< h1 class = "post-title" itemprop = "name headline" > 模糊测试与 AFL< / h1 >
< div class = "post-meta" >
@ -387,7 +387,7 @@
< span id = "/2019/07/01/AFL-first-learn/" class = "leancloud_visitors" data-flag-title = " AFL初探 ">
< span id = "/2019/07/01/AFL-first-learn/" class = "leancloud_visitors" data-flag-title = " 模糊测试与 AFL">
< span class = "post-meta-divider" > |< / span >
< span class = "post-meta-item-icon" >
< i class = "fa fa-eye" > < / i >
@ -479,7 +479,7 @@
< hr >
< h1 id = "0x02-AFL快速入门" > < a href = "#0x02-AFL快速入门" class = "headerlink" title = "0x02 AFL快速入门" > < / a > 0x02 < a href = "http://lcamtuf.coredump.cx/afl/QuickStartGuide.txt" target = "_blank" rel = "noopener" > AFL快速入门< / a > < / h1 > < p > 1) 用< code > make< / code > 编译AFL。如果构建失败, 请参阅docs / INSTALL以获取提示。< br > 2) 查找或编写一个相当快速和简单的程序, 该程序从< strong > < em > 文件或标准输入< / em > < / strong > 中获取数据, 以一种有价值的方式处理它, 然后干净地退出。如果测试网络服务, 请将其修改为在前台运行并从stdin读取。在对使用校验和的格式进行模糊测试时, 也要注释掉校验和验证码。< br > 遇到故障时, 程序必须正常崩溃。注意自定义SIGSEGV或SIGABRT处理程序和后台进程。有关检测非崩溃缺陷的提示, 请参阅< code > docs/README< / code > 中的第11节。< br > 3) 使用afl-gcc编译要模糊的程序/库。一种常见的方法是:< br > < figure class = "highlight plain" > < table > < tr > < td class = "gutter" > < pre > < span class = "line" > 1< / span > < br > < span class = "line" > 2< / span > < br > < / pre > < / td > < td class = "code" > < pre > < span class = "line" > $ CC = /path/to/afl-gcc CXX =/path/to/afl-g++ ./configure --disable-shared< / span > < br > < span class = "line" > $ make clean all< / span > < br > < / pre > < / td > < / tr > < / table > < / figure > < / p >
< p > 如果程序构建失败,请联系 < a href = "mailto:afl&# 45;users@googlegroups.c ;om" target = "_blank" rel = "noopener" > a f l &# 45;u s e r s @ g o o g l e g r o u p s . c ;o m < / a > 。< br > 4) 获取一个对程序有意义的小而有效的输入文件。在模糊详细语法( SQL, HTTP等) 时, 也要创建字典, 如< code > dictionaries/README.dictionaries< / code > 中所述。< br > 5) 如果程序从stdin读取, 则运行< code > afl-fuzz< / code > ,如下所示:< br > < code > ./afl-fuzz -i testcase_dir -o findings_dir -- /path/to/tested/program [... program' s cmdline ...]< / code > < br > 如果程序从文件中获取输入,则可以在程序的命令行中输入@@; AFL会为您放置一个自动生成的文件名。< / p >
< p > 如果程序构建失败,请联系 < a href = "mailto:afl&# x2d;users@googlegroups.c ;om" target = "_blank" rel = "noopener" > a f l &# x2d;u s e r s @ g o o g l e g r o u p s . c ;o m < / a > 。< br > 4) 获取一个对程序有意义的小而有效的输入文件。在模糊详细语法( SQL, HTTP等) 时, 也要创建字典, 如< code > dictionaries/README.dictionaries< / code > 中所述。< br > 5) 如果程序从stdin读取, 则运行< code > afl-fuzz< / code > ,如下所示:< br > < code > ./afl-fuzz -i testcase_dir -o findings_dir -- /path/to/tested/program [... program' s cmdline ...]< / code > < br > 如果程序从文件中获取输入,则可以在程序的命令行中输入@@; AFL会为您放置一个自动生成的文件名。< / p >
< p > < strong > 一些参考文档< / strong > < / p >
< blockquote >
< p > < a href = "http://lcamtuf.coredump.cx/afl/README.txt" target = "_blank" rel = "noopener" > docs/README< / a > - AFL的一般介绍, < br > < a href = "https://github.com/mirrorer/afl/blob/master/docs/perf_tips.txt" target = "_blank" rel = "noopener" > docs/perf_tips.txt< / a > - 关于如何快速模糊的简单提示,< br > < a href = "http://lcamtuf.coredump.cx/afl/status_screen.txt" target = "_blank" rel = "noopener" > docs/status_screen.txt< / a > - UI中显示的花絮的解释, < br > < a href = "https://github.com/mirrorer/afl/blob/master/docs/parallel_fuzzing.txt" target = "_blank" rel = "noopener" > docs/parallel_fuzzing.txt< / a > - 关于在多个核上运行AFL的建议< br > < a href = "http://lcamtuf.coredump.cx/afl/demo/" target = "_blank" rel = "noopener" > Generated test cases for common image formats< / a > - 生成图像文件测试用例的demo< br > < a href = "http://lcamtuf.coredump.cx/afl/technical_details.txt" target = "_blank" rel = "noopener" > Technical “whitepaper” for afl-fuzz< / a > - 技术白皮书< / p >
@ -496,10 +496,10 @@
< / ol >
< hr >
< h1 id = "0x04-AFL-README" > < a href = "#0x04-AFL-README" class = "headerlink" title = "0x04 AFL README" > < / a > 0x04 < a href = "http://lcamtuf.coredump.cx/afl/README.txt" target = "_blank" rel = "noopener" > AFL README< / a > < / h1 > < blockquote >
< p > Written and maintained by Michal Zalewski < a href = "mailto:lc&# 97;mtuf@google.c ;om" target = "_blank" rel = "noopener" > l c &# 97;m t u f @ g o o g l e . c ;o m < / a > < / p >
< p > Written and maintained by Michal Zalewski < a href = "mailto:lc&# x61;mtuf@google.c ;om" target = "_blank" rel = "noopener" > l c &# x61;m t u f @ g o o g l e . c ;o m < / a > < / p >
< p > Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved.< br > Released under terms and conditions of Apache License, Version 2.0.< / p >
< p > For new versions and additional information, check out:< br > < a href = "http://lcamtuf.coredump.cx/afl/" target = "_blank" rel = "noopener" > http://lcamtuf.coredump.cx/afl/< / a > < / p >
< p > To compare notes with other users or get notified about major new features,< br > send a mail to < a href = "mailto:&# x61;fl-users+subscribe@googlegroups.com ;" target = "_blank" rel = "noopener" > &# x61;f l - u s e r s + s u b s c r i b e @ g o o g l e g r o u p s . c o m ;< / a > .< / p >
< p > To compare notes with other users or get notified about major new features,< br > send a mail to < a href = "mailto:&# 97;fl-users+subscribe@googlegroups.com ;" target = "_blank" rel = "noopener" > &# 97;f l - u s e r s + s u b s c r i b e @ g o o g l e g r o u p s . c o m ;< / a > .< / p >
< p > < strong > See QuickStartGuide.txt if you don’ t have time to read this file.< / strong > < / p >
< / blockquote >
< h2 id = "1) 具有导向性的模糊测试的挑战" > < a href = "#1) 具有导向性的模糊测试的挑战" class = "headerlink" title = "1) 具有导向性的模糊测试的挑战" > < / a > 1) 具有导向性的模糊测试的挑战< / h2 > < p > Fuzzing是用于识别真实软件中的安全问题的最强大且经过验证的策略之一;它负责安全关键软件中迄今为止发现的绝大多数远程代码执行和权限提升漏洞。< br > 不幸的是,模糊测试也不够有力。盲目的、随机的变异使得它不太可能在测试代码中达到某些代码路径,从而使一些漏洞超出了这种技术的范围。< br > 已经有许多尝试来解决这个问题。早期方法之一 - 由Tavis Ormandy开创 - 是一种 < strong > 语义库蒸馏( corpus distillation) < / strong > 。网上找到的一些大型语料库中往往包含大量的文件,这时就需要对其精简,该方法依赖于覆盖信号从大量高质量的候选文件语料库中选择有趣种子的子集,然后通过传统方式对其进行模糊处理。该方法非常有效,但需要这样的语料库随时可用。正因为如此,< strong > 代码覆盖率< / strong > 也只是衡量程序执行状态的一个简单化的度量, 这种方式并不适合后续引导fuzzing测试的。< br > 其他更复杂的研究集中在诸如 < strong > 程序流分析( “concoic execution”) , 符号执行或静态分析< / strong > 等技术上。所有这些方法在实验环境中都非常有前景,但在实际应用中往往会遇到可靠性和性能问题 - 部分高价值的程序都有非常复杂的内部状态和执行路径, 在这一方面符号执行和concolic技术往往会显得不够健壮( 如路径爆炸问题) , 所以仍然稍逊于传统的fuzzing技术。< / p >
@ -510,8 +510,10 @@
< li > 3) 尝试将测试用例修剪到不会改变程序测量行为的最小尺寸, < / li >
< li > 4) 使用平衡且经过充分研究的各种传统模糊测试策略反复改变文件, < / li >
< li > 5) 如果任何生成的编译导致由instrumentation记录的新状态转换, 则将变异输出添加为队列中的新条目。< / li >
< li > 6) 转到2。< br > < img src = "https://image.3001.net/images/20181207/1544168163_5c0a22e3eedce.jpg" alt > < br > 发现的测试用例也会定期被淘汰, 以消除那些被更新, 更高覆盖率的发现所淘汰的测试用例。并经历其他几个插桩驱动( instrumentation-driven) 的努力最小化步骤。< br > 作为模糊测试过程的一个副作用,该工具创建了一个小型,独立的有趣测试用例集。这些对于播种其他劳动力或资源密集型测试方案非常有用 - 例如,用于压力测试浏览器,办公应用程序,图形套件或闭源工具。< br > 该模糊器经过全面测试,可提供远远优于盲目模糊或仅覆盖工具的开箱即用性能。< / li >
< li > 6) 转到2。< / li >
< / ul >
< p > < img src = "https://image.3001.net/images/20181207/1544168163_5c0a22e3eedce.jpg" width = "60%" div align = "center/" > < / p >
< p > 发现的测试用例也会定期被淘汰, 以消除那些被更新, 更高覆盖率的发现所淘汰的测试用例。并经历其他几个插桩驱动( instrumentation-driven) 的努力最小化步骤。< br > 作为模糊测试过程的一个副作用,该工具创建了一个小型,独立的有趣测试用例集。这些对于播种其他劳动力或资源密集型测试方案非常有用 - 例如,用于压力测试浏览器,办公应用程序,图形套件或闭源工具。< br > 该模糊器经过全面测试,可提供远远优于盲目模糊或仅覆盖工具的开箱即用性能。< / p >
< h2 id = "3) 用于AFL的插桩( instrumentation) 程序" > < a href = "#3) 用于AFL的插桩( instrumentation) 程序" class = "headerlink" title = "3) 用于AFL的插桩( instrumentation) 程序" > < / a > 3) 用于AFL的插桩( instrumentation) 程序< / h2 > < p > 当源代码可用时,可以通过配套工具 < strong > 注入instrumentation< / strong > , 该工具可作为第三方代码的任何标准构建过程中gcc或clang的替代品。< br > instrumentation具有相当适度的性能影响;与afl-fuzz实现的其他优化相结合, 大多数程序可以像传统工具一样快速或甚至更快地进行模糊测试。< / p >
< p > < strong > 重新编译目标程序< / strong > 的正确方法可能会有所不同,具体取决于构建过程的具体情况,但几乎通用的方法是:< br > < figure class = "highlight plain" > < table > < tr > < td class = "gutter" > < pre > < span class = "line" > 1< / span > < br > < span class = "line" > 2< / span > < br > < span class = "line" > 3< / span > < br > < / pre > < / td > < td class = "code" > < pre > < span class = "line" > $ CC = /path/to/afl/afl-gcc ./configure< / span > < br > < span class = "line" > $ make clean all< / span > < br > < span class = "line" > 对于C ++程序, 您还需要将CXX = / path /设置为/ afl / afl g ++。< / span > < br > < / pre > < / td > < / tr > < / table > < / figure > < / p >
< p > clang组件( afl-clang和afl-clang ++)可以以相同的方式使用; clang用户也可以选择利用更高性能的检测模式, 如llvm_mode / README.llvm中所述。< / p >
@ -621,7 +623,7 @@
< p > 除了检测新的tuple之外, AFL的fuzzer也会粗略地记录tuple的< strong > 命中数(hit counts)< / strong > 。这些被分割成几个buckets: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+< / p >
< p > 从某种意义来说, buckets里边的数目是有实际意义的: 它是一个8-bit counter和一个8-position bitmap的映射。8-bit counter是由桩生成的, 8-position bitmap则依赖于每个fuzzer记录的已执行的tuple的命中数。< br > 单个bucket的改变会被忽略掉: 在程序控制流中, bucket的转换会被标记成一个interesting change, 传入evolutionary(见第三部分)进行处理。< br > 通过命中次数(hit count),我们能够分辨控制流是否发生变化。例如一个代码块被执行了两次,但只命中了一次。并且这种方法对循环的次数不敏感(循环47次和48次没区别)。< br > 这种算法通过限制内存和运行时间来保证效率。< / p >
< p > 另外, 算法通过设置执行超时, 来避免效率过低的fuzz。从而进一步发现效率比较高的fuzz方式。< / p >
< h2 id = "3) 输入队列的进化-Evolving-the-input-queue" > < a href = "#3) 输入队列的进化-Evolving-the-input-queue" class = "headerlink" title = "3) 输入队列的进化(Evolving the input queue)" > < / a > 3) 输入队列的进化(Evolving the input queue)< / h2 > < p > 经变异的测试用例,会使程序产生 < strong > < em > 新的状态转移< / em > < / strong > 。这些测试用例稍后被添加到 input 队列中,用作下一个 fuzz 循环。它们补充但不替换现有的发现。< br > 这种算法允许工具可以持续探索不同的代码路径,即使底层的数据格式可能是完全不同的。如下图:< br > < img src = "http://lcamtuf.coredump.cx/afl/afl_gzip.png" alt> < / p >
< h2 id = "3) 输入队列的进化-Evolving-the-input-queue" > < a href = "#3) 输入队列的进化-Evolving-the-input-queue" class = "headerlink" title = "3) 输入队列的进化(Evolving the input queue)" > < / a > 3) 输入队列的进化(Evolving the input queue)< / h2 > < p > 经变异的测试用例,会使程序产生 < strong > < em > 新的状态转移< / em > < / strong > 。这些测试用例稍后被添加到 input 队列中,用作下一个 fuzz 循环。它们补充但不替换现有的发现。< br > 这种算法允许工具可以持续探索不同的代码路径,即使底层的数据格式可能是完全不同的。如下图:< br > < img src = "http://lcamtuf.coredump.cx/afl/afl_gzip.png" width= "60%" div align= "cen ter/" > < / p >
< p > 这里有一些这种算法在实际情况下例子:< / p >
< p > < a href = "https://lcamtuf.blogspot.com/2014/11/pulling-jpegs-out-of-thin-air.html" target = "_blank" rel = "noopener" > pulling-jpegs-out-of-thin-air< / a > < / p >
< p > < a href = "http://lcamtuf.blogspot.com/2014/11/afl-fuzz-nobody-expects-cdata-sections.html" target = "_blank" rel = "noopener" > afl-fuzz-nobody-expects-cdata-sections< / a > < / p >