天天看點

谷歌模糊測試工具 ClusterFuzz 安裝及使用谷歌模糊測試工具 ClusterFuzz 安裝及使用

谷歌模糊測試工具 ClusterFuzz 安裝及使用

本文發表于 TesterHome 社群,作者為資深測試開發工程師陳恒捷,原文标題為《谷歌開源模糊測試工具 ClusterFuzz 嘗鮮記錄 (進行中)》,原文連結:https://testerhome.com/topics/18171

背景

模糊測試,是指用随機壞資料(也稱做 fuzz)攻擊一個程式,然後等着觀察哪裡遭到了破壞。(出自 模糊測試)。一直以來都有不少的模糊測試工具,但大多隻集中在資料生成,執行和異常檢測依賴人工,未有比較完整的方案。

早在八年前,google 内部就在建設和使用模糊測試的工具來測試其内部的應用,而在兩年前, google 推出了 OSS-Fuzz 服務,用于給開源項目的進行免費的模糊測試服務,可自動在新版本代碼送出後自動完成 測試->異常檢測->issue登記->老版本issue回歸及自動關閉 的功能。背後使用的就是 ClusterFuzz 技術。流程圖如下:

谷歌模糊測試工具 ClusterFuzz 安裝及使用谷歌模糊測試工具 ClusterFuzz 安裝及使用

而在過年前,google 開源了 ClusterFuzz ,并解決了原有 ClusterFuzz 必須依賴 Google Cloud 提供的服務這個問題,提供了本地運作的解決方案。根據官方介紹,它具備如下功能:

  • 高度可擴充,谷歌的内部執行個體運作在超過 25000 台機器上
  • 準确的去副本化(Accurate deduplication)
  • 問題跟蹤器的全自動錯誤歸檔和關閉
  • 最小化測試用例
  • 通過二分法回歸查找
  • 提供分析 fuzzer 性能和崩潰率的統計資訊(不支援本地部署)
  • 易于使用的 Web 界面,用于管理和檢視崩潰
  • 支援引導模糊(例如 libFuzzer 和 AFL)和黑盒模糊測試

其大緻執行流程如下:

谷歌模糊測試工具 ClusterFuzz 安裝及使用谷歌模糊測試工具 ClusterFuzz 安裝及使用

當然,方案并不完美,如模糊資料統計、崩潰資料統計等功能由于依賴 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++ 之外的完整解決方案,但相信按照其擴充性,擴充到支援更多的語言并不是難題。期望未來有更多的同學參與擴充這個工具,形成開箱即用的解決方案。

繼續閱讀