谷歌开源模糊测试工具 ClusterFuzz 尝鲜记录

栏目: Python · 发布时间: 6年前

内容简介:模糊测试,是指用随机坏数据(也称做 fuzz)攻击一个程序,然后等着观察哪里遭到了破坏。(出自早在八年前,google 内部就在建设和使用模糊测试的工具来测试其内部的应用,而在两年前, google 推出了

背景

模糊测试,是指用随机坏数据(也称做 fuzz)攻击一个程序,然后等着观察哪里遭到了破坏。(出自 模糊测试 )。一直以来都有不少的模糊测试工具,但大多只集中在数据生成,执行和异常检测依赖人工,未有比较完整的方案。

早在八年前,google 内部就在建设和使用模糊测试的 工具 来测试其内部的应用,而在两年前, google 推出了 OSS-Fuzz 服务,用于给开源项目的进行免费的模糊测试服务,可自动在新版本代码提交后自动完成 测试->异常检测->issue登记->老版本issue回归及自动关闭 的功能。背后使用的就是 ClusterFuzz 技术。流程图如下:

谷歌开源模糊测试工具 ClusterFuzz 尝鲜记录

而在过年前,google 开源了 ClusterFuzz ,并解决了原有 ClusterFuzz 必须依赖 Google Cloud 提供的服务这个问题,提供了本地运行的解决方案。根据官方介绍,它具备如下功能:

  • 高度可扩展,谷歌的内部实例运行在超过 25000 台机器上
  • 准确的去副本化(Accurate deduplication)
  • 问题跟踪器的全自动错误归档和关闭
  • 最小化测试用例
  • 通过二分法回归查找
  • 提供分析 fuzzer 性能和崩溃率的统计信息(不支持本地部署)
  • 易于使用的 Web 界面,用于管理和查看崩溃
  • 支持引导模糊(例如 libFuzzer 和 AFL)和黑盒模糊测试

其大致执行流程如下:

谷歌开源模糊测试工具 ClusterFuzz 尝鲜记录

当然,方案并不完美,如模糊数据统计、崩溃数据统计等功能由于依赖 google cloud 强大的数据处理能力,本地运行时是用不了的。

官方说的总是美好的,现实是否这么完美呢?曾有人说,实践是检验真理的唯一标准,为了更好地了解这个工具,当然就要本地跑个 demo 玩下啦。

本地搭建及运行

要获得 ClusterFuzz 的完整功能,需要连接 Google Cloud Platform 。但结合国情,我们更期望了解它纯本地运行能做到什么,因此这次尝鲜主要尝试纯本地运行。

注意:虽然运行可以脱离 Google Cloud Platform ,但部分安装时用到的工具需要到 google 站点下载,所以,你懂得。

以下步骤均是在 macOS 10.14 上进行。

环境搭建

1、下载源码

git clone https://github.com/google/clusterfuzz
cd clusterfuzz

2、安装 google cloud sdk

进入 https://cloud.google.com/sdk/ ,按照引导安装 sdk 并配置好环境变量(mac 下可以直接用解压后的 install.sh 脚本一键安装),确认命令行可调用 gcloud 命令

$ gcloud -v
Google Cloud SDK 226.0.0
bq 2.0.38
core 2018.11.16
gsutil 4.34

3、安装 pythongo 运行环境。

特别注意:如果你使用的是 macOS 或者 Ubuntu、Debain,直接执行第4步即可,脚本里会自动安装 Python 和 go

python 要求 2.7.10 以上,但不能是 python 3。在 mac 上可以直接运行 brew install python@2 安装。

go 未要求版本,在 mac 上可以直接运行 brew install go 安装。我用的是 go1.11.5 darwin/amd64

4、安装其他依赖

针对

  • Ubuntu (14.04, 16.04, 17.10, 18.04, 18.10)
  • Debian 8 (jessie) or later
  • Recent versions of macOS with homebrew (experimental)

几个系统,官方已经内置了安装依赖的脚本,直接运行即可:

local/install_deps.bash

坑一,官方的脚本里第一行用了 -ex 参数,会导致运行脚本时如果有命令执行出错(如 brew install 时有些应用本地已经安装过,但非最新版本),直接退出程序。

可以通过 sed -i '' 's/bash -ex/bash -x/' local/install_deps* 命令直接去掉 -e 参数。已经给官方提了 issue

坑二,官方脚本里使用 python butler.py bootstrap 初始化环境时,会自动去 google 站点下载 chromedriver 相关的文件。

全局搜索了下源代码,只有跑单测的时候有用到 chromedriver ,所以可以直接注释掉这个函数:

diff --git a/src/local/butler/common.py b/src/local/butler/common.py
index 94b17b3..3e9de99 100644
--- a/src/local/butler/common.py
+++ b/src/local/butler/common.py
@@ -275,7 +275,7 @@ def install_dependencies(platform_name=None):
   _remove_invalid_files()
   execute('bower install --allow-root')

-  _install_chromedriver()
+  #_install_chromedriver()


 def symlink(src, target):

坑三,运行时会报错 Analysis of target '//local:create_gopath' failed; build aborted: no such package '@org_golang_google_api//iterator': failed to fetch org_golang_google_api: 2019/02/19 01:15:41 unrecognized import path "google.golang.org/api"

这是在运行 bazel 构建 go 环境的时候报错了,原因是 @org_golang_x_tools、@com_google_cloud_go、@org_golang_google_api 这几个第三方依赖网络原因获取不到。

尝试一:使用代理

因为 go 获取依赖有可能用 http ,也有可能用 git ,所以保险起见全部都配好代理:

export HTTP_PROXY=http://112.126.81.122:6$(date +%m%d)
export HTTPS_PROXY=${HTTP_PROXY}
git config --global https.proxy ${HTTP_PROXY}
git config --global http.proxy ${HTTP_PROXY}

可惜的是,配置完了还是不行,bazel 构建时提示 fatal: unable to access 'https://code.googlesource.com/google-api-go-client/': LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to code.googlesource.com:443 ,此路不通。

尝试二:修改运行环境,改为在网络本身就没问题的地方运行

嗯,哪里有这样的环境呢?一个是自己买云主机,另一个就是考虑用 docker hub 提供的构建环境了。看了下后面的使用步骤,也没有需要在源码目录做操作的部分,就选择 docker 吧。

动手 fork 了官方仓库,开始了漫长的尝试: https://github.com/chenhengjie123/clusterfuzz

目前还在尝试中,有新进展再更新。

后续部分翻译自官方文档,还没亲测,大家可以先看看了解,也欢迎不存在 go 问题的同学按照后续内容尝试下。

==========================================官方文档翻译分割线===============================================

执行过程会比较久(我装了快1个小时),而且中途可能会失败,需要重新运行,需要一些耐心。

执行完毕,会出现

Installation succeeded!
Please load virtualenv environment by running 'source ENV/bin/activate'.

的提示。

5、切换到 python 的 virtualenv

直接运行官方提供的脚本即可,但务必先完成上面的依赖库安装。

source ENV/bin/activate

校验是否一切就绪

$ python butler.py --help
python butler.py --help
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7.
usage: butler.py [-h]
                 {bootstrap,py_unittest,go_unittest,js_unittest,format,lint,package,deploy,run_server,run,run_bot,remote,clean_indexes,generate_datastore_models,create_config}
                 ...

运行本地实例

本地实例包含2个部分,一个是管理各个执行机器人的服务端,另一个是执行机器人。

启动本地服务

首次运行,添加 --bootstrap 进行各个数据的初始化

$ python butler.py run_server --bootstrap

非首次运行,务必去掉 --bootstrap 参数。

当看到 Starting admin server 日志出现时,表明已经启动完毕,可以通过打开 http://localhost:9000/ 打开管理员界面。

启动执行机器人

官方命令:

python butler.py run_bot --name my-bot /path/to/my-bot

其中 my-bot 可以替换为自己喜欢的名称。我改成了 fuzzing-bot

$ python butler.py run_bot --name fuzzing-bot `cwd`/fuzzing-bot

执行成功后,可在前一步的管理员界面看到机器人状态。

可通过

tail -f `cwd`/fuzzing-bot/bot.log

查看机器人实时日志输出。

开始测试

官方给了一个例子,寻找 OpenSSL 的心脏滴血内存溢出漏洞。下面按照给出的步骤执行。

编译一个包含这个漏洞和已经带有 fuzz 插桩的 OpenSSL

# 下载并解压包含这个漏洞的 OpenSSL :
curl -O https://www.openssl.org/source/openssl-1.0.1f.tar.gz
tar xf openssl-1.0.1f.tar.gz

# 使用 AScan 和 fuzzer 插桩编译 OpenSSL:
cd openssl-1.0.1f/
./config

# 注意:$CC 必须指向 clang 二进制文件。简单地说,按照这个命令来写就对了
make CC="$CC -g -fsanitize=address,fuzzer-no-link"
cd ..

# 下载 fuzz target 和它的数据依赖:
curl -O https://raw.githubusercontent.com/google/clusterfuzz/master/docs/setting-up-fuzzing/heartbleed/handshake-fuzzer.cc
curl -O https://raw.githubusercontent.com/google/clusterfuzz/master/docs/setting-up-fuzzing/heartbleed/server.key
curl -O https://raw.githubusercontent.com/google/clusterfuzz/master/docs/setting-up-fuzzing/heartbleed/server.pem

# 编译可用于 ClusterFuzz 的 OpenSSL fuzz target ($CXX 需要指向一个 clang++ 二进制文件):
$CXX -g handshake-fuzzer.cc -fsanitize=address,fuzzer openssl-1.0.1f/libssl.a \
  openssl-1.0.1f/libcrypto.a -std=c++17 -Iopenssl-1.0.1f/include/ -lstdc++fs   \
  -ldl -lstdc++ -o handshake-fuzzer

zip openssl-fuzzer-build.zip handshake-fuzzer server.key server.pem

上传 fuzzer 到 ClusterFuzz

1、进入 Jobs 页面,点击 【ADD NEW JOB】按钮

2、job 的各个输入框填写以下内容:

输入框名称 内容
Name libfuzzer_asan_linux_openssl
Platform LINUX
Templates libfuzzer engine_asan
Environment String CORPUS_PRUNE = True

3、把上一步打包的 openssl-fuzzer-build.zip 文件上传到 "Custom Build" 字段

4、点击 【ADD】 按钮,完成添加

5、点击【Select/modify jobs】,勾选 "libfuzzer_asan_linux_openssl" ,然后点击【SUBMIT】 按钮

执行及查看结果

通过查看本地的机器人执行日志,可以发现 fuzz libFuzzer libfuzzer_asan_linux_openssl 这个字符串,代表目前 fuzz 测试已经在进行中了。

稍等一会,会在日志中发现一个堆栈信息和 AddressSanitizer: heap-buffer-overflow 出现在日志中。

再稍等一会,可以在 <> 页面看到一个标题为 "Heap-buffer-overflow READ{*}" 的测试用例,这个就是 ClusterFuzz 发现的心脏滴血漏洞了。

扩展性

从官方文档上看,上面的例子只是用到了引导式 fuzz ,ClusterFuzz 还支持可任意扩展的黑盒 fuzz ,可支持使用 Python 编写 fuzz 生成器。此次由于时间关系未能尝试,有兴趣的同学可以尝试一下。

同时官方的 local 文件夹中有看到 docker 运行相关的脚本,相信未来会支持通过 docker 运行,降低环境配置成本。

局限性

从官方文档中可以看到,被测试的软件需要在编译时插入一些桩用于检测异常,而这个方案目前仅支持 C/C++ ,且主要用于内存地址检测。而对于我们平时接触到的 Java/python/go 应用,没有提供对应的方案,需要另行扩展。

小结及展望

ClusterFuzz 正如其名,一个集群运行的 Fuzz 工具。它提供了执行机器人管理以及一个非常简便的管理界面,也做到了和研发流程无缝的接入,甚至更进一步地做到了 bug 自动创建及修复检测。

从小的地方看,它让模糊测试通过集群获得了更高的执行效率和问题发现效率。

从大的地方看,它提供的整体流程,包含了自动报 bug 和检测 bug 修复情况,让大家只在需要的时候感知到它的存在,正是目前大部分 CI 实践中欠缺的最后一公里路,缺陷的自动上报与修复检测,值得我们思考补全我们的 CI 流程。

虽然目前并未提供除 C/C++ 之外的完整解决方案,但相信按照其扩展性,扩展到支持更多的语言并不是难题。期望未来有更多的同学参与扩展这个工具,形成开箱即用的解决方案。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ant Colony Optimization

Ant Colony Optimization

Marco Dorigo、Thomas Stützle / A Bradford Book / 2004-6-4 / USD 45.00

The complex social behaviors of ants have been much studied by science, and computer scientists are now finding that these behavior patterns can provide models for solving difficult combinatorial opti......一起来看看 《Ant Colony Optimization》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

html转js在线工具
html转js在线工具

html转js在线工具