作者:Yimi Hu & Light @胖猴實驗室
原文鏈接:https://mp.weixin.qq.com/s/k1ouK1Gyxpped0ZK4H4h7g
1、前言
2021年7月中旬,天府杯正式公布今年的比賽題目,筆者也有幸參與了今年的天府杯比賽。按照PwnMonkey & DC0086公眾號的技術方向,我們打算來聊一聊其中關于IoT設備的項目。本次天府杯一共有2個IoT設備作為攻擊目標,其一是華碩路由器;其二是群暉NAS。
在這兩個設備中,群暉NAS咱們就先放一放,因為天府杯上這個設備并沒有被打下來;而華碩路由器可以拿來好好說一說。在華碩路由器被宣布為天府杯比賽項目之后,華碩做了2次更新,每次更新都會導致一群小伙伴嗚呼哀哉,但是最終還是沒有攔住優秀的攻擊者。那么,在后文中,我們就一起來看看華碩路由器這個設備以及華碩官方的兩次圍剿。
PS:由于太久沒有更新文章,排版技能生疏,導致昨天的文章格式稀爛,所以今天調整之后重新發了一遍,抱歉給各位同學帶來了不好的體驗。
2、設備摘要
相比于我們此前討論過的各個設備,華碩路由器不用花太多時間在固件獲取上,因為設備自帶了telnetd,只需要在web管理頁面設置一下,就可以直接使用telnet登陸設備,將需要分析的文件拿回本地。我們選用的路由器型號為RT_AX56U_V2,固件版本為3.0.0.4.386.42844,后文中也是以此型號和版本展開敘述。
在登陸設備之后,我們可以簡單瀏覽一下端口監聽情況,用以幫助我們選擇目標進程,將端口監聽情況做一點點整理和篩選,我們發現有以下幾個進程可能會出現問題:
上圖被篩選出的5個進程分別是envrams、wanduck、cfg_server、httpd和infosvr,其他進程或者是第三方開源程序或者是僅監聽了127.0.0.1端口。第三方開源程序維護者眾多,在其中發現漏洞可能并沒有那么容易;而僅監聽本地端口的程序即便有漏洞也無法直接利用,所以把優先級放低一些。事實上,本文要提到的3個漏洞也的確出自這幾個進程。
此外,由于華碩路由器的固件是遵守GPL協議的,所以我們可以在網上找到一些相關的代碼,雖然我們沒找到最新版的代碼,但是以往代碼同樣很具備參考價值,其中梅林固件的代碼很具備參考價值,鏈接如下https://github.com/RMerl/asuswrt-merlin.ng。在我們逆向過程不太順利時,可以參考一下這里的代碼。
3、第一次圍剿
華碩官方在8月26日,更新了一個版本,除了修復大量已有CVE編號的漏洞之外,還修復了一個envrams暴露的問題,如下圖:
上圖中,紅框部分即是導致大家嗚呼哀哉的更新內容,我們來深入看一下。
如果用IDA分析過httpd或者cfg_server等程序,那么一定會發現華碩路由器的經常會調用nvram_開頭的多個函數,如下圖:
這些以nvram_開頭的函數,絕大部分是和設備的各種配置相關,其中set是保存或更新配置、get是獲取配置。如果一直深入挖掘nvram_系列的函數,會發現最終會執行到和內核通信的socket,猜測華碩設備應該是通過這種方法提高了配置訪問速度,并解決了同一個配置可能存在多個地方以及更新不同步的問題。
而我們將要討論的envrams就是提供了一個獲取和更新配置的接口。通過簡單的逆向,就可以看到envrams監聽了tcp5152端口,支持show、get、set、commit、rall等指令。原則上,envrams僅能獲取和更新/mnt/nvram/nvram.nvm中的配置信息,見下圖:
該文件中的部分配置信息如下圖所示:
看起來,并沒有什么值得一提的配置。實際上,我們可以在nvram.nvm中寫入其他進程使用的配置信息,這樣一來,設備在重啟之后,nvram.nvm中的配置信息就會被加載到內核中,由于nvram.nvm的加載時機比較晚,所以會覆蓋更新已有配置。舉例來說,我在envrams中將x_Setting的值設置為0,如下圖:
那么設備重啟之后,x_Setting的配置就被更新為0了。這意味著,設備誤認為自己剛剛被恢復出廠設置,打開web管理端口不需要輸入用戶名和密碼即可直接登陸。由此,造成了非常嚴重的影響。
華碩官方對這個漏洞的修復方案極其簡單粗暴,給iptables增加了一條規則限制了5152端口的訪問,如下圖:
4、第二次圍剿
華碩官方在10月7日,又更新了一個版本,其中修復了一個信息泄露問題,如下圖:
上圖中,紅框部分即是導致大家嗚呼哀哉的更新內容,我們來深入看一下。
此處信息泄露出現在httpd進程中,使用IDA載入httpd之后,可以在程序中找到路由表,如下圖所示:
上表中,每六行為一個結構體,以高亮的六行為例:其中第一行為訪問的url;最后一行表示是否需要登陸,0代表不需要;倒數第二行為處理函數,其中do_ej是一個小型的頁面解析器。
上圖中的asp和htm的頁面都是可以在未登陸狀態下用get請求直接訪問的。但逆向看代碼之后,便可知do_ej在解析過程中也能處理post請求,而且能接收一個名為current_lang的參數。顧名思義,該參數可以用于控制頁面的顯示語言。可以在IDA中找到關于current_lang參數的處理邏輯,如下圖所示:
可以看到snprintf的最大長度為0x10字節,如果我們輸入的長度超過0x10,那么原本的“%s.dict”就會被頂出去。例如,我們輸入“/////etc/shadow”作為current_lang的值,如下圖所示:
那么字符串在被格式化以后,將是下圖中的樣子:
在上圖中,可以看到原本的“%s.dict”已經消失了。
如果繼續執行該程序,那么/etc/shadow的內容將會通過http直接回顯出來,如下圖所示:
華碩官方對這個漏洞的修復方案是限制a1參數的長度和內容,如下圖所示:
5、最后一戰
雖然華碩兩次更新修復了很多問題,但最終還是沒能阻止各位攻擊者。最終的問題出現在cfg_server中,當多個華碩路由器通過AiMesh組網之后,會出現cfg_client和cfg_server之間的通信。類似httpd進程,可以在該程序中也找到多個路由表,其中一個是tcp7788端口的路由表,如下圖所示:
通過IDA逆向分析之后,可以推斷出tcp7788端口的通信格式為TLV(Type-Length-Value)報文格式,其中,T即路由表中的編號;V是aes加密數據內容及其crc32值。看到這里,就能順其自然地想到如果L為不合理的值會怎樣,其實漏洞就是出現在這里了。
我們可以按照下圖所示的方法構造惡意的發送數據:
上圖中,我們選擇第0x28號請求,將長度設置為0xFFFFFFF4,crc32值設置為0,由此繞過程序的crc32校驗,見下圖中R0和R3寄存器:
然后,在AES解密過程中,會觸發整數溢出,導致malloc錯誤的內存大小,如下圖所示:
可以看到,上圖中R11值為0xFFFFFFF4,而malloc長度僅僅為0x4。
接下來,由于聲明的內存長度小于實際長度,就會造成堆溢出,導致AES解密數據寫入后續溢出的堆內存中。接下來只要考慮怎么利用這個溢出寫入,并不麻煩,如果后續內存中有個函數指針或者其他什么有用的數據可以被覆蓋,我們就有了可乘之機。事實上,只要合理布局內存,就可以讓后面出現一個可以利用的函數指針,而cfg_server并沒有開啟ASLR,所以利用過程并不復雜,我們可以這樣操作:
各位,十分抱歉,這里容筆者先賣個官子,待固件完成更新修復之后,我們可以再回過頭來詳細討論。不過,話說回來,都已經提示到這里了,相信各位讀者只要自己分析一下也能解決這個漏洞利用
6、小結
本篇就先寫到這里,希望耐心讀到這里的各位有所收獲。除了今年以外,華碩路由器還是去年天府杯的項目之一,其中漏洞也很有意思;此外,在去年8月極光無限還報了個華碩路由器未授權棧溢出漏洞,感興趣的話可以去看看相關的信息。最后,很感謝對本文提供幫助的各位,有@Suzhang、@halo以及@tkmk等人,多謝。還有,本文中有很多結論和推測為我們個人的推測,如果不當指出,可以聯系我們做更正。
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1751/
暫無評論