您好,登錄后才能下訂單哦!
能修復自己的RouterOS漏洞指的是什么,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
2018年10月7日,來自全球知名高科技網絡安全公司Tenable的安全研究人員Jacob Baines針對CVE-2018-14847[2]發布了一段新的概念驗證(PoC)代碼[1],實現了在受漏洞影響的MikroTik路由器上的遠程代碼執行。我們第一時間對PoC進行了研究,目前我們對漏洞利用的部分改進已經合入了Tenable的Github倉庫[7]。本文將對CVE-2018-14847目錄穿越漏洞成因進行分析,同時闡述我們的一些發現,如何通過受此漏洞影響的Winbox指令進行任意文件上傳,從而實現一些更有趣的利用方式。我們能夠利用CVE-2018-14847在RouterOS 6.42中觸發后門shell,或在其他漏洞的配合下,通過在LD_LIBRARY_PATH中注入動態鏈接庫的方法,對存在漏洞的可執行文件進行熱補丁修復。我們還將在文中介紹一種“修改”只讀文件系統修復漏洞的方法。
MikroTik RouterOS是一個基于Linux開發的網絡設備操作系統,兼容x86、ARM、MIPS等多種CPU架構,因此RouterOS也可以安裝在PC上將其作為軟路由,提供防火墻、VPN、無線網絡等多種功能與服務。
RouterOS提供了多種途徑對其進行管理與配置,包括SSH、Telnet、Web界面(Webfig)與客戶端軟件(Winbox)等。本文討論的漏洞,位于RouterOS與客戶端軟件Winbox通信過程中所使用的Winbox私有協議中。
RouterOS官網提供了針對多種CPU架構的ISO安裝鏡像,我們下載6.41.3版本的ISO鏡像并安裝一個虛擬機。
在虛擬機中配置好IP等基本設置后,我們對各個配置項進行探索,可以總結出一些基本認知。
1. RouterOS可以通過Web(80端口)、SSH(22端口)、Winbox(8291端口)、Telnet(23端口)進行遠程訪問,使用相同的用戶名與密碼進行身份驗證。
2. 命令行方式訪問(SSH、Telnet)會登錄到一個廠商定制的shell界面,只能運行廠商實現的管理功能,無法運行Linux命令。
3. 通過Webfig途徑登錄后,與服務器的交互全部通過一個名為master-min-xxxxx.js的腳本進行加密傳輸。這個加密協議我們下文將稱之為JSProxy。
4. Webfig與Winbox途徑提供的配置選項幾乎完全相同,根據Tenable與Talos等前人的研究,二者在傳輸層的編碼方式上有些許差異,但在應用層的指令編號、指令參數等保持一致。
在上節我們提到,使用GUI管理RouterOS的兩個方式Webfig網頁端與Winbox客戶端,分別采用JSProxy與Winbox協議與RouterOS進行通信,下面我們將分別分析兩種協議的通信格式。
在JSProxy通信過程中,瀏覽器與服務器通信采用變種的MS-CHAP-2方式生成會話密鑰,并用于全程的數據加解密,在此我們不作深入講解,通過JSProxy我們能夠略窺RouterOS控制所需要的指令格式與指令映射關系。
對JSProxy的payload進行解密后,我們得到一條條JSON編碼的數據。基本格式如下:
JSON數據中的每個鍵值對包含了三種信息:字段類型、字段名、字段值。JSON鍵的第一個字母(上圖藍色部分)代表字段類型,包括字符串、整型、布爾值、數組等。JSON鍵的剩下6個十六進制位(上圖紅色部分)代表字段名,通常是一個編號,表示數據值的含義,我們下文稱之為key ID。JSON值(上圖黃色部分)就是這個字段的數據值。
到這里我們可以了解到,RouterOS管理頁面的通信方式是通過鍵值對的請求與回復實現的,鍵值對的編碼方式在JSProxy與Winbox中不盡相同,但數據含義是相同的。我們對 master-min-xxxxx.js進行分析,一個好消息是,我們可以在其中找到所有keyID。
而Winbox協議的二進制編碼格式,我們可以從Winbox客戶端中分析得到。我們尋找到了一個關鍵函數,功能是將Winbox消息轉換成字符串進行日志輸出,四舍五入等于開源了。
Winbox協議二進制格式的大致格式分為6字節的消息頭,與依次緊密排列的鍵值對,大于255字節的消息會插入兩字節的長度數據作為消息分片。
其中鍵值都是以小端序傳輸,同樣采取類似“數據類型-鍵-值”的格式。
借助Cisco Talos實驗室開源的Winbox協議Wireshark解析插件[9]。我們能非常直觀的看到數據中各個字段與原始數據的對應關系。
當然這個插件還有一些不足之處,無法解析所有類型的數據包,但對于我們,能夠對數據包進行過濾和簡單查看一下對應關系就足夠了。
CVE-2018-14847漏洞發生在漏洞上傳的位置。我們如何知道文件上傳指令發給誰,文件由誰接收,保存到哪里呢?我們需要先定位哪個程序在RouterOS上負責接收用戶上傳的文件。
從Winbox消息中,我們注意到不同指令會發送給不同的目的組件,從JSProxy中我們能夠得知這個目的地位于SYS_TO字段對應的字段中。這個字段是兩個int32組成的數組,第一個數字對應了系統中的一個程序,第二個數字對應了這個程序的第幾個功能。Tenable對系統中保存了這個對應關系的數據文件/nova/etc/loader/system.x3進行了分析,并制作了一個名為parse_x3的小工具,我們可以在Tenable的Github倉庫中的parse_x3目錄找到。
根據這個對應關系,結合抓包我們能夠得知,文件上傳請求的SYS_TO值為{0x02,0x02},對應的二進制文件位于/nova/bin/mproxy。
我們從RouterOS的ISO文件中提取出對應的二進制文件。文件位于mikrotik-6.41.3.iso\system-6.41.3.npk\nova\bin\mproxy,直接用7-zip打開iso和里面的npk,拖出來即可(很多地方其實用不著binwalk)。
在對mproxy進行分析的過程中,Tenable通過功能(handler)實現對應的基類nv::Handler找到了每個程序里面的所有功能的所有編號,并編寫了一個Binary Ninja腳本尋找程序中的所有handler,從而快速定位功能對應的函數,這個小工具位于Github倉庫中的find_handlers目錄中,有興趣的同學可以嘗試一下。
我們嘗試找一個簡單點的方法,從另外一個角度定位對應的函數。我們在Winbox客戶端中正常上傳一個文件,并尋找上傳的文件所在的路徑。當然,假如現在是黑盒測試的話,我們可以用其他的方法獲得文件系統的訪問權,例如利用其他漏洞進行提權、直接修改文件系統植入shell等等。我注意到文件系統根目錄下有很多的符號鏈接,其中有一些鏈接到可寫目錄中,所以我在這里用find -follow跟隨符號鏈接確保我們能夠定位到文件的所有可能的路徑。
通過這種方法獲得的路徑,與mproxy程序中出現的字符串進行交叉比對,我們可以得到結論:mproxy程序中,某個負責文件上傳的函數能夠上傳文件至/var/pckg目錄中。
再通過這個字符串的交叉引用,我們就能夠定位到我們所需的關鍵函數,我們命名為ked_handler。
對這個函數進行分析,我們可以得出ked_handler函數大致有7個功能,以傳入的第5個參數進行選擇,有以下7個取值(以IDA偽代碼中出現順序排序):
l 功能1:在/var/pckg目錄下創建文件,返回一個用于寫入數據的session
l 功能3:打開/var/pckg目錄下的一個文件,返回一個用于讀取數據的session
l 功能7:打開/home/web/webcfg目錄下的一個文件,返回一個用于讀取數據的session
l 功能2:向一個打開文件的session寫入數據
l 功能4:從一個打開文件的session讀取數據
l 功能5:中止一個session并刪除先前寫入的文件
l 功能6:在/var/pckg目錄下新建一個目錄
通過對抓包數據進行分析,我們發現官方客戶端在讀取并下載文件時調用的是3號功能,而Tenable的poc調用的是7號功能。
與這兩個功能相關的部分邏輯如下。
其中,tokenize函數對傳入的字符串按 / 字符進行切分,返回一個字符串數組。ked_check_path函數采用類似狀態機的方式有限制的允許“..”字符串,不允許穿越到父目錄中。但函數中沒有對“.”(即,當前目錄)進行驗證,所以我們可以構造類似“/./../”的payload,讓函數誤以為我們進入1級子目錄后返回了當前目錄,但實際我們進入了父目錄,成功實現目錄穿越。ked_check_path這個函數可以說是搬起石頭砸了自己的腳。
通過偽代碼我們能看到這三個功能都沒有對輸入參數進行正確過濾,應該存在相同的目錄穿越漏洞。這兩個命令理論上都能利用來進行任意寫入,實際情況呢?
關鍵點在權限上,對ked_handler進行調用回溯,我們能夠定位到mproxy的main函數中,向eventloop注冊handler的代碼片段。在添加handler前,程序調用了set_policy對7個命令進行了某種設置,據Tenable的深入研究,這幾條函數調用與handler中相關功能的調用權限相關。第三個參數為0的時候,代表調用此功能無需登錄。由以上代碼可知,功能命令4、5、7的調用無須登錄。
到這里,我們已經實現了對系統根目錄的任意文件讀寫。
下一個問題,有了權限,我們能做什么呢?當然是Getshell了!我們前面提到,即使我們有管理員賬號密碼,ssh登錄進去依然是一個功能受限的shell,不能執行Linux指令。Tenable在報告中提出了一種利用廠商開發者后門進行提權的方法。這個后門與上文提到的目錄穿越漏洞,在RouterOS 6.42.1與6.40.8版本一并得到修復。
這個漏洞存在于ssh和telnet登錄時運行的/nova/bin/login中。命令行登陸時,程序先正常向用戶請求輸入用戶名和密碼,然后根據兩個判斷條件:用戶名是否等于devel、hasOptionPackage返回是否為非0值,如果都符合則進入下一個代碼塊。
其中,hasOptionPackage函數位于/lib/libumsg.so中,它的取值依據為/pckg/option文件是否存在。
確認用戶名與OptionPackage后,程序將用戶名重置為admin,并設置一個標志位,指示后門的激活狀態。
處理一部分其他邏輯之后,程序再次檢查這個標志位,如果后門激活,則將shell運行的實際命令設置為bash。根據PATH環境變量的設置,最后命中并執行文件系統中名為/bin/bash(實際是一個busybox)的交互式命令行。
這個后門的觸發邏輯在RouterOS的不同版本中略有不同。根據Tenable的研究,在RouterOS 6.40.9以下版本中,依據的文件是/flash/nova/etc/devel-login,在6.41.1以下版本中,判斷的是/pckg/option,在6.42以上版本中,對/pckg/option文件類型做了額外的驗證,但依然能夠通過修改文件系統的方式進行觸發。
根據上面的兩個漏洞的細節,我們已經可以總結出整個漏洞利用的過程:
1. 構造payload,調用功能7,打開/flash/rw/store/user.dat文件,獲得session id。
2. 調用功能4,用這個session id讀取文件內容。
3. 用其他工具解密管理員賬戶的明文密碼。
4. 調用{0x0d,0x04}號handler進行Winbox管理員登錄(模擬Winbox客戶端登錄,協議細節不再贅述),獲得管理員權限session id。
5. 調用功能1,用管理員session在/pckg/option創建空文件。
6. 用管理員明文密碼登錄ssh/telnet,獲得root shell。
整個的利用過程已經被Tenable總結出了一個漏洞利用程序bytheway,在他們的Github中可以找到。
我們在這里使用的是基于Tenable的bytheway進行修改后的exploit。
交互過程如下:
根據RouterOS版本不同,觸發后門需要的文件也不同,因此exploit里面將兩個文件都創建了,盡量兼容更多的版本。
漏洞復現了就結束了?NO。我們在公網上部署了多臺測試環境對RouterOS漏洞的利用行為進行捕獲,從攻和守兩個角度都有一些新的發現。我們接下來將介紹一個幫我們“修復”漏洞的好心攻擊者與我們對其修復方法的復現,還有我們發現的另一種漏洞利用方法,同時介紹如何利用這種方法反過來修復這個漏洞。
挖礦、蠕蟲、僵尸網絡等攻擊行為不再多說,都是常規操作。在其中一個設備上,我們發現了一個好心的攻擊者幫助我們“修復”了后門shell。具體表現是,“修復”后的設備能夠通過ssh登錄管理界面,也能通過exp觸發后門,但卻無法登錄devel用戶,輸入正確的密碼后卻被斷開連接。估計是某個病毒的作者想要防止其他攻擊者利用這個漏洞,所以好心幫我們“修復”了。可以說是滑天下之大稽。
通過對設備文件系統的分析和虛擬機上的復現,我們猜測這個設備上的/bin/bash文件被“刪掉”了。但問題是,PATH變量是硬編碼的不可能修改,而/bin目錄所在的根文件系統是只讀掛載的squashfs,所以刪除系統文件是怎么實現的呢?
前面我提到了特殊意義的“刪掉”,是因為我們重新分析線上環境的文件系統時,發現/bin/bash并沒有被刪,所以下面的這種漏洞“修復”方式僅是我們能夠復現的一種猜想。
首先我們想知道,在系統目錄中有哪些是可寫入的。
我們選擇/ram,并用隨便一種方式上傳一個完整版busybox進去(因為RouterOS自帶的mount進行bindmount時會報錯)。隨后,在可寫目錄中新建bin文件夾并將/bin目錄中的內容復制進去,并用mount將新目錄掛載到/bin目錄之上,實現“覆蓋”的效果。由下圖可見,我們斷開連接后再次登錄,就會在登錄成功后馬上斷開,提示消息為Connection Closed而不是漏洞修復后提示的Permission denied。
用這種方式實現的修改,并沒有真實寫入文件系統,在重啟之后,后門依然可以訪問。病毒作者可以說是用心良苦哇。
這個思路同樣可以用于一些敏感的生產環境系統,很多嵌入式設備都采用squashfs或者其他用于Flash芯片的只讀文件系統,如果對可用性有較高的要求,不能接受重啟、系統升級帶來的服務中斷的話,可以用類似的目錄掛載方式對系統進行熱修復。
在對CVE-2018-14847漏洞進行分析的時候,我產生了一個疑問。既然功能1、3、7共享這個目錄穿越漏洞,那理論上我們可以在未授權的情況下向系統任意目錄寫入任意文件。也許我們不需要開發者后門,也可以實現遠程代碼執行。
我嘗試利用Tenable的協議庫winbox_message.hpp編寫一些poc,利用ked_handler中功能1提供的session寫入文件,在可寫的路徑上傳busybox。但服務器對上傳的功能2指令沒有任何響應。通過對Winbox客戶端上傳功能的分析,我發現Tenable的協議庫中對長度大于256字節的message處理有一些小bug。
下圖以一個文件上傳數據包內容為例,以全0數據方便我們觀察原始數據格式。方框部分就是Tenable協議庫遺漏的部分,我們在winbox_session.cpp中,在每個消息分片之前加入分片長度值與截斷標記,修復后的數據包就和Winbox客戶端發送的協議格式完全相同了。
進行修復以后,調用mproxy的功能2能夠正常上傳文件到指定位置,在修復之前,因為其他header的存在,最多只能上傳209字節的文件,更大的文件請求就會因為消息分片格式的問題被mproxy丟棄。這個patch我們也提交到了Github上。現在,我們打開了另一扇大門。
最開始我的設想,直接利用上傳功能覆蓋一個系統可執行文件,并觸發對應的功能。但后來發現有兩個難點。一是從未授權用戶的角度來看,能夠調用的程序就那么幾個,/nova/bin/login與mproxy、telnet和ssh服務器等,這些程序所在的掛載點都是只讀的,root用戶也無法覆蓋。二是通過功能2創建的文件默認權限都是644,即可讀可寫不可執行,即使傳上去了也會因為權限問題無法啟動。
不過對RouterOS有了更多的了解后,我有了一個設想。查看shell登錄以后的環境變量:
我們發現,LD_LIBRARY_PATH中包含了多個目錄,/lib在根文件系統下,是只讀的。/pckg是一個指向/ram/pckg的符號鏈接,/pckg/security/lib與/pckg/user-manager/lib只在安裝了對應的可選包才會出現,也都是只讀的。/rw是一個指向/flash/rw的符號鏈接,這個目錄是可寫的。雖然/rw/lib目錄在默認配置下不存在,但我們可以通過上文的目錄穿越漏洞調用ked_handler的功能6進行創建,從而使這個漏洞的利用成為可能。
LD_LIBRARY_PATH是一個危險的東西。利用這個環境變量,我們可以實現在任何程序運行前對程序的行為進行修改,甚至在程序運行時實現進程注入。子進程可以繼承父進程的環境變量,而系統中絕大多數應用都是loader進程的子進程(下圖PID 276)。
因此,將payload封裝為so庫,放置在LD_LIBRARY_PATH中的可寫路徑/rw/lib下,即可實現對接下來任意啟動的進程進行注入并實現命令執行——比如我們在命令行登錄時,就會啟動一個/nova/bin/login。
用這個思路,我們還可以在無法觸發后門的6.42版本中,使用老版本libumsg.so重新引入這個后門,對RouterOS“越獄”會有幫助。前面我們提到,
這個后門的觸發邏輯在RouterOS的不同版本中略有不同。根據Tenable的研究,在RouterOS 6.40.9以下版本中,依據的文件是/flash/nova/etc/devel-login,在6.41.1以下版本中,判斷的是/pckg/option,在6.42以上版本中,對/pckg/option文件類型做了額外的驗證,但依然能夠通過修改文件系統的方式進行觸發。
RouterOS 6.42+中,遠程觸發開發者后門幾乎是不可能的,攻擊者更不可能跑到別人家里去拆掉Flash芯片往里塞后門。意味著即使攻擊者拿下了用戶名密碼,但他也僅僅能訪問GUI中有限的控制選項,不能植入payload利用設備獲得更多的經濟利益。
我們前面分析過,與后門相關的控制邏輯,有一部分位于/lib/libumsg.so中,準確來講是nv::hasOptionPackage函數。既然我們已經能夠進行任意文件上傳,同時我們能夠控制LD_LIBRARY_PATH,那么我們簡單的將RouterOS 6.41.x中的libumsg.so復制出來,再在6.42.x的系統中利用目錄穿越漏洞調用ked_handler的功能6創建/rw/lib目錄并將libumsg.so上傳上去,因為LD_LIBRARY_PATH的函數加載優先級高于PE文件中定義的加載路徑[8],我們用這種方式即可實現后門觸發,在6.42.x系統中啟用ssh shell。
因為不想再寫代碼了,為了從另一個角度驗證這個思路的可行性,我們在RouterOS 6.41.x上設計了下面的實驗。
我們現在有一個后門,我們還控制了LD_LIBRARY_PATH下可寫的目錄/rw/lib,同時能夠創建這個目錄并向其中寫入文件。假如我現在的設備就是一個骨干路由,需要對漏洞進行緊急修復,我們現在來嘗試一下,在不更新、不重啟系統的情況下通過LD_LIBRARY_PATH預加載動態鏈接庫關掉這個后門。
首先,我們確認后門可以正常工作,并創建/rw/lib目錄。當然,我們也可以用漏洞來創建這個目錄,我只是懶得寫exp了(笑
接下來,我們從RouterOS 6.42的ISO中提取出libumsg.so,并利用CVE-2018-14847(或者用你能想到的其他方法)上傳到指定目錄中。我在這里同時上傳了一個busybox。
上傳成功后,kill掉所有名為login和sshd的進程。
這樣一來,當前所有通過控制臺、Telnet與ssh登錄的終端都會被關閉,再次連接就會啟動新進程,同時加載我們通過LD_LIBRARY_PATH植入的新版本libumsg.so,后門shell失效。
還記得我們在前面對開發者后門的分析嗎?如果libumsg.so中的后門函數hasOptionPackage返回true后,登錄session的用戶名會被重置為admin,從而控制臺中顯示的登錄成功、失敗的日志中的用戶名都會因此被修改。但后門修復之后,這一段程序邏輯不復存在,因此對后門的登錄嘗試也會在系統日志中顯示出來。
再結合我們前面提到的,用mount掛載魔改只讀文件系統的方式,我們還可以用新版本覆蓋根文件系統的/nova/bin/mproxy,將目錄穿越漏洞一并修復掉。
我們再開個腦洞,整個漏洞修復過程分為三步:創建目錄、上傳修補程序、重啟服務,這個過程完全可以自動化,一個腳本對全網存在漏洞的設備進行掃描修復。真正做出來肯定也會非常有趣吧。
看完上述內容,你們掌握能修復自己的RouterOS漏洞指的是什么的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。