使用Fuzzing工具測試完成之后,如果發現了大量的crashes,我們需要分析crash是否為真的漏洞,同時需要在CVE平台上使用關鍵字查找這些漏洞是否已經被別人發現。
本次的整理是為跟我一樣的初入此行時一片茫然的小伙伴們的,按照自己的理解,本次整理按照以下三個部分進行:POC去重、漏洞類型分析、CVE平台查新與提交。
一、POC去重
可能多個POC觸發同一個crashes
去重方式我居然已經記不清,后面碰到時再補充吧~~~~~
二、漏洞類型分析
包括三種分析方法,分別是crashwalk、GDB、Address Sanitizer,我比較推薦Address Sanitizer。
-
crashwalk
(需要注意:在執行AFL時,需要添加--
參數)
具體做法為:
(1) 安裝go:apt-get install gdb golang
(2) 安裝crashwalk:# mkdir go # export GOPATH=~/go # go get -u github.com/bnagy/crashwalk/cmd/... # ~/go/bin/cwtriage -root . -afl ./path/to/target @@ 對於測試結束結果進行分析:~/go/bin/cwtriage -root fuzzer2/crashes/ -match id -seen ~/afl-experient/binutils-2.29/binutils/objdump -d @@ (同時輸出到屏幕和一個名為crashwalk.db的數據庫中,上面的-seen代表可以對數據庫進行追加寫入,通過~/go/bin/cwdump ./crashwalk.db > triage.txt,可以將漏洞進行分類到txt文件中) NOTES:需要AFL命令為afl-fuzz -i input -o output -- ./binutils/size @@ # cwdump ./crashwalk.db > triage.txt
-
GDB
需要在編譯時添加-g
(gdb) file nasm Reading symbols from nasm...done. (gdb) run -felf ./input/seed1 Starting program: /home/lbb/afl-experient/Tests/ASAN/nasm-2.14.02/nasm -felf ./input/seed1 Program received signal SIGSEGV, Segmentation fault. expr2 (critical=critical@entry=0) at asm/eval.c:482 482 e = expr3(critical); (gdb) info stack #0 expr2 (critical=critical@entry=0) at asm/eval.c:482 #1 0x0000000000422941 in expr1 (critical=critical@entry=0) at asm/eval.c:456 #2 0x0000000000422cc1 in expr0 (critical=0) at asm/eval.c:430 #3 0x0000000000420233 in expr6 (critical=critical@entry=0) at asm/eval.c:857 #4 0x0000000000421139 in expr5 (critical=critical@entry=0) at asm/eval.c:567 #5 0x000000000042201c in expr4 (critical=critical@entry=0) at asm/eval.c:542 #6 0x0000000000422101 in expr3 (critical=critical@entry=0) at asm/eval.c:508 #7 0x00000000004225c1 in expr2 (critical=critical@entry=0) at asm/eval.c:482 #8 0x0000000000422941 in expr1 (critical=critical@entry=0) at asm/eval.c:456 #9 0x0000000000422cc1 in expr0 (critical=0) at asm/eval.c:430
-
Address Sanitizer,最新版gcc的內存檢測工具,用戶可以使用-fsanitize=address標簽對二進制文件進行編譯,這樣如果發生了內存訪問錯誤,用戶可以獲得一份十分詳盡的事件信息。
-
編譯源碼時添加'-fsanitize=address'
想要在錯誤消息中添加更好的堆棧跟蹤,啟用-fno-omit-frame-pointer
,此外還可以使用-O1
進行一級優化的編譯。具體做法為: (1) 對於單個程序編譯,直接在編譯時添加在命令行 如:`gcc -g -fsanitize=address -O1 -fno-omit-frame-pointer ./test.c` (2) 對於含有Makefile的項目,在'CFLAGS'后面添加 如:`CFLAGS = -g -fsanitize=address ......` (3) 對於含有configure的項目 ./configure CFLAGS='-g -fsanitize=address' 即可
-
使用一段python代碼對Fuzzing的crash進行批量化分析:
(此處借鑒於安全客《從零開始學習fuzzing》,在此基礎上做了一小部分修改)
運行方式為# python3 /path/xxx.py /path/crashes /path/program [param] 例如我將此python保存在 ~/mytest/crash_analyze.py,crashes存放在 ~/mytest/jhead-2.04/master/crashes,測試程序為 ~/mytest/jhead-2.04/jhead,因為jhead運行無參數,所以[param]缺省。 # python3 ~/mytest/crash_analyze.py ~/mytest/jhead-2.04/master/crashes ~/mytest/jhead-2.04/jhead 之后會在~/mytest/jhead-2.04/下創建analyze_output,所有分寫結果全部保存於此
#!/usr/bin/env python3 import os from os import listdir from os import sys def get_files(): #files = os.listdir("/root/crashes/") files = os.listdir(sys.argv[1]) return files # argv[1]: crashes dir # argv[2]: program-name # argv[3]: param def triage_files(files): len_argv = len(sys.argv) # 漏洞類型的統計 cout_crashes = {"SEGV": 0, "HBO": 0, "UNKNOWN":0} folder = os.path.exists("analyze_output") if not folder: os.makedirs("analyze_output") for x in files: if len_argv == 4: original_output = os.popen(sys.argv[2] + " " + sys.argv[3] + " " + x + " 2>&1").read() else: original_output = os.popen(sys.argv[2] + " " + os.path.join(sys.argv[1] ,x) + " 2>&1").read() output = original_output # Getting crash reason crash = '' if "SEGV" in output: crash = "SEGV" cout_crashes["SEGV"] += 1 elif "heap-buffer-overflow" in output: crash = "HBO" cout_crashes["HBO"] += 1 else: crash = "UNKNOWN" cout_crashes["UNKNOWN"] += 1 address = '' operation = '' if crash == "HBO": output = output.split("\n") counter = 0 target_line = '' while counter < len(output): if output[counter] == "=================================================================": target_line = output[counter + 1] target_line2 = output[counter + 2] counter += 1 else: counter += 1 target_line = target_line.split(" ") address = target_line[5].replace("0x","") target_line2 = target_line2.split(" ") operation = target_line2[0] elif crash == "SEGV": output = output.split("\n") counter = 0 while counter < len(output): if output[counter] == "=================================================================": target_line = output[counter + 1] target_line2 = output[counter + 2] counter += 1 else: counter += 1 if "unknown address" in target_line: address = "00000000" else: address = None if "READ" in target_line2: operation = "READ" elif "WRITE" in target_line2: operation = "WRITE" else: operation = None log_name = (x + "." + crash + "." + address + "." + operation) fn = os.path.join("analyze_output", log_name) f = open(fn,"w+") f.write(original_output) f.close() print("Numbers of the crash:") for ele in cout_crashes.items(): print(ele) if __name__ == "__main__": if len(sys.argv) == 1: print("Please input \"crash_analyze.py --help \"") elif sys.argv[1] == "--help": print("argv[1]: crashes dir\n",\ "argv[2]: program-name\n",\ "argv[3]: param" ) else: files = get_files() triage_files(files)
三、CVE平台查新與提交
-
查新:確定了分析得到的crash為漏洞之后,需要利用發現漏洞的關鍵信息在CVE平台上查找相應的漏洞是否已經被提交,還可以在所測軟件所屬平台上進行查詢。
例如我們在添加了'-fsanitize=address'編譯得到的jhead-3.04上執行前面的crashes里包含的測試用例之后,得到了如下圖信息,我們發現發生在jhead-3.04下的exif.c文件的Get32s函數出,通過定位到源碼之后發現確實存在此漏洞。 -
我們利用關鍵字
jhead``Get32s
等在CVE網站進行搜索
CVE網站:https://cve.mitre.org/-
如果發現相關信息,則需要點進去看相應版本和具體發生位置等信息(此漏洞為我1月份提交的)
-
如果沒有發現相關信息,並不意味着一定沒有,我們需要擴大范圍,例如前面是用兩個關鍵詞,可以直接用jhead關鍵詞,還可以在其軟件對應官網或其他平台
-
-
提交:我們可以將自己發現的漏洞的描述放在一個可以訪問的網站,自己創建的、github上存放的、或其他平台上描述的(因為我也是摸着石頭過河,參考一下CVE平台上的前輩們的鏈接),都可以,在CVE平台提交的時候提供相應鏈接即可。
如何提交,這篇文章寫得非常棒CVE申請的那些事- 描述:
例如我提交的描述信息一般放在https://launchpad.net/ubuntu 因為此網站包含了一些ubuntu上的軟件,直接定位的相應軟件即可進行描述。
- 提交:前面都准備完成之后就是在CVE網站上的提交了,提交時可以同時提交好幾個,我有一次連續提交了3個matio的,但后沒有任何相應,具體我也不清楚了(我的理解是有些軟件比較快,有些比較慢吧,我剛查詢完matio相關的CVE,發現依然停留在2019)。
-
查找相應的CNA,如果無法確定自己所提交軟件的CNA,可以按照前面漏洞查新部分的方法,查找相同軟件的CVE編號里描述的對應的CNA即可。如jhead屬於MITRE Corporation,點擊后面的Web鏈接即可。
-
申請CVE-ID,對其進行描述,比較關鍵的一點就是郵箱、申請的個數、還有下面的Discoverer(s)/Credits(即誰發現的)
-
全部提交完之后會返回一份郵件,應該是提示提交成功的,如果快的話一兩天就能收到CVE編號,慢的話一周或者更長時間吧。
- 描述:
這些全部是我的摸索與嘗試,有錯誤或者有更好方案的歡迎評論區大家交流,我們共同進步