内容简介:模糊测试,是指用随机坏数据(也称做 fuzz)攻击一个程序,然后等着观察哪里遭到了破坏。(出自早在八年前,google 内部就在建设和使用模糊测试的工具来测试其内部的应用,而在两年前, google 推出了
背景
模糊测试,是指用随机坏数据(也称做 fuzz)攻击一个程序,然后等着观察哪里遭到了破坏。(出自 模糊测试 )。一直以来都有不少的模糊测试工具,但大多只集中在数据生成,执行和异常检测依赖人工,未有比较完整的方案。
早在八年前,google 内部就在建设和使用模糊测试的 工具 来测试其内部的应用,而在两年前, google 推出了 OSS-Fuzz 服务,用于给开源项目的进行免费的模糊测试服务,可自动在新版本代码提交后自动完成 测试->异常检测->issue登记->老版本issue回归及自动关闭 的功能。背后使用的就是 ClusterFuzz 技术。流程图如下:
而在过年前,google 开源了 ClusterFuzz ,并解决了原有 ClusterFuzz 必须依赖 Google Cloud 提供的服务这个问题,提供了本地运行的解决方案。根据官方介绍,它具备如下功能:
- 高度可扩展,谷歌的内部实例运行在超过 25000 台机器上
- 准确的去副本化(Accurate deduplication)
- 问题跟踪器的全自动错误归档和关闭
- 最小化测试用例
- 通过二分法回归查找
- 提供分析 fuzzer 性能和崩溃率的统计信息(不支持本地部署)
- 易于使用的 Web 界面,用于管理和查看崩溃
- 支持引导模糊(例如 libFuzzer 和 AFL)和黑盒模糊测试
其大致执行流程如下:
当然,方案并不完美,如模糊数据统计、崩溃数据统计等功能由于依赖 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、安装 python 和 go 运行环境。
特别注意:如果你使用的是 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++ 之外的完整解决方案,但相信按照其扩展性,扩展到支持更多的语言并不是难题。期望未来有更多的同学参与扩展这个工具,形成开箱即用的解决方案。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Programming Concurrency on the JVM
Venkat Subramaniam / The Pragmatic Bookshelf / 2011-6-1 / USD 35.00
Concurrency on the Java platform has evolved, from the synchronization model of JDK to software transactional memory (STM) and actor-based concurrency. This book is the first to show you all these con......一起来看看 《Programming Concurrency on the JVM》 这本书的介绍吧!