軟體質量保障
專注測驗圈,自動化測驗、測驗平臺開發、測驗新技術、大廠測驗崗面經分享, 可以幫忙內推BATJ等大廠!歡迎加VX溝通交流: ISTE1024
測驗同行或多或少聽說過模糊測驗,但不知道它是什么?本文將詳細介紹Fuzzing Test幫助你快速了解它,
什么是 "模糊測驗"?
?
Fuzzing 是一種發現軟體缺陷的方法,它通過向程式提供隨機輸入來尋找導致程式崩潰的測驗場景(原理有點類似Monkey Test),可以幫助你快速了解程式整體的健壯性,并幫助你發現和修復關鍵的缺陷,
它是一種黑盒測驗技術,不需要訪問源代碼,但它仍然可以用來測驗那些有源代碼的軟體,這是因為它能更快地發現缺陷,并降低大量代碼評審成本,
模糊測驗優缺點
Fuzzing在某些業務下雖然非常有用,但它畢竟不是銀彈,以下是模糊技術的一些優點和缺點,
優點
-
可以說不費“吹灰之力”就能得到結果--一旦fuzzer啟動并運行,它就可以在沒有互動的情況下停留數小時、數天或數月來尋找錯誤,
-
可以發現人工審計中遺漏的錯誤
-
能對目標軟體的健壯性提供一個整體性概述
缺點
-
不會窮盡所有bug--模糊測驗可能會遺漏那些不會觸發整個程式崩潰的bug,而且對那些只在非常特殊情況下觸發的bug也難以覆寫,
-
產生的崩潰測驗用例可能難以分析,因為模糊測驗的行為并不能告訴你關于軟體內部運行方式的知識,
-
具有復雜輸入的程式可能需要更多的作業來產生一個足夠聰明的模糊測驗器,以獲得足夠的代碼覆寫率,
Smart/Dumb模糊測驗
Fuzzers向軟體系統提供隨機輸入,內容形式可能是某種網路協議、某種格式的檔案或用戶能直接輸入的資料,其輸入方式是完全隨機的,并不知道預期的輸入應該是什么樣子,也可以是經過一些修改后看起來像是有效的輸入,
產生完全隨機輸入的Fuzzer被稱為 Dumb Fuzzer,少量的作業可以用很少的成本產生結果--這是模糊測驗的一大優勢,然而,有時一個程式只有在輸入的特定場景才會執行某些處理,例如,一個程式的輸入需要傳入 "name"欄位,而這個欄位有一個與之相關的 "name length",
如果這些欄位沒有以足夠有效的形式出現讓程式識別,它可能永遠不會讀取這個名字,如果這些欄位以有效的形式存在,但長度值被設定為不正確的值,程式可能會讀到包含名字的緩沖區之外,并引發崩潰,如果缺乏有效的輸入,這是不可能發生的,在這些情況下,可以使用 Smart Fuzzer,Smart Fuzzer是基于輸入特定的規則實作的,例如協議定義或檔案格式的規則,它可以構建大部分有效的輸入,并且只對該基本格式內的輸入進行模糊處理,
Fuzzers的型別
廣義上講,Fuzzer可以根據它們創建程式輸入的方式分為兩類--基于變異與基于生成.
基于變異的fuzzer
基于突變的Fuzzer可以說是最容易創建的型別之一,這種技術適合Dumb Fuzzer,但也可用于智能的Fuzzer,通過突變,有效輸入的樣本被隨機突變以產生畸形的輸入,
dumb mutation Fuzzer可以簡單地選擇一個有效的輸入樣本,并隨機地改變它的一部分,因為輸入通常仍然與有效輸入有足夠的相似性,所以這意味著不需要進一步的智能化處理就可以實作良好的代碼覆寫,
下面是基于突變的Fuzzer可以使用的兩種技術,
流量回放
Fuzzer可以采取保存的樣本輸入,并在突變后重新播放,這對檔案格式的模糊處理很有效,可以保存一些樣本檔案并進行模糊處理以提供給目標程式,
簡單或無狀態的網路協議也可以用重放來有效地進行模糊處理,因為Fuzzer不需要提出大量的合法請求來深入到協議中去,對于更復雜的協議,重放可能更困難,這是因為Fuzzer需要以動態方式回應程式,以允許處理繼續深入協議,
代理
你可能聽說過中間人(MITM)是滲透測驗者和黑客使用的一種技術,但它也可以用于基于突變的網路協議模糊測驗,通過MITM,你置身于客戶端和服務器的中間,截獲并可能修改它們之間傳遞的資訊,通過這種方式,你就像兩者之間的一個代理,
通過將你的Fuzzer設定為代理,它可以根據你對服務器或客戶端的模糊處理來改變請求或回應,同樣,Fuzzer可以隨機地改變一些請求,也可以在你感興趣的協議的特定層次上智能地鎖定請求,基于代理的模糊測驗可以讓你利用現有的網路程式部署架構,快速插入模糊測驗層,而不需要讓你的fuzzer像客戶端或服務器本身一樣行動,
基于生成的fuzzer
基于生成的Fuzzer實際上是從零開始生成輸入,而不是突變現有的輸入,它們通常需要一定程度的智能來構建至少對程式有一定意義的輸入,盡管生成完全隨機的資料在技術上也是生成,
生成Fuzzer通常將協議或檔案格式分成幾塊,它們可以按照有效的順序建立起來,并隨機地對其中一些塊進行獨立模糊,這可以創造出保留其整體結構的輸入,但其中也包含不一致的資料,這些塊的顆粒度和構建這些塊的智能程度決定了Fuzzer的智能水平,雖然基于突變的模糊處理可以產生與生成模糊處理類似的效果(因為隨著時間的推移,突變將被隨機應用,而不會完全破壞輸入的結構),但生成輸入可以確保這種情況的發生,
生成fuzzers也可以更容易地深入到協議中,因為它可以構建有效的輸入序列,對該通信的特定部分進行模糊處理,它還允許Fuzzer作為一個真正的客戶/服務器,生成正確的、動態的回應,但這些回應不能盲目地重放,
進化型fuzzer
進化型模糊測驗是一種先進的技術,它允許Fuzzer使用來自每個測驗用例的反饋,以了解隨著時間推移輸入的格式,例如,通過測量每個測驗用例的代碼覆寫率,Fuzzer可以計算出測驗用例的哪些屬性可以鍛煉給定的代碼區域,并逐漸演化出一套覆寫大部分程式代碼的測驗用例,進化型模糊測驗通常依賴于與遺傳演算法類似的其他技術,并且可能需要某種形式的二進制工具來正確操作,
模糊測驗測什么?
即使是相對dumb的模糊測驗,也要記住你的測驗用例實際上有可能擊中代碼的哪一部分,舉個簡單的例子,如果你正在摸索一個使用TCP/IP的應用協議,而你的Fuzzers隨機突變了一個原始資料包的捕獲,你很可能會破壞TCP/IP資料包本身,因此,你的輸入根本不可能被應用程式所處理,再者,如果你正在測驗一個將文本的影像決議為真實文本的OCR程式,但你正在突變整個影像檔案,你最終可能會更頻繁地測驗其影像決議代碼而不是實際的OCR代碼,如果你想專門針對該OCR處理,你可能希望保持影像檔案的標題有效,
Fuzzer運行流程
為了有效地運行,Fuzzer需要執行以下重要任務:
-
生成測驗用例
-
記錄測驗用例或再現用例所需的任何資訊
-
對目標程式介面提供測驗case作為輸入
-
檢測崩潰
Fuzzer通常將其中的許多任務分成獨立的模塊,例如,有一個庫可以突變資料或根據定義生成資料,另一個庫可以向目標程式提供測驗用例等等,
生成測驗用例
測驗用例的生成將取決于是否采用了基于突變或基于生成的模糊處理,無論采用哪種方法,都會有一些需要隨機轉換的東西,無論是特定型別的欄位還是任意的資料塊,
這些轉換可以是完全隨機的,但值得注意的是,邊界和極端的情況往往是程式中錯誤的來源,因此,你可能希望偏向于這樣的情況,
-
非常長超長字串或Null
-
能支持的最大值和最小值整數
-
像-1、0、1和2這樣的值
根據你要模糊處理的內容,可能會有一些特定的值或字符更容易觸發bug,比如:
-
Null
-
分號
-
格式化字串值(%n,%s等等)
-
應用特定的關鍵詞
可重復性
重現一個測驗用例的最簡單方法是記錄檢測到崩潰時使用的確切輸入,在某些情況下,還有其他方法能實作重現性,一種方法是存盤用于測驗用例生成的隨機部分的初始種子,并確保所有后續的隨機行為遵循一個可以追溯到該種子的路徑,通過用相同的種子重新運行Fuzzer,行為應該是可重復的,例如,你可以只記錄測驗用例編號和初始種子,然后用該種子快速重新執行生成,直到達到給定的測驗用例,
當目標程式可能基于過去的輸入積累了依賴性時,這種技術就很有用,以前的輸入可能導致程式在其記憶體中初始化各種專案,而這些專案是觸發錯誤所必須的,在這些情況下,簡單地記錄崩潰的測驗用例并不足以重現該錯誤,
與目標程式對接
與目標程式連接以提供模糊輸入通常是簡單的,對于網路協議,它可能涉及在網路上發送測驗用例,或回應客戶的請求,對于檔案格式,它可能意味著用一個指向測驗用例的命令列引數來執行程式,然而,有時提供的輸入的形式不容易以自動化的方式生成,或者撰寫程式腳本來執行每個測驗用例的開銷很大,證明是非常緩慢的,在這些情況下,創造性的思考可以發現用正確的資料來鍛煉相關的代碼片斷的方法,
例如,這可以通過在記憶體中人為地設定程式來執行決議功能,而輸入的引數完全在記憶體中,這可以消除程式在每個測驗用例之前經過冗長的加載程式的需要,而且,通過讓測驗用例完全在記憶體中生成和提供,而不是通過硬碟驅動器,可以進一步提高速度,
崩潰檢測
崩潰檢測是模糊測驗的關鍵,如果你不能準確地確定一個程式何時崩潰,你就不能確定一個測驗用例是否觸發了一個錯誤,
-
附加一個除錯器
這可以為你提供最準確的結果,你可以撰寫除錯器的腳本,以便在檢測到崩潰時立即為你提供崩潰跟蹤,然而,附加一個除錯器會大大降低程式的速度,并會造成相當大的開銷,在給定的時間內,你能產生的測驗用例越少,你發現崩潰的機會就越少,
-
看看目標行程是否消失了
與其附加一個除錯器,你可以簡單地看看在執行測驗用例后,目標的行程ID是否仍然存在于系統中,如果行程消失了,它可能已經崩潰了,如果你想了解更多關于崩潰的資訊,你可以在以后用除錯器重新運行測驗用例,你甚至可以在每次崩潰時自動這樣做,同時還可以避免在每個案例中都連接除錯器而導致的速度下降,
超時
如果程式對你的測驗用例有正常的回應,你可以設定一個超時,超時后你就認為程式已經崩潰,這也可以檢測出導致程式無反應但不一定終止的錯誤,
無論你使用哪種方法,只要程式崩潰或變得無反應,就應該重新啟動,以便讓模糊測驗繼續進行,
模糊測驗的質量
你可以做一些事情來衡量或提高你的模糊測驗的質量,雖然這些都是需要記住的有用的東西,但如果你已經在一定的時間范圍內得到了很多獨特的崩潰,你可能不需要再為這些事情費心了,
速度
速度可能是模糊測驗中最重要的因素之一,你每秒鐘/每分鐘能運行多少個測驗用例?合理的數值當然取決于目標,但你能執行的測驗用例越多,你就越有可能在給定的時間段內發現崩潰,模糊測驗是隨機的,所以每一個測驗用例就像一張彩票,你要盡可能多地得到它們,
你可以做很多事情來提高測驗用例的速度,比如提高生成或變異例程的效率,并行化測驗用例,減少超時,或在不顯示圖形用戶界面的 "無頭 "模式下運行程式,如果你想的話,你可以簡單地購買更快的套件,
對崩潰進行歸類
找到崩潰只是程序的開始,一旦你找到一個崩潰的測驗用例,你就需要分析它,找出錯誤所在,并根據你的動機,修復它或為它撰寫一個漏洞,如果你有成千上萬個崩潰的測驗用例,這可能是相當令人生畏的,通過對崩潰進行分類,你可以根據哪些崩潰是你最感興趣的來確定它們的優先次序,這也可以幫助你識別一個測驗用例何時觸發了與另一個相同的錯誤,所以你只保留與獨特崩潰有關的案例,
為了做到這一點,你需要一些關于崩潰的自動資訊,以便你能做出決定,在目標機上運行測驗用例并連接到除錯器,可以提供崩潰跟蹤,你可以對其進行分析,找到諸如例外型別、暫存器值、堆疊內容等值,
減少測驗用例
由于模糊測驗是隨機改變輸入的,一個崩潰的測驗用例通常會有多個與觸發該錯誤無關的改變,測驗用例縮減是將測驗用例縮減到觸發bug所需的有效輸入的最小改動集,因此你只需要在分析中關注輸入的這一部分,
這種減少可以手動進行,但也可以由Fuzzer自動進行,當遇到一個崩潰的測驗用例時,Fuzzer可以重新執行該測驗用例幾次,每一次,它都會逐漸減少對輸入的改動,直到剩下最小的一組改動,同時仍然觸發該錯誤,這可以簡化你的分析,并有助于對崩潰的測驗用例進行分類,因為你會準確知道輸入的哪些部分受到影響,
代碼覆寫率
這是一個衡量程式的代碼有多少被Fuzzer執行的標準,其原理是,你得到的覆寫率越多,你實際測驗的程式就越多,測量代碼覆寫率可能很棘手,通常需要二進制儀器來跟蹤代碼的哪些部分正在被執行,你也可以用不同的方式測量代碼覆寫率,比如按行、按基本塊、按分支或按代碼路徑,
代碼覆寫率對于模糊測驗來說并不是一個完美的衡量標準,因為有可能在執行代碼的同時并沒有發現其中的漏洞,而且,經常有一些代碼區域幾乎不會被執行,例如安全錯誤檢查,反正我們不太可能真正需要,也不太感興趣,盡管如此,某種形式的代碼覆寫率測量可以讓我們了解到你的Fuzzer在程式中觸發了什么,特別是當你的模糊測驗是完全黑箱的時候,你可能還不太了解程式的內部運作,一些可能有助于代碼覆寫率的工具和技術包括Pai Mei、Valgrind、DynamoRIO和DTrace,
模糊測驗框架
目前市面上有許多框架可以讓你創建Fuzzer,而不必從頭開始造,下面列出了這些框架:
Radamsa
Radamsa被設計為易于使用和靈活,它試圖對各種輸入型別進行 "公正的作業",并包含一些不同的模糊演算法進行突變,
Sulley
Sulley提供了一個全面的生成框架,允許結構化資料被表示為基于生成的模糊處理,它還包含幫助記錄測驗用例和檢測崩潰的組件,
Peach
Peach框架可以對檔案格式和網路協議進行智能模糊測驗,它可以執行基于生成和突變的模糊測驗,并包含幫助建立模型和監控目標的組件,
SPIKE
SPIKE是一個網路協議Fuzzer,它需要用戶熟悉掌握C語言,并被設計為在Linux上運行,
Grinder
Grinder是一個網路瀏覽器Fuzzer,它還具有幫助管理大量崩潰的功能,
NodeFuzz
NodeFuzz是一個基于node.js的網路瀏覽器線束,它包括儀器模塊,可以從客戶端獲得更多資訊,
AFL
AFL是一個灰盒式的模糊測驗工具,利用編譯在目標代碼中的儀器,AFL最初是為Linux中的C和C++程式撰寫的,后來被分叉以支持Windows、Java和.Net,
往期推薦
介面測驗框架開發實踐4:HTTP方法封裝
介面測驗框架開發實踐3:用例管理模塊
經驗分享|測驗工程師轉型測驗開發歷程
介面測驗框架開發實踐5:組態檔讀取
介面測驗框架開發實踐2:介面自動化測驗框架設計思路
介面自動化測驗框架實踐1:介面測驗概述
Pytest系列(7)-資料驅動測驗DDT
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/357086.html
標籤:其他
下一篇:面向物件大作業
