谷歌模糊測試工具 ClusterFuzz 安裝及使用
本文發表于 TesterHome 社群,作者為資深測試開發工程師陳恒捷,原文标題為《谷歌開源模糊測試工具 ClusterFuzz 嘗鮮記錄 (進行中)》,原文連結:https://testerhome.com/topics/18171
背景
模糊測試,是指用随機壞資料(也稱做 fuzz)攻擊一個程式,然後等着觀察哪裡遭到了破壞。(出自 模糊測試)。一直以來都有不少的模糊測試工具,但大多隻集中在資料生成,執行和異常檢測依賴人工,未有比較完整的方案。
早在八年前,google 内部就在建設和使用模糊測試的工具來測試其内部的應用,而在兩年前, google 推出了 OSS-Fuzz 服務,用于給開源項目的進行免費的模糊測試服務,可自動在新版本代碼送出後自動完成 測試->異常檢測->issue登記->老版本issue回歸及自動關閉 的功能。背後使用的就是 ClusterFuzz 技術。流程圖如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPB10MBpWT6dmeNBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL3IzNwQTN0EjM5AzMwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
而在過年前,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、下載下傳源碼
2、安裝 google cloud sdk
進入 https://cloud.google.com/sdk/ ,按照引導安裝 sdk 并配置好環境變量(mac 下可以直接用解壓後的
install.sh
腳本一鍵安裝),确認指令行可調用 gcloud 指令
3、安裝 python 和 go 運作環境。
特别注意:如果你使用的是 macOS 或者 Ubuntu、Debain,直接執行第4步即可,腳本裡會自動安裝 Python 和 go
python 要求 2.7.10 以上,但不能是 python 3。在 mac 上可以直接運作
brew install [email protected]
安裝。
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)
幾個系統,官方已經内置了安裝依賴的腳本,直接運作即可:
執行完畢,會出現
的提示。
坑一,官方的腳本裡第一行用了 -ex 參數,會導緻運作腳本時如果有指令執行出錯(如 brew install 時有些應用本地已經安裝過,但非最新版本),直接退出程式。
可以通過
sed -i '' 's/bash -ex/bash -x/' local/install_deps*
指令直接去掉 -e 參數。已經給官方提了 issue
坑二,官方腳本裡使用
python butler.py bootstrap
初始化環境時,會自動去 google 站點下載下傳 chromedriver 相關的檔案。
全局搜尋了下源代碼,隻有跑單測的時候有用到 chromedriver ,是以可以直接注釋掉這個函數:
坑三,運作時會報錯
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 ,是以保險起見全部都配好代理:
可惜的是,配置完了還是不行,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
2.23 更新:docker 鏡像已成功打包,基于 ubuntu 16.04 系統。鏡像中已運作完畢本文中的第1-4步(除了坑2中的注釋 chromedriver ),裝好了所有依賴。鏡像位址:https://hub.docker.com/r/chenhengjie123/clusterfuzz_local
可通過
docker run -it --name clusterfuzz --network host chenhengjie123/clusterfuzz_local
進入鏡像運作環境,進入後續的步驟。clusterfuzz 的源代碼存放在鏡像的 /clusterfuzz 目錄。
5、切換到 python 的 virtualenv
校驗是否一切就緒
運作本地執行個體
本地執行個體包含2個部分,一個是管理各個執行機器人的服務端,另一個是執行機器人。
啟動本地服務
首次運作,添加
--bootstrap
進行各個資料的初始化。同時個人推薦加上
--skip-install-deps
跳過依賴安裝(前面步驟已經裝過了,不需要重複安裝)
非首次運作,務必去掉
--bootstrap
參數。
坑四:啟動時會到
https://www.googleapis.com/discovery/v1/apis/pubsub/v1/rest
擷取一些資訊,如果此時網絡連不通,會報錯
報錯資訊:
解決猜想:看了下這個頁面,實際上是擷取 api 文檔。理論上隻要把這個 api 文檔事先下載下傳好并放到資源檔案中,然後把這個從網絡擷取文檔的步驟改為讀取資源檔案即可。晚些嘗試下。
由于時間關系,暫時先想辦法讓網絡能通路 google 先繞過。
啟動到末尾,會出現如下日志:
表明已經啟動完畢。可以通過打開 http://localhost:9002/ 打開管理者界面。
坑五:内部監聽位址都是 localhost ,意味着在 docker 容器内部時,即使用 -p 暴露了端口也通路不了
解決猜想:把源碼中 localhost 都替換為 0.0.0.0 ,即監聽所有位址,應該可以解決。目前還在修改中。
後續部分翻譯自官方文檔,還沒親測,大家可以先看看了解。
==========================================官方文檔翻譯分割線===============================================
啟動執行機器人
官方指令:
其中 my-bot 可以替換為自己喜歡的名稱。我改成了
fuzzing-bot
執行成功後,可在前一步的管理者界面看到機器人狀态。
可通過
檢視機器人實時日志輸出。
開始測試
官方給了一個例子,尋找 OpenSSL 的心髒滴血記憶體溢出漏洞。下面按照給出的步驟執行。
編譯一個包含這個漏洞和已經帶有 fuzz 插樁的 OpenSSL
上傳 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++ 之外的完整解決方案,但相信按照其擴充性,擴充到支援更多的語言并不是難題。期望未來有更多的同學參與擴充這個工具,形成開箱即用的解決方案。