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è)試。
根據(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
使用netstat -pantl查看監(jiān)聽端口,當(dāng)發(fā)現(xiàn)python3程序正在監(jiān)聽8080端口時(shí),說明tenda ac仿真成功。
此時(shí)我們運(yùn)行./addressNet_overflow.sh生成snapshot.bin文件。
運(yùn)行./fuzz_tendaac15_httpd.sh進(jìn)行fuzz,經(jīng)過10分鐘左右出現(xiàn)了crash。
產(chǎn)生的crash文件內(nèi)容如下
這樣我們就完成對(duì)實(shí)例中tenda ac15的fuzz復(fù)現(xiàn)。官方提供demo的saver和fuzz腳本如下,現(xiàn)在我們對(duì)其進(jìn)行簡(jiǎn)單分析并學(xué)習(xí)。
通過上一小節(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)行了寫入。
那么我們要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é)束地址。
在分析的過程中,我們可以打開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)行寫入。
分析完上面的流程后,我們對(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ā)的棧溢出
fuzz的第一步就是摸清楚程序的執(zhí)行流程,我們先簡(jiǎn)單編寫仿真程序的腳本,隨后將其改為fuzz腳本。該仿真腳本定義了倆個(gè)hook函數(shù),當(dāng)程序執(zhí)行執(zhí)行地址處后會(huì)執(zhí)行該hook函數(shù),并打印出"Hit at xxx func"。
執(zhí)行仿真腳本,發(fā)現(xiàn)我們定義的倆個(gè)hook都被觸發(fā),說明我們簡(jiǎn)單分析后的執(zhí)行流程確實(shí)沒錯(cuò),并且調(diào)試信息后續(xù)還打印出了一下回應(yīng)信息。
我們繼續(xù)在ida中查找定位該信息,發(fā)現(xiàn)是LABEL_25中的處理,根據(jù)交叉引用,我們追蹤該信息產(chǎn)生的原因是env中沒有REQUEST_METHOD
那么我們?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ā)保存快照的功能。
最終編寫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í)字符串。
接下來我們編寫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。
最終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,還是比較快的。
authentication.cgi棧溢出
和上面的分析同理,我們首先跟一下程序的執(zhí)行流程,authentication.cgi的處理函數(shù)為authenticationcgi_main函數(shù)。
進(jìn)入到authenticationcgi_main函數(shù)后,我們發(fā)現(xiàn)和上面的hedwig類似,也是同樣獲取env中的變量進(jìn)行處理。
那么我們將前面的腳本進(jìn)行修改,這里直接將HEDWIGCGI_MAIN改為0x40afcc。
運(yùn)行后發(fā)現(xiàn)執(zhí)行觸發(fā)了倆個(gè)hook函數(shù),說明確實(shí)執(zhí)行到了authenticationcgi_main函數(shù)中。
authentication.cgi觸發(fā)棧溢出的執(zhí)行流程為REQUEST METHOD方法為POST,并且需要設(shè)置"CONTENT_TYPE"和"CONTENT_LENGTH"環(huán)境變量。
那么我們?cè)趀nv變量中設(shè)置如下參數(shù)并傳入qiling實(shí)例。
注:CONTENT_LENGTH中的999在程序執(zhí)行時(shí)還沒有溢出,v73定義的1024字節(jié)。
運(yùn)行后發(fā)現(xiàn)已經(jīng)執(zhí)行我們想要其執(zhí)行的流程了,并且需要我們輸入一些信息才可執(zhí)行后面的流程。
input中含有的內(nèi)容如下,需要包含"id=xxx&password=xxx"
再次執(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
根據(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有問題。
打開QL_VERBOSE.DUMP模式,查看read時(shí)寄存器變量的值,確實(shí)hook沒生效。那么我們直接在其調(diào)用read函數(shù)時(shí)hook,使其寄存器變成我們變異數(shù)據(jù)的長(zhǎng)度就可以了。
重新改正腳本
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。
綜上,我們以實(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è)試方面還是有很多的幫助。
審核編輯:劉清
-
寄存器
+關(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)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論