asp.net 網(wǎng)站備份免費(fèi)域名注冊(cè)網(wǎng)站
1. 引入
模糊測(cè)試是一種自動(dòng)化的軟件測(cè)試技術(shù),它通過(guò)自動(dòng)生成大量隨機(jī)數(shù)據(jù)作為輸入來(lái)測(cè)試程序,以發(fā)現(xiàn)潛在的錯(cuò)誤、漏洞或崩潰。atheris是一個(gè)專(zhuān)門(mén)用于CPython(Python的C語(yǔ)言實(shí)現(xiàn))的模糊測(cè)試框架。
2. 安裝atheris
參考1,筆者在Ubuntu 22.04.3 LTS下( gcc version 11.4.0,cmake version 3.22.1,不需要clang也不需要llvm ),直接用pip install atheris
就能安裝好atheris。但在centos7下,gcc版本較低的情況下,安裝報(bào)錯(cuò)較多且難以正確安裝。
3. fuzz過(guò)程
- 假設(shè)需要對(duì)如下example_library.py中的代碼進(jìn)行fuzz
def CodeBeingFuzzed(number):"""Raises an exception if number is 17."""if number == 17:raise RuntimeError('Number was seventeen!')
- fuzz驅(qū)動(dòng)例子(fuzzing_example.py)如下
import atheris
import sys# This tells Atheris to instrument all functions in the `struct` and
# `example_library` modules.
with atheris.instrument_imports():import structimport example_library@atheris.instrument_func # Instrument the TestOneInput function itself
def TestOneInput(data):if len(data) != 4:return # Input must be 4 byte integer.number, = struct.unpack('<I', data)example_library.CodeBeingFuzzed(number)atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()
這里有幾個(gè)重點(diǎn):
(1)使用atheris.instrument_imports()上下文管理器:
- 這個(gè)上下文管理器用于告訴Atheris框架,它應(yīng)該為在上下文內(nèi)導(dǎo)入的模塊中的所有函數(shù)添加模糊測(cè)試的支持(即“instrument”這些函數(shù))。
- 在這個(gè)例子中,struct和example_library模塊被導(dǎo)入,并且它們的函數(shù)會(huì)被Atheris框架進(jìn)行模糊測(cè)試時(shí)的跟蹤和修改。
(2)定義TestOneInput函數(shù):
這個(gè)函數(shù)是模糊測(cè)試的核心,每個(gè)測(cè)試用例的輸入數(shù)據(jù)都會(huì)傳遞給這個(gè)函數(shù)。
- 使用@atheris.instrument_func裝飾器,這個(gè)函數(shù)本身也被Atheris框架“instrument”了,意味著Atheris可以跟蹤函數(shù)內(nèi)部發(fā)生的各種事件,比如異常和返回值的改變。
- 函數(shù)內(nèi)部首先檢查輸入數(shù)據(jù)的長(zhǎng)度是否為4字節(jié),如果不是,則直接返回。這是因?yàn)楹竺娴膕truct.unpack調(diào)用期望的是一個(gè)4字節(jié)的整數(shù)。
- 使用struct.unpack(‘<I’, data)從輸入數(shù)據(jù)中解包出一個(gè)無(wú)符號(hào)整數(shù)(<I表示小端字節(jié)序的4字節(jié)無(wú)符號(hào)整數(shù))。
然后,這個(gè)整數(shù)被傳遞給example_library.CodeBeingFuzzed函數(shù)進(jìn)行實(shí)際的模糊測(cè)試。
- 直接運(yùn)行fuzz驅(qū)動(dòng)進(jìn)行測(cè)試
python fuzzing_example.py
- 命令行輸出
(env_aa_atheris_py311) bbb@ubuntu:/data/ccc/atheris/example_fuzzers$ python fuzzing_example.py
INFO: Instrumenting struct
INFO: Instrumenting example_library
INFO: Using built-in libfuzzer
WARNING: Failed to find function "__sanitizer_acquire_crash_state".
WARNING: Failed to find function "__sanitizer_print_stack_trace".
WARNING: Failed to find function "__sanitizer_set_death_callback".
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 4169936481
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED cov: 2 ft: 2 corp: 1/1b exec/s: 0 rss: 38Mb
#21 NEW cov: 5 ft: 5 corp: 2/5b lim: 4 exec/s: 0 rss: 38Mb L: 4/4 MS: 4 CopyPart-CopyPart-ShuffleBytes-CopyPart-=== Uncaught Python exception: ===
RuntimeError: Number was seventeen!
Traceback (most recent call last):File "/data/abcd/atheris/example_fuzzers/fuzzing_example.py", line 45, in TestOneInputexample_library.CodeBeingFuzzed(number)File "/data/abcd/atheris/example_fuzzers/example_library.py", line 19, in CodeBeingFuzzedraise RuntimeError('Number was seventeen!')
RuntimeError: Number was seventeen!==1066609== ERROR: libFuzzer: fuzz target exited
SUMMARY: libFuzzer: fuzz target exited
MS: 2 CMP-ChangeBit- DE: "\001\000\000\000"-; base unit: 3f3d2d8955322f325af6db2238355fa07007ebd9
0x11,0x0,0x0,0x0,
\021\000\000\000
artifact_prefix='./'; Test unit written to ./crash-498bcbf6cbffcc8dd2623f388d81f44cfad1014d
Base64: EQAAAA==
(env_aa_atheris_py311) bbb@ubuntu:/data/ccc/atheris/example_fuzzers$
異常之前的輸出解讀:
(1)INFO: Instrumenting struct
和 INFO: Instrumenting example_library
:
這兩條信息表明 Atheris 正在對(duì)特定的結(jié)構(gòu)體和庫(kù)(example_library)進(jìn)行代碼插樁(Instrumentation),這是模糊測(cè)試的一個(gè)步驟,用于收集代碼覆蓋率等信息。
(2)INFO: Using built-in libfuzzer
:
表示 Atheris 使用內(nèi)置的 libFuzzer 引擎來(lái)執(zhí)行模糊測(cè)試。libFuzzer 是一個(gè)由 LLVM 提供的庫(kù),用于自動(dòng)化模糊測(cè)試。
(3)WARNING: Failed to find function "__sanitizer_acquire_crash_state", "__sanitizer_print_stack_trace", "__sanitizer_set_death_callback"
:
這些警告表明 Atheris 或 libFuzzer 在嘗試使用某些與 AddressSanitizer(ASan)相關(guān)的函數(shù)時(shí)失敗了。這可能是因?yàn)楫?dāng)前的測(cè)試環(huán)境或配置不支持這些功能。
(4)INFO: Running with entropic power schedule (0xFF, 100).
:
這表明模糊測(cè)試正在使用一種特定的能量調(diào)度策略(Entropic Power Schedule)?!癳ntropic power schedule” 是一種基于熵理論的調(diào)度策略,主要用于優(yōu)化模糊測(cè)試(fuzzing)中的能量分配。具體來(lái)說(shuō),這種策略通過(guò)為那些能夠最大化信息的種子分配更多的能量來(lái)提高模糊測(cè)試的效率。這種方法被稱(chēng)為 Entropic,并已被集成到流行的灰盒模糊測(cè)試工具 LibFuzzer 中。
(5)INFO: Seed: 4169936481
:
顯示當(dāng)前模糊測(cè)試的隨機(jī)種子值。種子值用于確保測(cè)試的可重復(fù)性。
(6)INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
:
表示沒(méi)有指定最大輸入長(zhǎng)度,因此 libFuzzer 將不會(huì)生成大于 4096 字節(jié)的輸入。
(7)INFO: A corpus is not provided, starting from an empty corpus
:
表明沒(méi)有提供初始測(cè)試用例集(corpus),因此模糊測(cè)試將從空白的測(cè)試用例集開(kāi)始。
(8)#2 INITED cov: 2 ft: 2 corp: 1/1b exec/s: 0 rss: 38Mb 和 #21 NEW cov: 5 ft: 5 corp: 2/5b lim: 4 exec/s: 0 rss: 38Mb L: 4/4 MS: 4 CopyPart-CopyPart-ShuffleBytes-CopyPart-
:
這些是模糊測(cè)試過(guò)程中的狀態(tài)更新。#2 和 #21 表示測(cè)試的不同階段或迭代。cov 表示代碼覆蓋率,ft 表示特征數(shù)(可能指特定的測(cè)試路徑或條件),corp 表示測(cè)試用例集的大小和當(dāng)前狀態(tài),exec/s 表示每秒執(zhí)行的測(cè)試數(shù),rss 表示使用的常駐集大小(內(nèi)存使用量),L 表示當(dāng)前測(cè)試用例的長(zhǎng)度,MS 表示生成當(dāng)前測(cè)試用例所使用的變異策略(Mutation Strategy)。
Uncaught Python exception
:
表示觸發(fā)了一個(gè)異常。
異常之后的輸出解讀:
(1)==1066609== ERROR: libFuzzer: fuzz target exited
:
這條錯(cuò)誤信息表明模糊測(cè)試的目標(biāo)程序(fuzz target)異常退出了
(2)SUMMARY: libFuzzer: fuzz target exited
:
這是對(duì)上一條錯(cuò)誤信息的總結(jié),再次強(qiáng)調(diào)模糊測(cè)試目標(biāo)程序已經(jīng)退出。
(3)MS: 2 CMP-ChangeBit-
:
這表示在生成導(dǎo)致程序退出的測(cè)試用例時(shí),使用了兩個(gè)變異策略(Mutation Strategies):CMP(可能是指比較操作的某種變異)和ChangeBit(改變位)。
(4)DE: "\001\000\000\000"-; base unit: 3f3d2d8955322f325af6db2238355fa07007ebd9
:
DE 表示數(shù)據(jù)變異(Data Mutation)的結(jié)果。這里顯示了一個(gè)具體的變異數(shù)據(jù)(\001\000\000\000),以及一個(gè)基礎(chǔ)單元(base unit),這個(gè)基礎(chǔ)單元可能是指變異操作之前的數(shù)據(jù)或是一個(gè)特定的種子值。
(5)0x11,0x0,0x0,0x0,
:
0x11正好是十進(jìn)制數(shù)的17,這個(gè)數(shù)據(jù)能對(duì)要fuzz的函數(shù)CodeBeingFuzzed產(chǎn)生異常。
(6)\021\000\000\000
:
這是另一個(gè)變異后的數(shù)據(jù)示例,表明在模糊測(cè)試過(guò)程中,數(shù)據(jù)被進(jìn)一步修改以嘗試觸發(fā)不同的程序行為。
(7)artifact_prefix='./'; Test unit written to ./crash-498bcbf6cbffcc8dd2623f388d81f44cfad1014d
:
這條信息表明,當(dāng)模糊測(cè)試目標(biāo)程序退出時(shí),libFuzzer 自動(dòng)將觸發(fā)退出的測(cè)試用例保存到了一個(gè)文件中。artifact_prefix=‘./’ 表示保存的文件位于當(dāng)前目錄下,文件名是 crash-498bcbf6cbffcc8dd2623f388d81f44cfad1014d。這個(gè)文件包含了導(dǎo)致程序退出的具體輸入數(shù)據(jù)。
(8)Base64: EQAAAA==
:
這是觸發(fā)退出的測(cè)試用例的 Base64 編碼表示。Base64 是一種編碼方案,用于將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為 ASCII 字符串。這個(gè)編碼可以用于在文本環(huán)境中傳輸二進(jìn)制數(shù)據(jù),或者在不支持二進(jìn)制數(shù)據(jù)的系統(tǒng)中存儲(chǔ)二進(jìn)制數(shù)據(jù)。
- 輸出crash文件
$ hexdump crash-498bcbf6cbffcc8dd2623f388d81f44cfad1014d
0000000 0011 0000
0000004
從上面輸出數(shù)據(jù)的分析可以看到,0x11,0x0,0x0,0x0,
,0x11正好是十進(jìn)制數(shù)的17,這個(gè)數(shù)據(jù)能對(duì)要fuzz的函數(shù)CodeBeingFuzzed產(chǎn)生異常。
4. 總結(jié)
本文給出了atheris從安裝到fuzz輸入輸出解讀的過(guò)程,例子來(lái)源參考1。
參考
- https://github.com/google/atheris/tree/master
- https://yiyan.baidu.com/