0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

qiling fuzz iot設(shè)備測(cè)試及實(shí)例分析

蛇矛實(shí)驗(yàn)室 ? 來源:蛇矛實(shí)驗(yàn)室 ? 2023-07-22 09:05 ? 次閱讀

qiling fuzz 基礎(chǔ)

qiling和AFL++環(huán)境的搭建在前面的小節(jié)中已經(jīng)說過,這里就不再演示。我們進(jìn)入到qiling的qiling/example/fuzzing目錄下,qiling框架官方庫(kù)提供了幾個(gè)fuzz的example供我們學(xué)習(xí)和測(cè)試。我們先對(duì)tenda ac15進(jìn)行測(cè)試。

3c924048-27af-11ee-962d-dac502259ad0.png

根據(jù)README文檔中的介紹,我們首先需要提取tenda ac 15文件系統(tǒng)并放置于腳本同級(jí)目錄中,操作步驟如下:

1. wget https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip
2. unzip US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip
3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin
4. mv xxx/squashfs-root ./rootfs;cd rootfs
5. rm -rf webroot;mv webroot_ro webroot
6. mv etc_ro etc

隨后我們需要運(yùn)行saver_tendaac15_httpd.py

3cc0f726-27af-11ee-962d-dac502259ad0.png

使用netstat -pantl查看監(jiān)聽端口,當(dāng)發(fā)現(xiàn)python3程序正在監(jiān)聽8080端口時(shí),說明tenda ac仿真成功。

3d193df0-27af-11ee-962d-dac502259ad0.png

此時(shí)我們運(yùn)行./addressNet_overflow.sh生成snapshot.bin文件。

3d651e82-27af-11ee-962d-dac502259ad0.png

運(yùn)行./fuzz_tendaac15_httpd.sh進(jìn)行fuzz,經(jīng)過10分鐘左右出現(xiàn)了crash。

3da6f0a0-27af-11ee-962d-dac502259ad0.png

產(chǎn)生的crash文件內(nèi)容如下

3ddf3f00-27af-11ee-962d-dac502259ad0.png

這樣我們就完成對(duì)實(shí)例中tenda ac15的fuzz復(fù)現(xiàn)。官方提供demo的saver和fuzz腳本如下,現(xiàn)在我們對(duì)其進(jìn)行簡(jiǎn)單分析并學(xué)習(xí)。

3e467f58-27af-11ee-962d-dac502259ad0.png3e8efa76-27af-11ee-962d-dac502259ad0.png

通過上一小節(jié)中對(duì)qiling基礎(chǔ)的學(xué)習(xí),我們可以對(duì)兩個(gè)腳本中的函數(shù)功能進(jìn)行拆分。

saver.py

保存快照

defsave_context(ql, *args, **kw):
ql.save(cpu_context=False, snapshot="snapshot.bin")

替換網(wǎng)卡名稱

defpatcher(ql):
br0_addr = ql.mem.search("br0".encode() + b'x00')
foraddr inbr0_addr:
ql.mem.write(addr, b'lox00')

檢查停止地址

defcheck_pc(ql):
print("="* 50)
print("Hit fuzz point, stop at PC = 0x%x"% ql.arch.regs.arch_pc)
print("="* 50)
ql.emu_stop()

網(wǎng)絡(luò)設(shè)置

defnvram_listener():
server_address = 'rootfs/var/cfm_socket'
data = ""

try: 
os.unlink(server_address) 
exceptOSError: 
ifos.path.exists(server_address): 
raise

sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) 
sock.bind(server_address) 
sock.listen(1) 

whileTrue: 
connection, client_address = sock.accept() 
try: 
whileTrue: 
data += str(connection.recv(1024))

if"lan.webiplansslen"indata: 
connection.send('192.168.170.169'.encode()) 
else: 
break
data = ""
finally: 
connection.close()

仿真流程

defmy_sandbox(path, rootfs):
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG)
ql.add_fs_mapper("/dev/urandom","/dev/urandom")
ql.hook_address(save_context, 0x10930)
ql.hook_address(patcher, ql.loader.elf_entry)
ql.hook_address(check_pc, 0x7a0cc)
ql.run()

fuzz.py

替換網(wǎng)卡名稱

defpatcher(ql):
br0_addr = ql.mem.search("br0".encode() + b'x00')
foraddr inbr0_addr:
ql.mem.write(addr, b'lox00')

fuzz流程

defmain(input_file, enable_trace=False):
# 生成qiling實(shí)例
ql = Qiling(["rootfs/bin/httpd"], "rootfs", verbose=QL_VERBOSE.DEBUG, console = Trueifenable_trace elseFalse)

# 恢復(fù)快照內(nèi)容
ql.restore(snapshot="snapshot.bin")

# 變異數(shù)據(jù)地址點(diǎn)定位
fuzz_mem=ql.mem.search(b"CCCCAAAA")
target_address = fuzz_mem[0]

# target_address為fuzz變異點(diǎn),place_input_callback函數(shù)通過afl++對(duì)數(shù)據(jù)進(jìn)行變異
defplace_input_callback(_ql: Qiling, input: bytes, _):
_ql.mem.write(target_address, input)
# fuzz函數(shù)定義
defstart_afl(_ql: Qiling):
ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point]) 

ql.hook_address(callback=start_afl, address=0x10930+8)

# qiling實(shí)例運(yùn)行
try:
ql.run(begin = 0x10930+4, end = 0x7a0cc+4)
os._exit(0)
except:
ifenable_trace:
print("
Fuzzer Went Shit")
os._exit(0)

通過功能的拆分以及我們的分析,可以知道fuzz大致流程是:

1.運(yùn)行saver.py生成qiling實(shí)例仿真運(yùn)行,此時(shí)運(yùn)行addressNet_overflow.sh觸發(fā)相關(guān)執(zhí)行流程,當(dāng)pc寄存器運(yùn)行到0x10930地址時(shí),觸發(fā)保存快照功能。

2.fuzz.sh會(huì)調(diào)用afl++并執(zhí)行fuzz.py腳本對(duì)其input輸入進(jìn)行數(shù)據(jù)變異。

3.fuzz.py腳本中,首先會(huì)恢復(fù)快照狀態(tài),并在內(nèi)容中尋找數(shù)據(jù)變異點(diǎn),并接受afl++的變異數(shù)據(jù)將其寫入數(shù)據(jù)變異點(diǎn)進(jìn)行fuzz。

了解了大致fuzz流程,我們可能存在幾點(diǎn)疑慮:

1.saver.py腳本中如何知道在哪個(gè)地址觸發(fā)保存快照功能?在仿真的httpd程序觸發(fā)執(zhí)行addressNet_overflow.sh執(zhí)行流程后,程序?qū)⒆儺悢?shù)據(jù)存儲(chǔ)至內(nèi)存完成后,就可以觸發(fā)快照保存功能。

2.addressNet_overflow.sh腳本中為什么定義page為CCCCAAAA?CCCCAAAA為poc的溢出標(biāo)識(shí),以便后續(xù)我們進(jìn)行查找定位。

3.fuzz.py腳本中為什么先要替換br0?tenda ac15路由器設(shè)備啟動(dòng)時(shí)會(huì)檢測(cè)br0網(wǎng)卡狀態(tài),我們本地沒有這個(gè)網(wǎng)卡所以替換成了lo。

4.fuzz.py腳本中如何知道ql.run的起始和結(jié)束地址?起始地址是保存快照后面的指令,需要保證執(zhí)行流程的連貫性(保存寄存器狀態(tài)除外),結(jié)束地址便是漏洞函數(shù)可以觸發(fā)crash后的函數(shù)結(jié)束地址。

這里1、4還是不太清楚,帶著疑問我們接著往下分析:

根據(jù)addressNet_overflow.sh腳本中的poc,我們使用ida進(jìn)行定義,發(fā)現(xiàn)漏洞函數(shù)如下,產(chǎn)生漏洞的原因便是沒有對(duì)用戶發(fā)送post包data數(shù)據(jù)中的entrys、mitInterface、page參數(shù)進(jìn)行過濾,并使用sprintf危險(xiǎn)函數(shù)進(jìn)行了寫入。

3edf5584-27af-11ee-962d-dac502259ad0.png

那么我們要fuzz的函數(shù)就是formAddressNat函數(shù)了,首先第1點(diǎn)saver.py腳本中該如何定位保存地址點(diǎn),這里其實(shí)當(dāng)v1=sprintf(xxx)執(zhí)行完畢后,已經(jīng)將用戶參數(shù)數(shù)據(jù)保存到v6中時(shí),就已經(jīng)可以保存快照了(后續(xù)fuzz.py也要進(jìn)行相應(yīng)修改)。這里作者定位的是0x10930,那么后續(xù)fuzz的起始地址和結(jié)束地址分別就是0x10930執(zhí)行流程的后面下一條指令和formAddressNet函數(shù)的結(jié)束地址。

3f197638-27af-11ee-962d-dac502259ad0.png

在分析的過程中,我們可以打開QL_VERBOSE.DISASM來清楚的查看匯編指令的執(zhí)行流程和對(duì)應(yīng)指令的寄存器信息

分析完tenda ac同理example中的dir815實(shí)例也是同樣的流程,只不過dir815的fuzz腳本并沒有使用保存快照功能,而是直接使用ql.mem.search進(jìn)行查找變異數(shù)據(jù)點(diǎn)以及使用ql.mem.write對(duì)變異數(shù)據(jù)進(jìn)行寫入。

3f57abf6-27af-11ee-962d-dac502259ad0.png3f85c23e-27af-11ee-962d-dac502259ad0.png

分析完上面的流程后,我們對(duì)fuzz的流程有了大概理解。后面我們以dlink dir645路由器中的兩個(gè)棧溢出實(shí)例進(jìn)行fuzz測(cè)試。

qiling fuzz 實(shí)例

以經(jīng)典的dir645棧溢出為例,我們使用qiling框架對(duì)兩個(gè)棧溢出漏洞進(jìn)行fuzz測(cè)試。

首先下載固件并使用binwalk -Me 固件名進(jìn)行提取,簡(jiǎn)單查看后發(fā)現(xiàn)本次分析的程序hedwig.cgi和authentication.cgi均為軟鏈接(鏈接到htdocs/cgibin),qiling對(duì)軟連接的處理不是很友好,建議將所有軟連接替換為源文件。

hedwig.cgi棧溢出

我們首先將cgibin拖入ida進(jìn)行簡(jiǎn)單分析,進(jìn)入main函數(shù)后發(fā)現(xiàn),main程序根據(jù)傳入?yún)?shù)與相關(guān)"*.cgi"進(jìn)行比較,隨后進(jìn)入相關(guān)的cgi_main函數(shù)中,那我們先分析一下hedwig.cgi觸發(fā)的棧溢出

3fbee0fa-27af-11ee-962d-dac502259ad0.png

fuzz的第一步就是摸清楚程序的執(zhí)行流程,我們先簡(jiǎn)單編寫仿真程序的腳本,隨后將其改為fuzz腳本。該仿真腳本定義了倆個(gè)hook函數(shù),當(dāng)程序執(zhí)行執(zhí)行地址處后會(huì)執(zhí)行該hook函數(shù),并打印出"Hit at xxx func"。

3fea9ef2-27af-11ee-962d-dac502259ad0.png

執(zhí)行仿真腳本,發(fā)現(xiàn)我們定義的倆個(gè)hook都被觸發(fā),說明我們簡(jiǎn)單分析后的執(zhí)行流程確實(shí)沒錯(cuò),并且調(diào)試信息后續(xù)還打印出了一下回應(yīng)信息。

402cfffe-27af-11ee-962d-dac502259ad0.png

我們繼續(xù)在ida中查找定位該信息,發(fā)現(xiàn)是LABEL_25中的處理,根據(jù)交叉引用,我們追蹤該信息產(chǎn)生的原因是env中沒有REQUEST_METHOD

40986262-27af-11ee-962d-dac502259ad0.png40dceb4e-27af-11ee-962d-dac502259ad0.png

那么我們?cè)趀nv中設(shè)置該環(huán)境變量然后傳入給qiling實(shí)例就可以了,接著往下分析發(fā)現(xiàn)程序的溢出點(diǎn)位于sess_get_uid中,并通過QL_VERBOSE.DISASM信息,我們理清楚了大概的產(chǎn)生漏洞流程。定位了棧溢出地址后,那么我們根據(jù)漏洞產(chǎn)生流程設(shè)置相關(guān)的env參數(shù)數(shù)據(jù)并傳入qiling實(shí)例中,隨后我們使用mem.search()替換成為變異數(shù)據(jù),程序仿真時(shí)就會(huì)取出環(huán)境變量中的值進(jìn)行處理從而產(chǎn)生棧溢出。

注:由于程序是從env中讀取變量的值,所以也就不存在前面提到的拷貝到內(nèi)存中然后觸發(fā)保存快照功能指定流程,這里可以直接觸發(fā)保存快照的功能。

4126958c-27af-11ee-962d-dac502259ad0.png

最終編寫saver.py腳本如下:

importctypes, os, pickle, socket, sys, threading
sys.path.append("..")
fromqiling import*
fromqiling.const importQL_VERBOSE


MAIN = 0x402770
HEDWIGCGI_MAIN = 0x40bfc0
SESSION_UID = 0x4083f0
SAVE_ADDRESS = 0x40c070

deftest_print1(ql: Qiling)->None:
print("Hit at main func")

deftest_print2(ql: Qiling)->None:
print("Hit at hedwig func")

deftest_print3(ql: Qiling)->None:
print("Hit at session uid func")

defsaver(ql: Qiling):
print('[!] Hit Saver 0x%X'%(ql.arch.regs.arch_pc))
ql.save(cpu_context=False, snapshot='./context.bin')

defmy_sandbox(path, rootfs):
env_vars = {
"REQUEST_METHOD": "POST",
"REQUEST_URI": "/hedwig.cgi",
"CONTENT_TYPE": "application/x-www-form-urlencoded",
"REMOTE_ADDR": "127.0.0.1",
"HTTP_COOKIE": "uid=AAAABBBB"
}
ql = Qiling(path, rootfs,env=env_vars,verbose=QL_VERBOSE.DEBUG)
ql.hook_address(test_print1, MAIN)
ql.hook_address(test_print2, HEDWIGCGI_MAIN)
ql.hook_address(test_print3, SESSION_UID)
ql.hook_address(saver, SAVE_ADDRESS)
ql.run()

if__name__ == "__main__":
my_sandbox(["rootfs/htdocs/web/hedwig.cgi"], "rootfs")

執(zhí)行后,保存的快照為context.bin,我們可以使用strings定位棧溢出標(biāo)識(shí)字符串。

41b7a040-27af-11ee-962d-dac502259ad0.png

42281186-27af-11ee-962d-dac502259ad0.png

接下來我們編寫fuzz.py,前面我們觸發(fā)快照的地址為getenv("REQUEST_METHOD") 執(zhí)行后的一條指令,那么我們?cè)诰帉慺uzz.py中ql.run的起始地址時(shí)就應(yīng)該為下一條指令,這里為了方便我直接讓其跳過if判斷直接從cgibin_parse_request處開始執(zhí)行(0x40c0a4)。結(jié)束地址呢,這里直接指定hedwigcgi_main函數(shù)的結(jié)尾就可以(0x40c598),因?yàn)橛幸绯鰯?shù)據(jù)時(shí)程序執(zhí)行到函數(shù)最后一定會(huì)觸發(fā)crash。

42531d40-27af-11ee-962d-dac502259ad0.png

最終hedwig.cgi棧溢出fuzz.py的腳本如下:

importos, pickle, socket, sys, threading
sys.path.append("../../../")
fromqiling import*
fromqiling.const importQL_VERBOSE
fromqiling.extensions.afl importql_afl_fuzz

defmain(input_file, enable_trace=False):
ql = Qiling(["rootfs/htdocs/web/hedwig.cgi"], "rootfs", verbose=QL_VERBOSE.DEBUG)
ql.restore(snapshot="context.bin")
fuzz_mem=ql.mem.search(b"AAAABBBB")
target_address = fuzz_mem[0]

defplace_input_callback(_ql: Qiling, input: bytes, _):
_ql.mem.write(target_address, input)

defstart_afl(_ql: Qiling):
ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point]) 

ql.hook_address(callback=start_afl, address=0x40c0a4)

try:
ql.run(begin = 0x40c0a4, end = 0x40c598)
os._exit(0)
except:
ifenable_trace:
print("
Fuzzer Went Shit")
os._exit(0) 

if__name__ == "__main__":
iflen(sys.argv) == 1:
raiseValueError("No input file provided.")

iflen(sys.argv) > 2andsys.argv[1] == "-t":
main(sys.argv[2], enable_trace=True)
else:
main(sys.argv[1])

不到1分鐘就fuzz到了crash,還是比較快的。

42859798-27af-11ee-962d-dac502259ad0.png

authentication.cgi棧溢出

和上面的分析同理,我們首先跟一下程序的執(zhí)行流程,authentication.cgi的處理函數(shù)為authenticationcgi_main函數(shù)。

42e92628-27af-11ee-962d-dac502259ad0.png

進(jìn)入到authenticationcgi_main函數(shù)后,我們發(fā)現(xiàn)和上面的hedwig類似,也是同樣獲取env中的變量進(jìn)行處理。

431ef258-27af-11ee-962d-dac502259ad0.png

那么我們將前面的腳本進(jìn)行修改,這里直接將HEDWIGCGI_MAIN改為0x40afcc。

3fea9ef2-27af-11ee-962d-dac502259ad0.png

運(yùn)行后發(fā)現(xiàn)執(zhí)行觸發(fā)了倆個(gè)hook函數(shù),說明確實(shí)執(zhí)行到了authenticationcgi_main函數(shù)中。

439a8ab2-27af-11ee-962d-dac502259ad0.png

authentication.cgi觸發(fā)棧溢出的執(zhí)行流程為REQUEST METHOD方法為POST,并且需要設(shè)置"CONTENT_TYPE"和"CONTENT_LENGTH"環(huán)境變量。

43e4b7e0-27af-11ee-962d-dac502259ad0.png

那么我們?cè)趀nv變量中設(shè)置如下參數(shù)并傳入qiling實(shí)例。

注:CONTENT_LENGTH中的999在程序執(zhí)行時(shí)還沒有溢出,v73定義的1024字節(jié)。

44151b10-27af-11ee-962d-dac502259ad0.png

運(yùn)行后發(fā)現(xiàn)已經(jīng)執(zhí)行我們想要其執(zhí)行的流程了,并且需要我們輸入一些信息才可執(zhí)行后面的流程。

4440a06e-27af-11ee-962d-dac502259ad0.png44792074-27af-11ee-962d-dac502259ad0.png

input中含有的內(nèi)容如下,需要包含"id=xxx&password=xxx"

44af88e4-27af-11ee-962d-dac502259ad0.png44d6751c-27af-11ee-962d-dac502259ad0.png

再次執(zhí)行,輸入"id=1&password=123"后,程序正常執(zhí)行。那么我們的fuzz思路如下:

傳入env環(huán)境變量,使其按照漏洞觸發(fā)流程進(jìn)行執(zhí)行,隨后在程序賦值content_length時(shí),進(jìn)行hook,將需要用到的寄存器修改成afl++變異數(shù)據(jù)的大小(其實(shí)這里應(yīng)該取出所有header的字節(jié),不過這里不是很影響),隨后進(jìn)行調(diào)用start_afl進(jìn)行fuzz。寫入棧溢出標(biāo)識(shí)地址的content格式為:b"id=1&password="+input

452ed0ea-27af-11ee-962d-dac502259ad0.png

根據(jù)上面的信息,我們編寫的fuzz.py如下:

importctypes, os, pickle, socket, sys, threading
sys.path.append("../../../")
fromqiling import*
fromqiling.const importQL_VERBOSE
fromqiling.extensions importpipe
fromqiling.extensions.afl importql_afl_fuzz


MAIN = 0x402770
AUTHENTICATION_MAIN = 0x40afcc
CONTENT_LENGTH = 0x40b48c
CONTENT_SIZE = 0x40b4b4
size = 0

deftest_print1(ql: Qiling)->None:
print("Hit at main func")

deftest_print2(ql: Qiling)->None:
print("Hit at authentication func")

deftest_print3(ql: Qiling):
print("address:",hex(ql.arch.regs.s0))

deftest_print4(ql: Qiling):
print("Hit at exit func")

deftest_size(ql: Qiling):
globalsize
ql.arch.regs.s0 = size
ql.arch.regs.a2 = size
print("Hit at test_size func")

defmain(input_file, enable_trace=False):
env_vars = {
"REQUEST_METHOD": "POST",
"REQUEST_URI": "/authentication.cgi",
"CONTENT_TYPE": "application/x-www-form-urlencoded",
"REMOTE_ADDR": "127.0.0.1",
"CONTENT_LENGTH": "100"
}
ql = Qiling(["rootfs/htdocs/web/authentication.cgi"], "rootfs",env=env_vars,verbose=QL_VERBOSE.DEBUG)
ql.os.stdin = pipe.SimpleInStream(0)
ifnotenable_trace:
ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno())
ql.os.stderr = pipe.NullOutStream(sys.stderr.fileno())

defplace_input_callback(ql: Qiling, input: bytes, _: int):
globalsize
content = b"id=1&password="+input
size = len(content)
ql.os.stdin.write(content)
ql.hook_address(test_size,CONTENT_SIZE)

defstart_afl(_ql: Qiling):
ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point])


ql.hook_address(test_print1, MAIN)
ql.hook_address(test_print2, AUTHENTICATION_MAIN)
ql.hook_address(test_print3, CONTENT_LENGTH)
ql.hook_address(test_print4,address=0x40bc90)

ql.hook_address(callback=start_afl, address=AUTHENTICATION_MAIN)

try:
ql.run()
os._exit(0)
except:
ifenable_trace:
print("
Fuzzer Went Shit")
os._exit(0)


if__name__ == "__main__":
iflen(sys.argv) == 1:
raiseValueError("No input file provided.")
iflen(sys.argv) > 2andsys.argv[1] == "-t":
main(sys.argv[2], enable_trace=True)
else:
main(sys.argv[1])

運(yùn)行后發(fā)現(xiàn),afl++給到的變異數(shù)據(jù)確實(shí)傳入了進(jìn)去。

但是fuzz了一會(huì)兒發(fā)現(xiàn)沒crash,原來是read(fd=0x0,buf=0x7ff3c940,length=0x64),這里讀取的length還是100,也就是說afl++不管變異多少數(shù)據(jù)都只讀取100字節(jié),這說明我們的hook有問題。

459a46ae-27af-11ee-962d-dac502259ad0.png

打開QL_VERBOSE.DUMP模式,查看read時(shí)寄存器變量的值,確實(shí)hook沒生效。那么我們直接在其調(diào)用read函數(shù)時(shí)hook,使其寄存器變成我們變異數(shù)據(jù)的長(zhǎng)度就可以了。

45ece2a6-27af-11ee-962d-dac502259ad0.png462e8a08-27af-11ee-962d-dac502259ad0.png

重新改正腳本

importctypes, os, pickle, socket, sys, threading
sys.path.append("../../../")
fromqiling import*
fromqiling.const importQL_VERBOSE
fromqiling.extensions importpipe
fromqiling.extensions.afl importql_afl_fuzz


MAIN = 0x402770
AUTHENTICATION_MAIN = 0x40afcc
CONTENT_LENGTH = 0x40b48c
CONTENT_SIZE = 0x40b4a8
size = 1000

deftest_print1(ql: Qiling)->None:
print("Hit at main func")

deftest_print2(ql: Qiling)->None:
print("Hit at authentication func")

deftest_print3(ql: Qiling):
print("address:",hex(ql.arch.regs.s0))

deftest_print4(ql: Qiling):
print("Hit at exit func")

deftest_size(ql: Qiling):
globalsize
ql.arch.regs.s0 = size
ql.arch.regs.a1 = size
print("Hit at test_size func")

defmain(input_file, enable_trace=False):
globalsize
env_vars = {
"REQUEST_METHOD": "POST",
"REQUEST_URI": "/authentication.cgi",
"CONTENT_TYPE": "application/x-www-form-urlencoded",
"REMOTE_ADDR": "127.0.0.1",
"CONTENT_LENGTH": "100"
}
ql = Qiling(["rootfs/htdocs/web/authentication.cgi"], "rootfs",env=env_vars,verbose=QL_VERBOSE.DEBUG)

ql.os.stdin = pipe.SimpleInStream(0)
ifnotenable_trace:
ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno())
ql.os.stderr = pipe.NullOutStream(sys.stderr.fileno())

defplace_input_callback(ql: Qiling, input: bytes, _: int):
globalsize
content = b"id=1&password="+input
size = len(content)
ql.os.stdin.write(content)

defstart_afl(_ql: Qiling):
ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point])


ql.hook_address(test_print1, MAIN)
ql.hook_address(test_print2, AUTHENTICATION_MAIN)
ql.hook_address(test_print3, CONTENT_LENGTH)
ql.hook_address(test_print4,address=0x40bc90)
ql.hook_address(callback=start_afl, address=AUTHENTICATION_MAIN)
ql.hook_address(test_size,CONTENT_SIZE)

try:
ql.run()
os._exit(0)
except:
ifenable_trace:
print("
Fuzzer Went Shit")
os._exit(0)

if__name__ == "__main__":
iflen(sys.argv) == 1:
raiseValueError("No input file provided.")
iflen(sys.argv) > 2andsys.argv[1] == "-t":
main(sys.argv[2], enable_trace=True)
else:
main(sys.argv[1])

運(yùn)行后,3分鐘左右fuzz出crash。

467426a8-27af-11ee-962d-dac502259ad0.png46a4d50a-27af-11ee-962d-dac502259ad0.png

綜上,我們以實(shí)例的方式分析并fuzz了dir645路由器的倆個(gè)棧溢出漏洞,可能很多人覺得在fuzz時(shí)已經(jīng)知道了漏洞點(diǎn)和執(zhí)行流程,使用qiling進(jìn)行fuzz有點(diǎn)多余。但是對(duì)于我們沒有實(shí)體設(shè)備或者qemu不能完全仿真時(shí),即使我們知道了漏洞點(diǎn),我們也沒法去簡(jiǎn)單測(cè)試或驗(yàn)證,那么這時(shí)qiling框架就是一個(gè)比較好的選擇。這個(gè)小節(jié)中qiling 的fuzz思路像是在驗(yàn)證漏洞而且比較基礎(chǔ),而在真正fuzz漏洞時(shí),也許我們可以hook危險(xiǎn)函數(shù)并進(jìn)行fuzz,又或者其他思路,這些就靠大家的思維拓展了。

總結(jié)

在這小節(jié)中,我們使用qiling框架分析并測(cè)試了tenda ac15、dir 815以及dir 645實(shí)例設(shè)備的棧溢出漏洞,掌握了在分析fuzz時(shí)的基礎(chǔ)思路。熟練掌握qiling框架的使用,對(duì)于后續(xù)我們的漏洞測(cè)試方面還是有很多的幫助。






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5343

    瀏覽量

    120377
  • 仿真器
    +關(guān)注

    關(guān)注

    14

    文章

    1018

    瀏覽量

    83746
  • 路由器
    +關(guān)注

    關(guān)注

    22

    文章

    3732

    瀏覽量

    113788
  • 觸發(fā)器
    +關(guān)注

    關(guān)注

    14

    文章

    2000

    瀏覽量

    61158
  • python
    +關(guān)注

    關(guān)注

    56

    文章

    4797

    瀏覽量

    84690

原文標(biāo)題:Qiling Fuzz實(shí)例分析

文章出處:【微信號(hào):蛇矛實(shí)驗(yàn)室,微信公眾號(hào):蛇矛實(shí)驗(yàn)室】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    基于Big Muff類的fuzz

    描述這是基于 Big Muff fuzz 類的 fuzz。Morbid Fur 移除了 Big Muff 的音調(diào)控制,并調(diào)整晶體管和二極管以獲得響亮而原始的音調(diào)。
    發(fā)表于 07-06 07:16

    ZVEX Masotron Fuzz的資料分享

    描述ZVEX Masotron Fuzz
    發(fā)表于 07-12 07:22

    Skreddy Fuzz Driver資料分享

    描述Skreddy Fuzz Driver
    發(fā)表于 08-11 06:00

    基本音頻Zippy Fuzz資料分享

    描述基本音頻Zippy Fuzz早期的 fuzz box 旨在模仿薩克斯管的聲音。Zippy 將允許您以非常蘆葦?shù)慕q毛音調(diào)引導(dǎo)您內(nèi)心的 Coltrane。薩克斯和性感。在較低的設(shè)置下,一個(gè)美妙的音樂
    發(fā)表于 08-12 07:47

    HUAWEI DevEco Testing注入攻擊測(cè)試:以攻為守,守護(hù)OpenHarmony終端安全

    )。連接設(shè)備,創(chuàng)建任務(wù)并執(zhí)行。查看異常日志。根據(jù)異常分析是否存在漏洞。修復(fù)完漏洞后,重新測(cè)試驗(yàn)證。測(cè)試小貼士:根據(jù)Fuzz
    發(fā)表于 09-15 10:31

    完整記錄整個(gè)fuzz的過程,加深對(duì)web sql注入fuzz的理解

    因此可以作為fuzz的判斷(當(dāng)然有些waf是靜默waf,就是照樣接收你的數(shù)據(jù)但自己做了處理,返回正常頁(yè)面,這種fuzz的判斷有時(shí)候就需要設(shè)計(jì)下你的payload,這種在以后的文章繼續(xù)討論)
    的頭像 發(fā)表于 12-31 11:54 ?4017次閱讀

    制定IOT設(shè)備標(biāo)準(zhǔn):最新實(shí)例

    ? 精確農(nóng)業(yè)、水資源利用監(jiān)測(cè)、遠(yuǎn)程醫(yī)療——這些只是由于物聯(lián)網(wǎng)(IoT設(shè)備使用范圍的擴(kuò)大而帶來的一些發(fā)展。毫無(wú)疑問,物聯(lián)網(wǎng)設(shè)備可以改善我們的生活。但是,與此同時(shí),物聯(lián)網(wǎng)設(shè)備的使用不斷增
    的頭像 發(fā)表于 12-29 17:55 ?2499次閱讀

    圍繞CMOS反相器構(gòu)建的Big Muff fuzz

    電子發(fā)燒友網(wǎng)站提供《圍繞CMOS反相器構(gòu)建的Big Muff fuzz.zip》資料免費(fèi)下載
    發(fā)表于 07-06 11:16 ?2次下載
    圍繞CMOS反相器構(gòu)建的Big Muff <b class='flag-5'>fuzz</b>

    基于Big Muff fuzz類的fuzz

    電子發(fā)燒友網(wǎng)站提供《基于Big Muff fuzz類的fuzz.zip》資料免費(fèi)下載
    發(fā)表于 07-07 09:33 ?0次下載
    基于Big Muff <b class='flag-5'>fuzz</b>類的<b class='flag-5'>fuzz</b>

    Greeny(Fuzz Face OpAmp仿真器)開源

    電子發(fā)燒友網(wǎng)站提供《Greeny(Fuzz Face OpAmp仿真器)開源.zip》資料免費(fèi)下載
    發(fā)表于 07-27 15:36 ?4次下載
    Greeny(<b class='flag-5'>Fuzz</b> Face OpAmp仿真器)開源

    基本音頻Zippy Fuzz開源

    電子發(fā)燒友網(wǎng)站提供《基本音頻Zippy Fuzz開源.zip》資料免費(fèi)下載
    發(fā)表于 07-27 14:37 ?1次下載
    基本音頻Zippy <b class='flag-5'>Fuzz</b>開源

    重現(xiàn)傳奇的Dallas Arbiter Fuzz聲音的踏板

    電子發(fā)燒友網(wǎng)站提供《重現(xiàn)傳奇的Dallas Arbiter Fuzz聲音的踏板.zip》資料免費(fèi)下載
    發(fā)表于 07-27 11:20 ?1次下載
    重現(xiàn)傳奇的Dallas Arbiter <b class='flag-5'>Fuzz</b>聲音的踏板

    ZVEX Masotron Fuzz開源分享

    電子發(fā)燒友網(wǎng)站提供《ZVEX Masotron Fuzz開源分享.zip》資料免費(fèi)下載
    發(fā)表于 08-22 16:48 ?1次下載
    ZVEX Masotron <b class='flag-5'>Fuzz</b>開源分享

    速通IoT設(shè)備電源測(cè)量難點(diǎn)

    IoT設(shè)備的蓬勃發(fā)展促進(jìn)了越來越多適用于各種場(chǎng)景的IoT設(shè)備生產(chǎn),帶動(dòng)了更多廠商加入到研發(fā)與生產(chǎn)IoT設(shè)
    的頭像 發(fā)表于 04-08 09:57 ?729次閱讀

    qiling框架和AFLplusplus安裝

    供了易于使用的API和插件系統(tǒng),方便使用者進(jìn)行二進(jìn)制分析和漏洞挖掘等工作。其創(chuàng)始人是一名IoT Hacker,創(chuàng)建qiling的初衷便是解決在研究IoT時(shí)遇到的種種問題,這也是為什么上
    的頭像 發(fā)表于 06-17 16:12 ?1983次閱讀
    <b class='flag-5'>qiling</b>框架和AFLplusplus安裝