Vuzzer 是由計算機科學機構 Vrije Universiteit Amsterdam、Amsterdam Department of Informatics 以及 International Institute of Information Technology, Hyderabad 共同開發的工具。
項目來源 : https://github.com/vusec/vuzzer
參考資料 :《VUzzer: Application-aware Evolutionary Fuzzing》
VUzzer 是什么?
為何選擇 VUzzer
自動漏洞測試技術當前主要為基於fuzzing的有結果反饋能力的AFL與使用符號執行的driller等。
符號執行(symbolic execution)的一大優勢在於發現盡可能多的路徑,實現高覆蓋率,但其消耗大量運行空間的方式使其難以擴展,而vuzzer能在不使用符號執行的情況下,對AFL效率進行大幅的提升。
VUzzer使用應用感知的”智能“變異策略——基於數據流和控制流,使用輕量靜態分析與動態分析,通過結果反饋和優化輸入的生成過程以求產生更優秀更少的測試輸入,達到加快挖掘效率,增加挖掘深度的目的。
案例
用以下簡單的情況進行對比
...
read(fd,buf,size);
if(buf[5] == 0xD8 && buf[4] == 0xFF){ //在匯編代碼中以CMP形式出現,同時應注意其檢查順序 if(...) //if的嵌套 ...some useful code containg bug... }else{ ... EXIT_ERROR("Invalid file\n"); }
輸入buf中的buf[4],buf[5]包含着被污染的數據(tained data)。
對於工具AFL—-對程序進行黑盒測試的fuzzer:
1.必須通過變異輸入完全猜對兩字節為FFD8才能進入深層代碼
2.必須找對該在buf[4],buf[5]的位置進行變異
3.作為一基於覆蓋率的fuzzer,AFL追求發現新路徑,當AFL沒能通過if而進入了else,對其來說仍然發現了新路徑,將會以這個進入else的輸入作為新的反饋。可能致使AFL過分輕視if分支,這種情況在嵌套判斷語句中會更加明顯。
這將會使fuzzer浪費大量時間與運算資源,在else和其下的錯誤處理中。
而對於VUzzer:
1.在靜態分析階段,vuzzer會通過在程序的匯編碼中尋找cmp指令集相關命令,將if語句中的判斷值提取出來存儲在Lcmp當中,找到這些magic bytes值是什么(如 FFD8)
2.而在動態分析中,通過不斷迭代,將Lcmp 與取地址值類操作Llea中信息與種子文件輸入和新生成輸入進行類型匹配等,找到這些magic bytes在輸入中的可能位置,更精准的進行變異
3.而對於嵌套判斷語句引起的深度代碼不易發現的問題,VUzzer的基本塊(Basic Block)權重管理將會很好的解決這個問題
對於應用反匯編后,匯編碼中的每一個基本塊(Basic Block),都有一個權重值,由於VUzzer追求更深層的代碼,所以對可能執行到概率越小的塊,他的權重值要更高,若從main到達塊A的概率為P,其權重就為1/p。
但如何做到這一點?
以上圖為例如果說有main開始,那么執行到main的概率就是1,main后有兩個可能方向,那么就划分兩者概率均為0.5,依次向下。
例如$H{概率}=E*0.5+P{外來}(0.5)*0.5=0.5$
則$H{權重}=1/H{概率}=2$
例圖中藍線所表示為F塊觸發概率為0.25,權重為倒數4
特別的,對於很小可能含有bug的錯誤處理塊其權重為1(通過動態分析才能發現錯誤處理塊)
由此有了,解決深層代碼被隱藏的方法。
VUzzer 概述
vuzzer頂層圖(具體術語參見下表)
靜態分析階段
1).在匯編碼中進行,找出基本塊,計算塊權重並將塊重量存入
LBB
2).掃描編碼中的cmp指令相關的立即數,存入
Limm
(包含如上文中的0xFF,0xD8等)
動態分析階段—–每一loop為一代
1).對種子文件(使用者提供的基礎輸入)進行DTA分析,捕獲輸入中的共同特征,以期找到magic bytes的位置與錯誤處理塊,使新產生的孩子測試輸入,不會陷於外圍的判斷和出錯處理
2).對於發現了新的基本塊的輸入用例,進行DTA分析,追蹤輸入的值在程序中的運行,監測數據流特征,以推斷輸入的結構
3).適應度計算
適應度是對每一個輸入而言的,適應度越高,代表其可進入更多的塊,更深的塊(權重更大的塊),是更有價值的輸入。
再結合此圖,對於每一個輸入,運行中必會通過一條路徑,輸入A的適應度就是改路徑所經過塊的權重和
例如路徑1(紅色)2(藍色):
$p1=A-B-D-E-H-J=1+1+2+2+2-1=7$
$p2=A-B-D-E-F-J=1+1+2+2+4-1=9$
則
$適應度{P2}>適應度{P1}$
輸入2將更被看重,更多的參與到生成下一代去,具體做法是將輸入按適應度呈順序排列存入Lfit
,再選取使用時,使用前n%的做法
4).生成下一代
其變異來源是被稱為vuzzer下的ROOT set
的輸入集合,其中包含種子文件,tainted input, Lfit
中的前n%。
典型的子測試用例演化算法
vuzzer采用典型演化算法步驟並優化
INITIALIZE population with seed inputs repeat SELECT1 parents RECOMBINE parents to generate children MUTATE parents/children EVALUATE new candidates with FITNESS function SELECT2 fittest candidates for the next population until TERMINATION CONDITION is met //迭代次數超過限制 或 觸發crash return BEST Solution
| 變異策略 | 具體步驟 || —– | —————- || 交叉 | 取一個偏移量,而后使兩半互換 || 刪去 | 刪除字節 || 替換與插入 | 在特定的位置改變或插入特定的字節 |
特定的字節 ,是通過從程序的匯編碼中cmp指令集族的代碼中取出立即數置入Limm
,並從Limm
中取出。生成為不同長度的新字節串得到的
特定的位置 ,是通過從父測試用例集中,尋找其偏移量,並在此之上變異引起的
產生孩子測試用例后由此再進行一輪,在達到迭代上限或發現bug前,循環往復
vuzzer安裝
這里結合官方安裝說明 進行講解:
需求條件:
環境:
32位Linux系統,因vuzzer作者聲明僅在Ubuntu14.04版本中完成測試,所以建議使用該版本系統。
vuzzer_github 在本地目錄准備源碼
$ git clone https://github.com/vusec/vuzzer
C++11 編程以及 Unix 開發利用 (例如: GNU Make).
gcc4.8開始默認支持c++11
Ubuntu14.04當前自帶版本為4.8.*的gcc,g++,支持c++11。
通過以下命令可以檢查當前版本
$ gcc --version
$ g++ --version
若不合適可通過過以下命令安裝該版本
$ sudo apt-get install gcc-4.8
$ sudo apt-get install g++-4.8
准備Intel Pin:Intel Pin 的較新版本 (>=2.13) 。必須在 VUzzer 頂級目錄中的 pin 目錄中保存框架。
PIN的下載可以通過以下兩個方法:
(1).(推薦)使用vuzzer自帶pin配置腳本,自動下載合適版本pin並配置,在vuzzer根目錄輸入以下命令,使用此方法pin會被下載至vuzzer/support/
make -C support -f makefile.pin
(2) . 在官方網站 Pin – A Binary Instrumentation Tool 下載合適版本pin工具(查看release note尋找對應版本)
后在vuzzer目錄下建立一個到pin的鏈接:
$ cd vuzzer
$ ln -s /path-to-pin-home pin
其中/path-to-pin-home是Pin的根目錄,不是可執行文件
利用 Python 2.7 ,使用 Turtle 語法將源代碼轉換成 PROV 形式:
Ubuntu14.04 帶有 python2.7
通過以下命令檢查
$ python --version
如果未安裝執行以下命令安裝
$ sudo apt-get install python-2.7
安裝EWAGBoolArray:只需將 headers 文件 復制粘貼到 /usr/include 文件夾中即可安裝:
完成該步驟僅需將指定頭文件下載放置到/usr/include目錄下
具體為下載headers file所指向鏈接下4個.h格式文件。
后通過以下命令拷貝頭文件,其中headers
為包含4個頭文件的文件夾
$ sudo cp headers/* /usr/include/
安裝 BitMagic:
輸入以下命令安裝 BitMagic
$ sudo apt-get install bmagic
要求修改過的libdft,在當前vuzzer目錄的support下已有該版本,已准備好編譯,無需操作
BitVector module for python.點擊bitvector下載
官方網站:https://engineering.purdue.edu/kak/dist/BitVector-2.2.html
安裝通過以下命令:在解壓后的BitVector目錄下
$ sudo python setup.py install
環境准備結束
安裝
First do cd vuzzer
and then
export PIN_ROOT=$(pwd)/pin
設置PIN_ROOT,由於當前目錄(pwd)下的pin根目錄鏈接,該命令將使PIN_ROOT指向可執行文件pin
編譯libdft,在vuzzer/support/libdft/src目錄下
make clean
清空make文件,再回到vuzzer目錄下執行
make support-libdft
編譯libdft
make
編譯vuzzer
make -f mymakefile
(截圖未做make clean,且已安裝過,僅供參考)
安裝完成
vuzzer基礎參數說明
位於根目錄下的
runfuzzer.py是啟動vuzzer的入口
config.py是包含vuzzer代數上限等設置的配置文件
$ python runfuzzer.py -h
usage: runfuzzer.py [-h] -s SUT -i INPUTD -w WEIGHT -n NAME [-l LIBNUM] -o OFFSETS [-b LIBNAME]
這里假定以tiff2pdf(圖片格式轉換工具)為測試對象,同時監測其運行庫libtiff.so
-s
(SUT commandline): 被測程序命令行
e.g. -s "./bin/tiff2pdf -d %s -o result.pdf"
是要進行vuzzer的對象,具體為將普通執行程序語句中傳入參數文件語句替換為%s,使vuzzer以此處輸入為基礎進行漏洞挖掘。如果有其他參數與設置將保留在其原位置,
-i
(seed input directory (relative path)): 種子文件目錄
e.g. -i "datatemp/tiff_seeds/"
(該目錄下存有4個.tiff文件)
種子文件是自動化漏洞挖掘的起始輸入,vuzzer將在此之上進行輸入變異。這里指向種子文件所在文件夾,建議對每一個被測程序,在vuzzer/datatemp/
目錄下新建文件夾存放其種子,種子文件至少4個(實際上有的官方示例種子文件卻只有3個),大小被明確要求小於20kb。
-w
(path of the pickle file(s) for BB wieghts (separated by comma in case there are two)
-n
(Path of the pickle file(s) containing strings from CMP
inst (separated by comma if there are two))
e.g.
-w "idafiles/tiff/tiff2pdf.pkl,idafiles/tiff/libtiff.so.pkl" -n "idafiles/tiff/tiff2pdf.names,idafiles/tiff/libtiff.so.names"
這兩類文件分別為 基本塊描述文件 和 被測程序匯編碼中用到cmp指令集的語句的有關信息。目前,這兩類文件需要通過裝有python擴展的IDA生成,將二進制可執行文件通過IDA打開,運行(Alt+F7)位於vuzzer目錄下的BB-weightv4.py,將在二進制文件目錄下生成.pkl,.names的文件。
如果要同時vuzzer一個該應用的庫文件,那么也應對它的庫(如libtiff.so)做同樣的操作,並在使用參數時添上,再以“,”隔開。如上示例
需要注意的是,若在windows下使用IDA生成.pkl,.names文件,要在vuzzer上使用時,需要對這兩個文件進行部分編碼的轉換,具體操作為:
$ dos2unix tiff2pdf.pkl
$ dos2unix tiff2pdf.names
-l
(Number of binaries to monitor) 需要監測的二進制文件數量
e.g.
-l 2
默認為1,當僅需對程序進行vuzzer時忽略此項,若同時要對庫文件進行vuzzer則該數=庫數量+1
如本例為2
-o
(base-address of application and library (if used))程序或庫的起始地址
e.g.
-o "0x00000000,0x00000000"
默認”0×00000000″當僅檢測程序時可忽略此項,若同時檢測一個庫則如上設置,一次運行后會提示庫地址偏移已顯示。在根目錄下尋找到imageoffset.txt,取出其中的庫地址偏移並修改-o
值,如下,重新執行該命令,則會正常啟動。(沒錯這確實是很奇怪的操作,作者說在下一版本會改正)
-o "0x00000000,0xba45760"
-b
(library name to monitor)要監測的庫名
e.g.
-b "libtiff"
參數使用要檢測的庫的名字,一般去掉拓展名(.so等)
示例程序測試
Project vuzzer 本身帶有幾個可供試驗的程序,在bin目錄下,其pickle文件在idafiles下,種子文件在datatemp下。
在vuzzer目錄下,運行樣例的命令為
peter@ubuntu:~/Desktop/vuzzer$ export PIN_ROOT=$(pwd)/pin ******設置pin根目錄****** peter@ubuntu:~/Desktop/vuzzer$ echo 0 |sudo tee /proc/sys/kernel/randomize_va_space [sudo] password for peter: ******關閉緩沖區隨機化****** 0 peter@ubuntu:~/Desktop/vuzzer$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope 0 peter@ubuntu:~/Desktop/vuzzer$ python runfuzzer.py -s './bin/who %s' -i 'datatemp/utmp/' -w 'idafiles/who.pkl' -n idafiles/who.names ******啟動vuzzer******
運行一段時間后
ROOT集可能會保存在data中
靜態分析結果limm存放在cmp.out中
如果觸發程序crash會在error.log記錄
觸發bug的輸入存留在outd/crashInput/中
可以用該輸入測試該程序
status.log中存有每一代的記錄
同時監測程序與程序調用的庫的vuzzer命令腳本
例如:對 tiff2pdf 及其引用庫libtiff.so
#!/bin/bash cd /home/peter/Desktop/vuzzer/ export PIN_ROOT=/home/peter/Desktop/vuzzer/pin export LD_LIBRARY_PATH=/usr/lib/ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope echo "done" python runfuzzer.py -s './bin/tiff2pdf %s -o result.pdf' \ -i 'datatemp/tiff2pdftemp/' \ -w './idafiles/tiff2pdf.pkl,./idafiles/libtiff.so.pkl' \ -n './idafiles/tiff2pdf.names,./idafiles/libtiff.so.names' \ -l 2 \ -o '0x00000000, 0xb67a5000' \ -b 'tiff'#!/bin/bash cd /home/peter/Desktop/vuzzer/ export PIN_ROOT=/home/peter/Desktop/vuzzer/pin export LD_LIBRARY_PATH=/usr/lib/ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope echo "done" python runfuzzer.py -s './bin/tiff2pdf %s -o result.pdf' \ -i 'datatemp/tiff2pdftemp/' \ -w './idafiles/tiff2pdf.pkl,./idafiles/libtiff.so.pkl' \ -n './idafiles/tiff2pdf.names,./idafiles/libtiff.so.names' \ -l 2 \ -o '0x00000000, 0xb67a5000' \ -b 'tiff'
感謝實習期間,在北京奇虎360公司,網絡安全研究院對我的細致指導
附錄
安裝使用如遇到問題可在vuzzer_Issues討論