idea2020shezhi代码检查级别_优秀的模糊测试代码是如何炼成的?
所謂模糊測(cè)試,是指一種通過(guò)向目標(biāo)系統(tǒng)提供非預(yù)期的輸入并監(jiān)視異常結(jié)果來(lái)發(fā)現(xiàn)軟件漏洞的方法,它經(jīng)過(guò)了近 20 年的發(fā)展,早已在程序員圈中成為一種主流漏洞挖掘技術(shù)。基于此,開(kāi)發(fā)者們?cè)撊绾尉帉懥己玫哪:郎y(cè)試代碼?
作者 |?John Regehr
譯者 | 彎月,責(zé)編 | 屠敏
出品 | CSDN(ID:CSDNnews)
以下為譯文:
模糊測(cè)試(Fuzzing)是發(fā)掘漏洞和其他軟件缺陷的強(qiáng)力手段,但通常開(kāi)發(fā)者都是利用這種方式來(lái)深入發(fā)掘已部署代碼中的問(wèn)題。實(shí)際上,我們應(yīng)該盡早完成模糊測(cè)試,而且開(kāi)發(fā)人員應(yīng)該花點(diǎn)時(shí)間來(lái)編寫更易于開(kāi)展模糊測(cè)試的代碼。
在這篇文章中,我想介紹一些方法,告訴你如何編寫更方便模糊測(cè)試的代碼。但這些方法并不全面,而且各個(gè)方法之間也可能有重疊。縱觀本文,我會(huì)使用“模糊器”來(lái)指代所有類型的隨機(jī)測(cè)試用例生成器,無(wú)論是基于突變的(afl、libFuzzer等)還是生成的(jsfunfuzz、Csmith等)生成器。注意,本文提出的建議并非適用所有情況,但其中很多都是合理的軟件工程建議。我會(huì)用粗體標(biāo)明一些我認(rèn)為特別重要的觀點(diǎn)。
在測(cè)試預(yù)言上下功夫
測(cè)試預(yù)言(test oracle)決定了測(cè)試用例是否會(huì)觸發(fā)bug。在默認(rèn)情況下,afl等模糊器唯一可以使用的預(yù)言就是操作系統(tǒng)的頁(yè)面保護(hù)機(jī)制。換句話說(shuō),它只能檢測(cè)系統(tǒng)的崩潰。但是我們能做到遠(yuǎn)不止于此。
斷言和由編譯器插入的sanitizer檢查是另一種類型的預(yù)言。在模糊測(cè)試中,你應(yīng)該盡可能多地使用這種類型的檢查。除了這些簡(jiǎn)單的預(yù)言之外,還有很多其他的預(yù)言,例如:
函數(shù)與反函數(shù):解析與輸出的閉環(huán)、壓縮與解壓縮的閉環(huán)、加密與解密的閉環(huán)及其他類似的代碼是否會(huì)按預(yù)期正常工作?
差異:兩個(gè)不同的實(shí)現(xiàn)或同一個(gè)實(shí)現(xiàn)的兩種不同的模式是否表現(xiàn)出相同的行為?
變形:如果在保證語(yǔ)義的情況下修改測(cè)試用例,系統(tǒng)是否會(huì)表現(xiàn)出的行為,例如在表達(dá)式中再添加一層括號(hào)?
資源:處理輸入時(shí),系統(tǒng)消耗的時(shí)間、內(nèi)存等是否合理?
特定領(lǐng)域:例如,一個(gè)因壓縮而導(dǎo)致畫質(zhì)受損的圖像在視覺(jué)上是否與未壓縮的圖像一致??
我們值得花時(shí)間和精力建立強(qiáng)大的預(yù)言,因?yàn)樗鼈兺軌虬l(fā)現(xiàn)應(yīng)用程序級(jí)的邏輯錯(cuò)誤,而通常我們通過(guò)查找數(shù)組越界等方式只能捕獲低級(jí)的錯(cuò)誤。
幾年前,我撰寫過(guò)一篇有關(guān)于該話題的文章(https://blog.regehr.org/archives/856)。有一個(gè)Twitter用戶建議:“在測(cè)試解析器的時(shí)候,你必須檢查它返回的對(duì)象,而不僅僅是檢查解析這個(gè)動(dòng)作的執(zhí)行。”這是一個(gè)很好的建議。
干預(yù)I/O與狀態(tài)
無(wú)狀態(tài)代碼更方便展開(kāi)模糊測(cè)試。但除此之外,你還需要API來(lái)控制狀態(tài)和干預(yù)I/O。例如,如果程序需要從操作系統(tǒng)中獲取核心數(shù)、當(dāng)前日期或剩余磁盤空間量等信息,那么你應(yīng)該提供一種設(shè)置這些值的方法并寫在文檔中。我并不是說(shuō),我們需要隨時(shí)改變核心數(shù)量,而是我們可能在單核模式下針對(duì)代碼展開(kāi)模糊測(cè)試,然后還需要在128核模式下再進(jìn)行一次模糊測(cè)試。有些控制狀態(tài)和I/O的方法非常重要,比如簡(jiǎn)化重置狀態(tài)(為了支持持久模式的模糊測(cè)試),并避免會(huì)導(dǎo)致非確定性執(zhí)行的隱藏輸入等。在針對(duì)代碼進(jìn)行模糊測(cè)試時(shí),我們希望擁有盡可能多的確定性。
避免或控制模糊測(cè)試的阻礙
模糊測(cè)試的阻礙就是那些無(wú)法模糊化的東西。典型的模糊測(cè)試阻礙是包含在輸入中某處的校驗(yàn)和:基于突變的模糊器隨機(jī)修改輸入會(huì)導(dǎo)致校驗(yàn)和不合法,從而降低代碼覆蓋率。這個(gè)問(wèn)題基本上有兩種解決方案。第一種,在模糊測(cè)試構(gòu)建中關(guān)閉校驗(yàn)和驗(yàn)證;第二種,確保模糊器能夠生成帶有合法校驗(yàn)和的輸出。基于生成的模糊器自帶這種功能;如果使用基于突變的模糊器,那么我們需要編寫一個(gè)小工具,在生成測(cè)試用例后,我們需要趕在測(cè)試用例傳遞給模糊測(cè)試程序前,給測(cè)試用例加上有效的校驗(yàn)和。alf支持這種方法。
除了校驗(yàn)和之外,難以滿足的輸入驗(yàn)證屬性也是一個(gè)嚴(yán)重的問(wèn)題。例如,如果你要針對(duì)強(qiáng)類型編程語(yǔ)言的編譯器進(jìn)行模糊測(cè)試,那么盲目地修改編譯器的輸入很難獲得有效的編譯器輸入。我喜歡將有效性的約束分為軟約束(無(wú)效輸入除了浪費(fèi)時(shí)間外,并沒(méi)有其他害處)和硬約束(系統(tǒng)在處理無(wú)效輸入時(shí)可能會(huì)暴走,因此必須避免無(wú)效輸入,否則完全無(wú)法進(jìn)行模糊測(cè)試)。如果我們通過(guò)針對(duì)C++編譯器開(kāi)展模糊測(cè)試來(lái)尋找錯(cuò)誤代碼中的bug,就會(huì)面臨硬有效性約束,因?yàn)闀?huì)導(dǎo)致未定義行為的編譯器輸入看上去很像是代碼中有bug。對(duì)于這類問(wèn)題,我們沒(méi)有簡(jiǎn)單的通用解決方案,只能通過(guò)一系列技巧來(lái)考慮有效性屬性。有一個(gè)最簡(jiǎn)單的解決方案(但往往不是正確的解決方案),那就是自己編寫一個(gè)模糊器。但問(wèn)題在于,如果自己編寫模糊器,就無(wú)法再利用現(xiàn)代覆蓋驅(qū)動(dòng)的模糊測(cè)試技術(shù)——這種技術(shù)非常了不起的。為了匹配覆蓋率驅(qū)動(dòng)的模糊測(cè)試框架,你有以下幾種選擇:首先,編寫一個(gè)能夠滿足有效性約束的自定義變異器;其次,采用了解結(jié)構(gòu)的模糊,意思是說(shuō)從模糊器中獲取修改后的數(shù)據(jù),并將其轉(zhuǎn)換為模糊測(cè)試程序所需要的內(nèi)容。關(guān)于如何讓覆蓋驅(qū)動(dòng)的模糊器在有效性約束下依然良好地運(yùn)行,且不需要大量的手動(dòng)工作,我們還有大量的研究工作需要展開(kāi)。這其中涉及很多細(xì)節(jié),改日再深入介紹。一般來(lái)說(shuō),在模糊器中加入類似SAT的求解器并不能解決這個(gè)問(wèn)題,其原因首先是,有的有效性約束(比如校驗(yàn)和)對(duì)于求解器來(lái)說(shuō)難度特別大;其次是因?yàn)橛行┯行约s束(如C++程序中的未定義行為)是隱含的,我們無(wú)法從系統(tǒng)中推斷,甚至從原理上也不可能。
一般來(lái)說(shuō),你無(wú)法通過(guò)為公共API提供輸入的方式,來(lái)針對(duì)系統(tǒng)的大部分代碼進(jìn)行模糊測(cè)試,因?yàn)檫@些訪問(wèn)會(huì)被系統(tǒng)中的其他代碼阻止。例如,如果你使用自定義的內(nèi)存分配器實(shí)現(xiàn)或自定義的哈希表實(shí)現(xiàn),那么應(yīng)用程序級(jí)別的模糊測(cè)試可能無(wú)法針對(duì)分配器或哈希表進(jìn)行有效的模糊測(cè)試。這些API應(yīng)該直接暴露給模糊測(cè)試。單元測(cè)試和模糊測(cè)試有強(qiáng)烈的聯(lián)系:如果其中一個(gè)可行且可取,那么另一個(gè)也應(yīng)該差不多。通常你應(yīng)該同時(shí)兼顧兩者。
通常,Sanitizer和模糊器需要對(duì)構(gòu)建過(guò)程進(jìn)行調(diào)整,甚至是重大的改動(dòng)。為了簡(jiǎn)化這一過(guò)程,請(qǐng)盡可能簡(jiǎn)化構(gòu)建過(guò)程。確??梢暂p松切換編譯器以及修改編譯器選項(xiàng)。盡量減少對(duì)特定工具(以及工具版本)的依賴。定期利用多個(gè)編譯器構(gòu)建和測(cè)試代碼。構(gòu)建系統(tǒng)的特殊依賴都需要記錄下來(lái)。
最后,有些模糊測(cè)試的阻礙有點(diǎn)傻而且很容易避免。如果你的代碼存在泄漏內(nèi)存的問(wèn)題,或者過(guò)深的調(diào)用棧會(huì)導(dǎo)致進(jìn)程終止,那么使用持久模式的模糊測(cè)試是一件痛苦的事情,所以請(qǐng)盡量避免這些問(wèn)題。盡量不要處理SIGSEGV信號(hào),如果無(wú)法避免的話,那么應(yīng)當(dāng)有辦法在模糊器構(gòu)建中禁用相應(yīng)的信號(hào)處理程序。如果你的代碼無(wú)法與ASan或UBSan兼容,那么這些非常有用的預(yù)言就很難善加利用了。特別是,如果你的代碼使用自定義的內(nèi)存分配器,那么你應(yīng)該考慮在模糊測(cè)試構(gòu)建中將其關(guān)閉,或者經(jīng)過(guò)調(diào)整后與ASan一起使用,否則就有可能漏掉重大bug。
為覆蓋驅(qū)動(dòng)的模糊器排除障礙
由于覆蓋驅(qū)動(dòng)的模糊器的主要精力放在了測(cè)試未覆蓋的分支上,因此可能會(huì)被特殊的方式阻礙。例如,如果覆蓋驅(qū)動(dòng)的模糊器遇到了太多未覆蓋的分支,它就會(huì)在這些分支上花費(fèi)大量時(shí)間,導(dǎo)致覆蓋程序其他分支的可能性降低。例如,有一次我比較了一個(gè)程序在使用和不使用UBSan兩種情況下的afl覆蓋率,結(jié)果發(fā)現(xiàn)(在我設(shè)定的時(shí)間限制下)sanitized程序的覆蓋率要比沒(méi)有sanitized的程序低得多。但另一方面,我們也希望模糊器能找到sanitizer的錯(cuò)誤。我的建議是有sanitized和沒(méi)有sanitized的程序都進(jìn)行模糊測(cè)試。我不知道應(yīng)該如何為這些模糊測(cè)試活動(dòng)分配資源,也不知道是否有人在研究這個(gè)問(wèn)題。也許這個(gè)問(wèn)題并不重要,因?yàn)槟:郎y(cè)試本來(lái)就是過(guò)度測(cè)試。
有時(shí)候,你的程序在執(zhí)行前期調(diào)用的代碼會(huì)包含大量分支且會(huì)被過(guò)度模糊的代碼。例如,可能你需要在處理輸入之前對(duì)輸入進(jìn)行解壓縮或解密。這很可能會(huì)影響基于覆蓋的模糊器,導(dǎo)致模糊器花費(fèi)大量時(shí)間去模糊測(cè)試加密庫(kù)或壓縮庫(kù)。如果你不是希望這樣,那么就應(yīng)該提供一種方法,在模糊測(cè)試過(guò)程中禁用加密或壓縮。
程序中的解釋器都可能會(huì)給基于覆蓋的模糊器造成困難,因?yàn)橄嚓P(guān)的程序執(zhí)行路徑是在解釋器數(shù)據(jù)中編碼的,而對(duì)于模糊器而言,一般情況下數(shù)據(jù)是不透明的。如果你想讓基于覆蓋的模糊器發(fā)揮最大作用,那么就應(yīng)該考慮避免編寫解釋器,或者至少大力簡(jiǎn)化解釋器。解決嵌入式解釋器有一個(gè)很明好的方法(我相信肯定有人嘗試過(guò),不過(guò)我不知道)就是提供一個(gè)API,告訴模糊器該如何觀察被解釋語(yǔ)言的覆蓋率。
支持高吞吐量的模糊測(cè)試
模糊測(cè)試對(duì)于高吞吐量的系統(tǒng)最有效,特別是對(duì)于基于反饋的模糊器而言,這種模糊器需要一定時(shí)間來(lái)學(xué)習(xí)怎樣才能測(cè)試難以覆蓋的目標(biāo)。有關(guān)吞吐量的一個(gè)簡(jiǎn)單技巧是:提供禁用慢速代碼(例如詳細(xì)日志)的方法。類似地,干預(yù)I/O可以讓我們不需要借助運(yùn)行速度技巧,比如在內(nèi)存盤上運(yùn)行模糊器等方法。
“但我希望模糊我的代碼變得更難,而不是更容易”
我不太贊同這個(gè)觀點(diǎn)。我們不應(yīng)該期待模糊代碼來(lái)保證安全,而應(yīng)該采用以下方法:
盡早、盡可能徹底地實(shí)施模糊測(cè)試,在將代碼發(fā)布到外部之前消除模糊測(cè)試能夠發(fā)現(xiàn)的缺陷。
通過(guò)人見(jiàn)人愛(ài)的強(qiáng)類型系統(tǒng)的編程語(yǔ)言編寫代碼——這可以靜態(tài)地消除由于錯(cuò)誤的編程習(xí)慣造成的問(wèn)題,例如可以防止我們將錯(cuò)誤的東西放入哈希映射。
積極地使用斷言和sanitizer來(lái)動(dòng)態(tài)檢查類型系統(tǒng)無(wú)法靜態(tài)強(qiáng)制執(zhí)行的屬性。
反模糊技術(shù)的確存在,但我不認(rèn)為它代表軟件朝著更好的方向發(fā)展。
總結(jié)
隨機(jī)測(cè)試非常強(qiáng)大,我們理應(yīng)善加利用:如果你不針對(duì)你的代碼展開(kāi)模糊測(cè)試,那么別人也會(huì)。本文向軟件開(kāi)發(fā)人員介紹了一些實(shí)施模糊測(cè)試的好方法。當(dāng)然還有很多其他方面本文未能提及,比如選擇一個(gè)優(yōu)秀的語(yǔ)料庫(kù)以及編寫一個(gè)良好的模糊驅(qū)動(dòng)程序。
原文:https://blog.regehr.org/archives/1687
本文為 CSDN 翻譯,轉(zhuǎn)載請(qǐng)注明來(lái)源出處。
【END】
?熱 文?推 薦?
?頂配 12699 元、沒(méi)有 5G,“浴霸三攝”的 iPhone 到底長(zhǎng)什么樣??Mate 30 不預(yù)裝任何谷歌應(yīng)用;阿里巴巴發(fā)布新“六脈神劍”;VS Code 1.38 發(fā)布 | 極客頭條?超 60 萬(wàn) GPS 定位服務(wù)被曝漏洞,用戶信息或?qū)⒈┞?#xff01;?2億日活,日均千萬(wàn)級(jí)視頻上傳,快手推薦系統(tǒng)如何應(yīng)對(duì)技術(shù)挑戰(zhàn)??Docker容器化部署Python應(yīng)用?給面試官講明白:一致性Hash的原理和實(shí)踐?預(yù)警,CSW的50萬(wàn)枚塵封BTC即將重返市場(chǎng)??她說(shuō):行!沒(méi)事別嫁程序員!你點(diǎn)的每個(gè)“在看”,我都認(rèn)真當(dāng)成了喜歡
總結(jié)
以上是生活随笔為你收集整理的idea2020shezhi代码检查级别_优秀的模糊测试代码是如何炼成的?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: mac hdmi 不能调整音量_如何使用
- 下一篇: c++ 无法读取内存_Linux内存机制