sulley 是一款模糊測試框架芬萍,可以使用 sulley 進(jìn)行協(xié)議Fuzzing衷快。Sulley(以作者的觀點來看)所具有的能力超過了以前所發(fā)布的大多數(shù)模糊測試技術(shù)宙橱,包括商業(yè)工具和那些在公開領(lǐng)域中可用的工具。該框架的目標(biāo)是不僅要簡化數(shù)據(jù)的表示蘸拔,而且還要簡化數(shù)據(jù)的傳輸以及對目標(biāo)的監(jiān)視师郑。Sulley從Monsters,Inc創(chuàng)建之后就被親切的命名 ,因為它是模糊化的工具〉髑希現(xiàn)在sulley 已經(jīng)停止更新宝冕,不在維護(hù)。
sulley 安裝教程
sulley 的Windows的安裝 網(wǎng)上教程很多, 對于linux的安裝比較少. 這是linux的安裝教程
安裝測試環(huán)境
deepin 15.3
python2.7
安裝系統(tǒng)環(huán)境:
$ sudo apt-get install python
$ Sudo apt-get install flex
$ Sudo apt-get install bison
Install libpcap-1.4.0
http://www.tcpdump.org/release/libpcap-1.4.0.tar.gz
$ ./configure
$ make
$ sudo make install
$ sudo apt-get install libpcap-dev
$ sudo apt-get install python-pcapy
之后下載sulley目錄
git clone https://github.com/Bit9/sulley.git sulley
由于在linux 還需要相關(guān)依賴
所以下載
解壓vdb在sulley 的父目錄下 即跟sulley 處于同一目錄
最后的目錄結(jié)構(gòu)
.
├── sulley
│ ├── archived_fuzzies
│ ├── AUTHORS.txt
│ ├── CONTRIBUTORS.txt
│ ├── docs
│ ├── ftp_session.py
│ ├── init.py
│ ├── installer
│ ├── INSTALL.txt
│ ├── LICENSE.txt
│ ├── network_monitor.py
│ ├── process_monitor.py
│ ├── README.md
│ ├── requests
│ ├── session_test.udg
│ ├── sulley
│ ├── unit_test.py
│ ├── unit_tests
│ ├── utils
│ ├── vmcontrol.py
│ └── wftpserver.session
└── vdb
├── cobra
├── docs
├── Elf
├── envi
├── mach
├── PE
├── README
├── scripts
├── vdb
├── vdbbin
├── visgraph
├── vqt
├── vstruct
├── vtrace
└── vwidget
安裝python 環(huán)境
python 環(huán)境下需要安裝 distorm 包
pip install distorm3
pip install pcapy
pip install
sulley 目錄結(jié)構(gòu)
在Sulley的目錄結(jié)構(gòu)中存在著一些技巧邓萨。對目錄結(jié)構(gòu)進(jìn)行維護(hù)將可以確保當(dāng)你使用用戶定義的復(fù)雜類型地梨、請求以及工具對模糊器進(jìn)行擴(kuò)展時,目錄中的所有內(nèi)容仍然是有組織的缔恳。下面的層次關(guān)系指出了你需要了解的有關(guān)目錄結(jié)構(gòu)的一些內(nèi)容:
-
archived_fuzzies:這是一個自由格式的目錄宝剖,由模糊測試目標(biāo)應(yīng)用的名字進(jìn)行組織,以存儲已存檔的模糊器以及從模糊測試會話中所生成的數(shù)據(jù)歉甚。
trend_server_protect_5168:包含將在本文檔后面的單步遍歷中被引用的已執(zhí)行完畢的模糊測試万细。
trillian_jabber:包含文檔將引用的另外一個已執(zhí)行完畢的模糊測試。
audits:針對活動的模糊測試會話所記錄的PCAP铃芦、崩潰的二進(jìn)制文件雅镊、代碼覆蓋以及分析圖等應(yīng)當(dāng)被保存到這個目錄中。一旦模糊測試執(zhí)行完畢刃滓,應(yīng)當(dāng)將所記錄的數(shù)據(jù)轉(zhuǎn)移到archived_fuzzies目錄中。
docs:該目錄包含相關(guān)文檔以及所生成的Epydoc API引用耸弄。
-
requests:該目錄是Sulley請求庫咧虎。每個目標(biāo)應(yīng)用都應(yīng)當(dāng)獲得其自己的文件,該文件可以被用來存儲多個請求计呈。
_REQUESTS_html:這個文件包含針對所存儲的請求分類的描述砰诵,并且列出了單個的類型。它是按照字母順序來進(jìn)行維護(hù)的捌显。
http.py:表示不同的Web服務(wù)器模糊測試請求茁彭。
trend.py:包含與本文檔后面所討論的完整的模糊測試走查相關(guān)聯(lián)的請求。
-
sulley:該目錄是模糊器的框架扶歪。除非你想要擴(kuò)展該框架理肺,否則的話不要觸及這些文件。
legos:包含用戶所定義的復(fù)雜原始類型。
ber.py:包含ASN.1/BER原始類型妹萨。
dcerpc.py:包含微軟的RPC NDR原始類型年枕。
misc.py:包含多種不同的未分類的復(fù)雜原始類型,如郵件地址和主機(jī)名等乎完。
xdr.py:包含XDR類型熏兄。
pgraph:該目錄包含Python圖形抽象庫。在構(gòu)建會話時使用树姨。
-
utils:包含不同的幫助例程摩桶。
dcerpc.py:微軟的RPC幫助例程,例如實現(xiàn)綁定到一個接口或者生成一個請求帽揪。
misc.py:包含不同的未分類例程硝清,比如CRC-16以及UUID操縱例程。
scada.py:包含一個DNP3塊編碼器的特定于SCADA的幫助例程台丛。
init_py:這里定義了在創(chuàng)建請求時所使用的不同的s別名耍缴。
blocks.py:這里定義了塊以及塊的幫助例程。
pedrpc.py:這個文件定義了Sulley所使用的在不同的代理與主模糊器之間進(jìn)行通信的客戶端和服務(wù)器類挽霉。
primitives.py:該文件定義了不同的模糊器原始類型防嗡,包括靜態(tài)類型、隨機(jī)類型侠坎、字符串類型以及整數(shù)類型等蚁趁。
sessions.py:這個文件包含構(gòu)建以及執(zhí)行一個會話所需要的功能。
sex.py:包含Sulley的定制異常處理類实胸。
-
unit_tests:該目錄包含Sulley的單元測試套件他嫡。
-
utils:包含多種不同的單機(jī)版工具。
Crashbin_explorer.py:包含用于研究存儲在序列化的崩潰bin文件中的結(jié)果的命令行工具庐完。
pcap_cleaner.py:包含用于清除一個PCAP目錄中與錯誤不相關(guān)的所有條目的命令行工具钢属。
-
network_monitor.py:包含PedRPC驅(qū)動的網(wǎng)絡(luò)監(jiān)視代理。
process_monitor.py:包含PedRPC驅(qū)動的门躯、基于調(diào)試器的目標(biāo)監(jiān)視代理淆党。
unit_test.py:Sulley的單元測試套件。
vmcontrol.py:包含PedRPC驅(qū)動的VMWare控制代理讶凉。
參考網(wǎng)址
http://blog.163.com/wuzhiyong_430/blog/static/48883052201351310184631
https://github.com/Bit9/sulley/blob/master/INSTALL.txt
http://download.csdn.net/download/xiaoliyaqian/8402057
https://github.com/OpenRCE/sulley/issues/51
https://github.com/Bit9/sulley
1染乌、sulley 用法
1.數(shù)據(jù)表示:這是使用任何模糊器所需要執(zhí)行的第一個步驟。運行你的目標(biāo)應(yīng)用懂讯,并且當(dāng)攔截包時處理某些接口荷憋。將協(xié)議分解為單獨的請求,并使用Sulley將它們表示為塊褐望。
2.會話:將所開發(fā)的請求進(jìn)行連接以形成一個會話勒庄,并將其關(guān)聯(lián)到不同的可用的Sulley監(jiān)視代理(socket,調(diào)試器等等)串前,然后開始執(zhí)行模糊測試。
3.事后工作:對生成的數(shù)據(jù)以及所監(jiān)視的結(jié)果進(jìn)行評審锅铅。重放單獨的測試用例酪呻。
2、sulley 目錄結(jié)構(gòu)
在Sulley的目錄結(jié)構(gòu)中存在著一些技巧盐须。對目錄結(jié)構(gòu)進(jìn)行維護(hù)將可以確保當(dāng)你使用用戶定義的復(fù)雜類型玩荠、請求以及工具對模糊器進(jìn)行擴(kuò)展時,目錄中的所有內(nèi)容仍然是有組織的贼邓。下面的層次關(guān)系指出了你需要了解的有關(guān)目錄結(jié)構(gòu)的一些內(nèi)容:
archived_fuzzies:這是一個自由格式的目錄阶冈,由模糊測試目標(biāo)應(yīng)用的名字進(jìn)行組織,以存儲已存檔的模糊器以及從模糊測試會話中所生成的數(shù)據(jù)塑径。
trend_server_protect_5168:包含將在本文檔后面的單步遍歷中被引用的已執(zhí)行完畢的模糊測試女坑。
trillian_jabber:包含文檔將引用的另外一個已執(zhí)行完畢的模糊測試。
audits:針對活動的模糊測試會話所記錄的PCAP统舀、崩潰的二進(jìn)制文件匆骗、代碼覆蓋以及分析圖等應(yīng)當(dāng)被保存到這個目錄中。一旦模糊測試執(zhí)行完畢誉简,應(yīng)當(dāng)將所記錄的數(shù)據(jù)轉(zhuǎn)移到archived_fuzzies目錄中碉就。
docs:該目錄包含相關(guān)文檔以及所生成的Epydoc API引用。
requests:該目錄是Sulley請求庫闷串。每個目標(biāo)應(yīng)用都應(yīng)當(dāng)獲得其自己的文件瓮钥,該文件可以被用來存儲多個請求。
_REQUESTS_html:這個文件包含針對所存儲的請求分類的描述烹吵,并且列出了單個的類型碉熄。它是按照字母順序來進(jìn)行維護(hù)的。
http.py:表示不同的Web服務(wù)器模糊測試請求肋拔。
trend.py:包含與本文檔后面所討論的完整的模糊測試走查相關(guān)聯(lián)的請求锈津。
sulley:該目錄是模糊器的框架。除非你想要擴(kuò)展該框架凉蜂,否則的話不要觸及這些文件一姿。
legos:包含用戶所定義的復(fù)雜原始類型。
ber.py:包含ASN.1/BER原始類型跃惫。
dcerpc.py:包含微軟的RPC NDR原始類型。
misc.py:包含多種不同的未分類的復(fù)雜原始類型艾栋,如郵件地址和主機(jī)名等爆存。
xdr.py:包含XDR類型。
pgraph:該目錄包含Python圖形抽象庫蝗砾。在構(gòu)建會話時使用先较。
utils:包含不同的幫助例程携冤。
dcerpc.py:微軟的RPC幫助例程,例如實現(xiàn)綁定到一個接口或者生成一個請求闲勺。
misc.py:包含不同的未分類例程曾棕,比如CRC-16以及UUID操縱例程。
scada.py:包含一個DNP3塊編碼器的特定于SCADA的幫助例程菜循。
init_py:這里定義了在創(chuàng)建請求時所使用的不同的s別名翘地。
blocks.py:這里定義了塊以及塊的幫助例程。
pedrpc.py:這個文件定義了Sulley所使用的在不同的代理與主模糊器之間進(jìn)行通信的客戶端和服務(wù)器類癌幕。
primitives.py:該文件定義了不同的模糊器原始類型衙耕,包括靜態(tài)類型、隨機(jī)類型勺远、字符串類型以及整數(shù)類型等橙喘。
sessions.py:這個文件包含構(gòu)建以及執(zhí)行一個會話所需要的功能。
sex.py:包含Sulley的定制異常處理類胶逢。
unit_tests:該目錄包含Sulley的單元測試套件厅瞎。
utils:包含多種不同的單機(jī)版工具。
Crashbin_explorer.py:包含用于研究存儲在序列化的崩潰bin文件中的結(jié)果的命令行工具初坠。
pcap_cleaner.py:包含用于清除一個PCAP目錄中與錯誤不相關(guān)的所有條目的命令行工具和簸。
network_monitor.py:包含PedRPC驅(qū)動的網(wǎng)絡(luò)監(jiān)視代理。
process_monitor.py:包含PedRPC驅(qū)動的某筐、基于調(diào)試器的目標(biāo)監(jiān)視代理比搭。
unit_test.py:Sulley的單元測試套件。
vmcontrol.py:包含PedRPC驅(qū)動的VMWare控制代理南誊。
3身诺、sulley 數(shù)據(jù)表示
3.1 靜態(tài)和隨機(jī)的原始類型
num_mutations(整數(shù)值,默認(rèn)值是25):在恢復(fù)到默認(rèn)值之前要進(jìn)行的變異的數(shù)量抄囚。
fuzzable(布爾值霉赡,默認(rèn)值是True):將對此原始類型的模糊測試設(shè)置為使能或者不使能。
name(字符串值幔托,默認(rèn)值是None):在所有Sulley對象中穴亏,指定一個名字就可以在整個請求中直接訪問該原始類型。
num_mutations關(guān)鍵字參數(shù)指定了在該原始類型被認(rèn)為用完之前重挑,應(yīng)當(dāng)被重新顯示多少次嗓化。為了用隨機(jī)數(shù)據(jù)填充一個靜態(tài)大小的字段,可以將'min_length'和'max_length'的值設(shè)置為相同值谬哀。
3.2整數(shù)類型
一個字節(jié):s_byte(),s_char()
兩個字節(jié):s_word(),s_short()
四個字節(jié):s_dword(),s_long(),s_int()
八個字節(jié):s_qword(),s_double()
每個整數(shù)類型至少接受一個單一的參數(shù)刺覆,即默認(rèn)的整數(shù)值。另外史煎,下面的可選的關(guān)鍵字參數(shù)也可以被指定:
endian(字符型谦屑,默認(rèn)值為'<'):位字段的存放順序驳糯。將低位字節(jié)先存放在低地址處的順序指定為<,將高位字節(jié)先存放在低地址處的順序指定為>氢橙。
format(字符串型酝枢,默認(rèn)值是"binary"):將輸出格式指定為"binary"或者"ascii",用以控制整數(shù)原始類型的顯示格式悍手。例如帘睦,值100以ASCII格式顯示為"100",而以二進(jìn)制格式則顯示為"\x64"谓苟。
signed(布爾型官脓,默認(rèn)值是False):將大小設(shè)置為有符號的或者無符號的,只有當(dāng)輸出格式設(shè)定為"ascii"時才可應(yīng)用該類型涝焙。
full_range(布爾型卑笨,默認(rèn)值是False):如果其值為真,那么該原始類型將變異所有可能的值(稍后將對該類型進(jìn)行更加詳細(xì)的介紹)仑撞。
fuzzable(布爾型赤兴,默認(rèn)值是True):將對該原始類型的模糊測試設(shè)置為使能或者不使能。
name(字符串型隧哮,默認(rèn)值是None):在所有的Sulley對象中桶良,指定一個名字就可以在整個請求中直接訪問該原始類型。
full_range修飾符在上述這些類型中是特別有趣的一個沮翔≡煞考慮你想要對一個DWORD值進(jìn)行模糊測試,總共有4294967295個可能的值采蚀。以每秒鐘執(zhí)行10個測試用例的速度來計算疲牵,它將會耗費13年的時間完成對這個單一的原始類型的模糊測試。為了減少巨大的輸入空間榆鼠,Sulley在默認(rèn)情況下只嘗試那些"智能"值纲爸。這包括對0周圍的10個邊界測試用例加上或減去適當(dāng)?shù)闹担畲蟮恼麛?shù)值(MAX_VAL)妆够,MAX_VAL/2识啦,MAX_VAL/3,MAX_VAL/4神妹,MAX_VAL/8颓哮,MAX_VAL/16,MAX_VAL/32鸵荠√夥縮減后的輸入空間只包含141個測試用例,而執(zhí)行這些測試用例只需要幾秒鐘的時間。
3.3 字符串和分隔符
size(整數(shù)值嵌赠,默認(rèn)值是-1):該字符串的靜態(tài)大小。為了指定動態(tài)大小熄赡,將該值設(shè)置為-1姜挺。
padding(字符型,默認(rèn)值是'\x00'):如果一個顯式大小被指定彼硫,并且所生成的字符串要小于該大小炊豪,那么就使用該值將字段變?yōu)榈扔诖笮≈怠?/p>
encoding(字符串型,默認(rèn)值是"ascii"):編碼以為字符串所用拧篮。有效選項包括Python str.encode()例程可以接受的任何內(nèi)容词渤。對于微軟的Unicode字符串而言,將其指定為"utf_16_le"串绩。
fuzzable(布爾值缺虐,默認(rèn)值是True):將對該原始類型的模糊測試設(shè)置為使能或者不使能。
name(字符串型礁凡,默認(rèn)值是None):在所有的Sulley對象中高氮,指定一個名字就可以在整個請求中直接訪問該原始類型。
通過使用分隔符顷牌,字符串經(jīng)常被解析為子字段剪芍。例如,空格字符在HTTP請求GET/index.html HTTP/1.0中就被用做一個分隔符窟蓝。在這個請求當(dāng)中罪裹,前面的斜線(/)和點(.)字符同樣也是分隔符。當(dāng)在Sulley中定義一個協(xié)議時运挫,要確保使用s_delim()原始類型來表示分隔符状共。同其它的原始類型一樣,第一個參數(shù)是強(qiáng)制使用的滑臊,并且被用來指定默認(rèn)值口芍。同樣评腺,與其它原始類型一樣印蔗,s_delim()也接受可選的'fuzzable'和'name'關(guān)鍵字參數(shù)存哲。針對分隔符的變異包括重復(fù)顶燕、替換和刪除味滞。作為一個完整的例子熄求,考慮針對HTML主體標(biāo)簽進(jìn)行模糊測試的原始類型序列次兆。
3.4 塊
group(字符串型箱舞,默認(rèn)值是None):該塊所關(guān)聯(lián)的群組的名字(稍后將對此進(jìn)行更加詳細(xì)的介紹)贮折。
encoder(函數(shù)指針裤翩,默認(rèn)值是None):指向一個函數(shù)的指針,該函數(shù)在返回所顯示的數(shù)據(jù)之前顯示該數(shù)據(jù)。
dep(字符串型踊赠,默認(rèn)值是None):可選的原始類型呵扛,該塊依賴于該類型的特定值。
dep_value(混合類型筐带,默認(rèn)值是None):為了能夠顯示塊今穿,dep字段必須要包含的值。
dep_value(混合類型的列表伦籍,默認(rèn)值是[]):為了能夠顯示塊蓝晒,dep字段可能將包含的值。
dep_compare(字符串型帖鸦,默認(rèn)值是"=="):應(yīng)用于依賴的比較方法芝薇。有效的選項包括==,!=,>,>=,<以及<=。
分組作儿、編碼和依賴是在其它的大多數(shù)框架中所沒有的功能強(qiáng)大的特性洛二,因此值得對它們進(jìn)行深入的研究。
3.5 群組
分組允許你將一個塊關(guān)聯(lián)到一個群組原始類型立倍,以指定該塊應(yīng)當(dāng)為群組內(nèi)部的每個值來循環(huán)遍歷所有可能的變異灭红。例如,群組原始類型對于表示帶有相似參數(shù)結(jié)構(gòu)的有效操作碼或動詞的一個列表是非常有用的口注。原始類型s_group()定義了一個群組变擒,并且接受兩個強(qiáng)制使用的參數(shù)。第一個參數(shù)指定了群組的名字寝志,第二個參數(shù)指定了將要遍歷的娇斑、可能的原始值的列表。作為一個簡單的例子材部,考這個完整的Sulley請求毫缆,該請求被設(shè)計為對一個Web服務(wù)器進(jìn)行模糊測試。
在該腳本的開始乐导,首先導(dǎo)入了Sulley的所有構(gòu)件苦丁。接下來,初始化了一個新的請求物臂,并且將其命名為HTTP BASIC旺拉。在后面可以通過引用這個名字來直接訪問該請求。然后定義了一個群組棵磷,其名字為verbs蛾狗,所包含的可能的字符串值為GET,HEAD,POST以及TRACE。接著啟動了一個新塊仪媒,其名字為body沉桌,并且通過可選的group關(guān)鍵字參數(shù)將其關(guān)聯(lián)到前面所定義的群組原始類型。注意s_block_start()將一直返回True,這就允許你可以使用一個簡單的if語句來識別出其所包含的原始類型留凭。同時注意到s_block_end()的name參數(shù)也是可選的佃扼。這些框架的設(shè)計決定純粹是出于美觀的目的而做出的。接著冰抢,在body塊的內(nèi)部定義了一系列基本的分隔符和字符串原始類型松嘶,然后將該塊關(guān)閉。當(dāng)將這個被定義的請求加載到一個Sulley會話中時挎扰,模糊器將為該塊生成并傳遞所有可能的值,每次為群組中定義的每個動詞生成并傳遞值巢音。
3.6 編碼器
編碼器是一個簡單而又功能強(qiáng)大的塊修飾符遵倦。可以指定一個函數(shù)并將其關(guān)聯(lián)到一個塊官撼,以在通過網(wǎng)絡(luò)返回和傳輸之前梧躺,來修改所顯示的該塊的內(nèi)容。使用一個現(xiàn)實世界中的例子可以更好的對此進(jìn)行解釋傲绣。來自于Trend微控制管理器的DcsProcessor.exe daemon程序在TCP端口20901進(jìn)行監(jiān)聽掠哥,并且期望接收被私有的XOR編碼例程所格式化的數(shù)據(jù)。通過對解碼器實施逆向工程秃诵,開發(fā)了XOR編碼例程续搀。
Sulley編碼器包含一個單一的參數(shù),即將要編碼的數(shù)據(jù)菠净,并且返回被編碼的數(shù)據(jù)〗希現(xiàn)在可以將這個定義的編碼器關(guān)聯(lián)到包含可模糊化原始類型的一個塊,并且允許模糊器的開發(fā)者繼續(xù)工作就好像不存在這個小的障礙一樣毅往。
3.7 依賴
依賴允許你將一個條件應(yīng)用于一個完整塊的顯示中牵咙。其實現(xiàn)過程如下,首先使用可選的dep關(guān)鍵字參數(shù)將一個塊與它將要依賴的原始類型相連接攀唯。當(dāng)Sulley準(zhǔn)備顯示依賴塊時洁桌,它將會檢查所連接的原始類型的值并相應(yīng)的采取行為『钹郑可以使用dep_value關(guān)鍵字參數(shù)來指定一個依賴值另凌。另外,可以使用dep_values關(guān)鍵字參數(shù)來指定依賴值的一個列表残拐。最后途茫,可以通過使用dep_compare關(guān)鍵字參數(shù)來修改實際的條件比較。例如溪食,考慮這樣一個情形囊卜,取決于一個整數(shù)的值而期望得到不同的數(shù)據(jù)。
可以采用多種方法將塊依賴串接起來,以構(gòu)成功能更加強(qiáng)大(但也更為復(fù)雜)的組合栅组。
3.8 塊幫助函數(shù)
為了有效的利用Sulley雀瓢,你必須要熟悉的關(guān)于數(shù)據(jù)生成的一個重要方面就是塊幫助函數(shù)。這些函數(shù)包括大小計算函數(shù)(sizers)玉掸、校驗和函數(shù)(checksums)和重復(fù)函數(shù)(repeaters)等刃麸。
3.9 大小計算函數(shù)
SPIKE的用戶將會對塊幫助函數(shù)s_sizer()(或s_size())非常熟悉。該幫助函數(shù)使用塊的名字來度量第一個參數(shù)的大小司浪,并且接受如下的額外關(guān)鍵字參數(shù):
endian(字符型泊业,默認(rèn)值為'<'):位字段的存放順序。將低位字節(jié)先存放在低地址處的順序指定為<啊易,將高位字節(jié)先存放在低地址處的順序指定為>吁伺。
format(字符串型,默認(rèn)值是"binary"):將輸出格式指定為"binary"或者"ascii"租谈,用以控制整數(shù)原始類型的顯示格式篮奄。
inclusive(布爾型,默認(rèn)值是False):大小計算函數(shù)應(yīng)當(dāng)計算其自己的長度嗎割去?
signed(布爾型窟却,默認(rèn)值是False):將大小設(shè)置為有符號的或者無符號的,只有當(dāng)輸出格式設(shè)定為"ascii"時才可應(yīng)用該類型呻逆。
fuzzable(布爾型夸赫,默認(rèn)值是False):將對該原始類型的模糊測試設(shè)置為使能或者不使能。
name(字符串型页慷,默認(rèn)值是None):在所有的Sulley對象中憔足,指定一個名字就可以在整個請求中直接訪問該原始類型。
大小計算函數(shù)是數(shù)據(jù)生成中的一個重要構(gòu)件酒繁,它允許表示諸如XDR符號和ASN.1等的復(fù)雜協(xié)議滓彰。當(dāng)顯示大小計算函數(shù)時,Sulley將會動態(tài)的計算所關(guān)聯(lián)塊的長度州袒。在默認(rèn)情況下揭绑,Sulley將不會對size字段進(jìn)行模糊測試。在許多情況下我們需要進(jìn)行這樣的處理郎哭,然而他匪,如果不想這樣處理,那么就將可模糊化標(biāo)志設(shè)置為使能夸研。
3.10 校驗和
類似于大小計算函數(shù)邦蜜,s_checksum()幫助函數(shù)使用塊的名字來計算第一個參數(shù)的校驗和。同時也可以指定下面的可選的關(guān)鍵字參數(shù):
algorithm(字符串型或者是函數(shù)指針亥至,默認(rèn)值是"crc32"):應(yīng)用于目標(biāo)塊的校驗和算法(crc32,adler32,md5,sha1)悼沈。
endian(字符型贱迟,默認(rèn)值為'<'):位字段的存放順序。將低位字節(jié)先存放在低地址處的順序指定為<絮供,將高位字節(jié)先存放在低地址處的順序指定為>衣吠。
length(整數(shù)值,默認(rèn)值是0):校驗和的長度壤靶,其值為0時表示自動計算缚俏。
name(字符串型,默認(rèn)值是None):在所有的Sulley對象中贮乳,指定一個名字就可以在整個請求中直接訪問該原始類型忧换。
該算法的參數(shù)可以是crc32,adler32,md5或者sha1中的一個。另外向拆,你還可以為該參數(shù)指定一個函數(shù)指針包雀,以應(yīng)用一個定制的校驗和算法。
3.11 重復(fù)函數(shù)
可以使用s_repeat()(或者s_repeater()函數(shù))對一個塊重復(fù)可變數(shù)量的次數(shù)亲铡。例如,當(dāng)對帶有多個元素的表中的溢出進(jìn)行測試時葡兑,該函數(shù)是非常有用的奖蔓。該幫助函數(shù)包含三個強(qiáng)制使用的參數(shù):將要被重復(fù)的塊的名字,重復(fù)的最小次數(shù)以及重復(fù)的最大次數(shù)讹堤。另外吆鹤,也可以指定下面的可選的關(guān)鍵字參數(shù):
step(整數(shù)值,默認(rèn)值是1):在最小重復(fù)次數(shù)和最大重復(fù)次數(shù)之間的單步計數(shù)洲守。
fuzzable(布爾型疑务,默認(rèn)值是False):將對該原始類型的模糊測試設(shè)置為使能或者不使能。
name(字符串型梗醇,默認(rèn)值是None):在所有的Sulley對象中知允,指定一個名字就可以在整個請求中直接訪問該原始類型。
考慮下面的例子叙谨,它將所介紹的三個幫助函數(shù)連接到了一起温鸽。我們正在對包含一個字符串表的協(xié)議的一部分進(jìn)行模糊測試。該表中的每個條目包含以下內(nèi)容:一個兩字節(jié)字符串類型的字段手负,一個兩字節(jié)長度字段涤垫,一個字符串字段,最后是一個對字符串字段進(jìn)行計算的CRC32校驗和字段竟终。由于我們不知道這些類型字段的有效值是什么蝠猬,因此我們將使用隨機(jī)數(shù)據(jù)對它們進(jìn)行模糊測試。
這個Sulley腳本將不僅對表條目的解析過程進(jìn)行模糊測試统捶,而且還可能會在對超長表的處理中發(fā)現(xiàn)一個錯誤榆芦。
3.12 Legos
Sulley利用legos來表示用戶定義的構(gòu)件柄粹,如郵件地址、主機(jī)名以及在微軟的RPC ,XDR,ASN.1以及其它標(biāo)準(zhǔn)中所使用的協(xié)議原始類型歧杏。在ASN.1/BER中镰惦,字符串被表示為[0x04][0x84][雙字長度][字符串]的序列。當(dāng)對一個基于ASN.1的協(xié)議進(jìn)行模糊測試時犬绒,在每個字符串的前面加上長度和類型前綴將是非常繁瑣的旺入。取而代之,我們可以定義一個lego凯力,并對其進(jìn)行引用茵瘾。
幾乎所有的lego都遵循著一個類似的格式,而其中的一個例外情形是可選的options關(guān)鍵字參數(shù)咐鹤,它是特定于單個的lego的拗秘。作為一個簡單的例子,考慮如下的對tag lego的定義祈惶,它有助于對XMLish協(xié)議進(jìn)行模糊測試雕旨。
這個示例lego簡單的將所需要的標(biāo)簽作為一個字符串來接受,并且將其封裝到適當(dāng)?shù)姆指舴信跚搿K峭ㄟ^下面的操作來實現(xiàn)這一點的凡涩,即將塊類進(jìn)行擴(kuò)展,并且通過self.push()來手工的將標(biāo)簽分隔符和用戶提供的字符串添加到塊中疹蛉。
這里還有另外一個例子活箕,它生成一個簡單的lego以在Sulley中表示ASN.1/BER 整數(shù)。采用最低層次的通用命名符將所有的整數(shù)表示為四字節(jié)整數(shù)可款,其格式如下:[0x02][0x04][雙字]育韩,其中0x02指明了整數(shù)的類型,0x04指定了該整數(shù)的長度為四字節(jié)闺鲸,雙字表示我們正在解析的實際整數(shù)值筋讨。下面是摘自于sulley\legos\ber.py的示例定義。
4翠拣、會話
一旦你已經(jīng)定義了許多的請求版仔,那么就可以將它們在一個會話中連接起來。同其它的模糊測試框架相比误墓,Sulley所具有的一個主要的優(yōu)越性在于蛮粮,它具備對協(xié)議進(jìn)行深層次模糊測試的能力。這一功能是通過在一個圖中將請求連接在一起來實現(xiàn)的谜慌。在下面的例子中然想,一系列的請求被連接到了一起,并且利用pgraph庫以uDraw格式將圖形加以顯示欣范,而會話和請求類都是從pgraph庫擴(kuò)展而來的变泄。
當(dāng)實例化一個會話時令哟,可以指定如下所示的可選的關(guān)鍵字參數(shù):
sessio_filename(字符串型,默認(rèn)值是None):序列化持久數(shù)據(jù)的文件名妨蛹。指定一個文件名將允許你停止并重新啟動模糊器屏富。
skip(整數(shù)值,默認(rèn)值是0):將要被略過的測試用例數(shù)蛙卤。
sleep_time(浮點數(shù)狠半,默認(rèn)值是1.0):在傳輸測試用例之間的休眠時間。
log_level(整數(shù)值颤难,默認(rèn)值是2):設(shè)置日志級別神年,一個更大的數(shù)字表示將包含更多的日志消息。
proto(字符串型行嗤,默認(rèn)值是"tcp"):通信協(xié)議已日。
timeout(浮點數(shù),默認(rèn)值是5.0):在超時之前等待send()或recv()返回的秒數(shù)栅屏。
Sulley所具備的另外一個高級特性是飘千,它可以在協(xié)議圖結(jié)構(gòu)中所定義的每條邊上記錄回調(diào)函數(shù)。這就允許我們在節(jié)點傳輸之間記錄一個將調(diào)用的函數(shù)栈雳,以實現(xiàn)諸如挑戰(zhàn)響應(yīng)系統(tǒng)這樣的功能占婉。回調(diào)方法必須要采用的原型加以定義甫恩。
5 、實例
5.1 FTP協(xié)議測試
Fuzzing對象: FTP服務(wù)器
環(huán)境:host:windows xpsp2,虛擬機(jī)
工具:sulley framework + ollydbg
首先了解要fuzzing的對象,對fuzzing對象協(xié)議的熟悉程度對fuzzing的結(jié)果有很大影響
FTP的配置就無需多說,21端口,若干FTP命令,因為我對python不是很熟悉,就只能簡單構(gòu)造一些用來fuzz數(shù)據(jù)
第一步:創(chuàng)建一個FTP.py的文件酌予,內(nèi)容如下
# ftp.py 2008-12-17
# we use this moduie to generate fuzzing data
#
from sulley import *
#########################################################
s_initialize("War-FTP")
s_group("verbs",values=["USER","PASSWORD"])
if s_block_start("body",group = "verbs"):
#以verbs形成報文的頭
s_delim(" ")
s_string("A"*1000)
s_static("\r")
s_block_end()
#上面的代碼片斷形成一個如 "USER AAAAAAA...\r"\"PASSWORD AAAAAAAA...."的數(shù)據(jù)報文,
s_initialize()#等函數(shù)在sulley\__init__.py模塊中定義,是作者自己寫的形成請求數(shù)據(jù)的函數(shù)
s_delim(" ")#加入一個空格分隔符
s_string("A"*1000)#,由1000個A組成的字符串
s_static("\r")#回車字符
將ftp.py文件放入/requests目錄下,作為fuzzing的數(shù)據(jù)模塊調(diào)用,讀者可以自行擴(kuò)展,這樣就粗糙的完成了構(gòu)造fuzzing數(shù)據(jù)的工作.
第二步,按照自己的要求完成一個會話,命名為example.py
#sulley module test
#example.py
from sulley import *
#from primitives import *
from requests import ftp
def bind(target):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(target)
s.send("USER anonymous\n")
s.recv(buff,100)
s.send("anonymous\n")
def do_fuzz():
sess = sessions.session(session_filename ="tmp.log")
target = sessions.target("192.168.15.22",21)
#使用procmon監(jiān)控fuzzing
target.procmon = pedrpc.client("192.168.15.22",26002)
target.procmon_options = \
{
"proc_name":"War-ftpd.exe"
}
sess.add_target(target)
# 首先啟動 process_monitor.py -c audits\war-ftp.crashbin -p war-ftpd.exe
#sess.pre_send = bind
sess.connect(s_get("War-FTP"))
sess.fuzz()
print "done fuzzing..."
if 1:
do_fuzz()
第三步 運行我們建立好的example.py
E:\Hack_tools\FUZZTOOL\Fuzz_FrameWork\sulley>example.py
[10:53.43] current fuzz path: -> War-FTP
[10:53.43] fuzzed 0 of 2244 total cases
[10:53.43] fuzzing 4 of 2244
[10:53.45] xmitting: [1.4]
[10:53.46] fuzzing 5 of 2244
[10:53.46] xmitting: [1.5]
[10:53.54] procmon detected access violation on test case #5
[10:53.54] primitive lacks a name, type: delim, default value:
[10:53.54] [INVALID]:41414141 Unable to disassemble at 41414141 from thread 1500
caused access violation
[10:53.54] restarting target process
監(jiān)控程序窗口出現(xiàn)連接的信息磺箕,說明已經(jīng)開始工作了
10:53.43] updating target process name to 'War-ftpd.exe'
10:53.43] debugger thread-1229655223 looking for process name: War-ftpd.exe
10:53.43] debugger thread-1229655223 found match on pid 3676
10:53.54] debugger thread-1229655223 caught access violation: '[INVALID]:414141
1 Unable to disassemble at 41414141 from thread 1500 caused access violation'
10:53.54] debugger thread-1229655223 exiting
10:53.54] starting target process
5.2 私有協(xié)議 SecuRemote 模糊測試
SecuRemote協(xié)議結(jié)構(gòu)
模糊測試邏輯
#!/usr/bin/env python
from sulley import *
SLEEP_TIME=0.5TIMEOUT=3CRASH_THRESHOLD=3# The function Sulley will run prior to sending each mutation. We leverage
# it to setup the target system with the initial packets and response in the
# protocol exchange prior to our target packet.
def preconn(sock):
sock.send("\x51\x00\x00\x00") time.sleep(0.5)
sock.send("\x00\x00\x00\x21")
# Set a socket timeout on the recv so we aren't waiting indefinitely if
# the server crashed from a previous test case.
sock.settimeout(5) response = sock.recv(4)
print "Setup response: ", for i in response:
print "%02x" % ord(i),
print
s_initialize("SecuRemote-Simple-String")
# Create a size field, which is based on the content of the named block
# Sulley uses ">" to indicate big-endian values, "<" is little-endian
s_size("client-name-string", length=4, endian=">")
# This is the block of data used for filling in the s_sizeif s_block_start("client-name-string"):
# "securemote" is the default string
s_string("securemote")
# constant null terminator
s_byte("\x00")
s_block_end()
sess = sessions.session(session_filename="Securemote-Simple-string.sess", sleep_time=SLEEP_TIME, timeout=TIMEOUT, crash_threshold=CRASH_THRESHOLD)
# Call preconn() before each mutation is sent to setup the target
sess.pre_send = preconn
sess.connect(s_get("SecuRemote-Simple-String"))
target = sessions.target("127.0.0.1", 264)
sess.add_target(target)
sess.fuzz()