上一篇文章分了一下ARM系統的路由器漏洞,本次打算嘗試一下MIPS系統,於是選了最近DLink路由器的漏洞CVE-2019-17621作爲目標。同樣一路走來各種踩坑不斷,“紙上得來終覺淺,絕知此事要躬行”,對整個過程做一下梳理。

1、環境搭建

運行環境安裝配置之前須瞭解你所使用的Linux系統的版本以及Qemu的版本,因爲這直接影響着你後續選擇安裝各種依賴包、mips qemu鏡像等的版本,各種版本都對應上,最終系統才能正確運行。本次漏洞分析的基礎環境爲前期的Ubuntu18.04虛擬機和基於qemu-4.0.0源碼編譯安裝的Qemu運行環境:

從站點 https://people.debian.org/~aurel32/qemu/mips/ 下載debianmips qemu鏡像,由於虛擬機是Ubuntu linux,下載debian_squeeze_mips_standard.qcow2和vmlinux-2.6.32-5-4kc-malta即可:

MIPS系統網絡配置

使用QEMU 模擬運行MIPS系統,需要將ubuntu虛擬機設置成橋接,這樣以來ubuntu系統就可以和QEMU虛擬機進行通信和數據傳輸(此操作類似配置VMware Workstation的橋接用以與物理機的通信)。

獲取安裝依賴,執行以下命令:

sudo apt-get install bridge-utils uml-utilities

修改ubuntu主機網絡配置,將ubuntu的網絡接口配置文件 /etc/network/interfaces 修改爲如下內容並保存、關閉:

sudo gedit /etc/network/interfaces

修改QEMU的網絡接口啓動腳本,重啓網絡使配置生效,執行以下命令:

sudo gedit /etc/qemu-ifup

在腳本文件/etc/qemu-ifup結尾增加如下內容:

保存文件/etc/qemu-ifup 以後,賦予可執行權限,然後重啓網絡使所有的配置生效:

sudo chmod a+x /etc/qemu-ifup
sudo /etc/init.d/networking restart

QEMU啓動配置

Qemu運行之前先啓動橋接網絡,在本地ubuntu命令行終端執行以下命令(注意:ens33爲ubuntu默認網卡):

sudo ifdown ens33

sudo ifup br0

QEMU MIPS虛擬機啓動

進入前面下載的mips鏡像目錄,執行以下命令:

sudo qemu-system-mips -M malta -kernelvmlinux-2.6.32-5-4kc-malta -hda debian_squeeze_mips_standard.qcow2 -append"root=/dev/sda1 console=tty0" -net nic,macaddr=00:16:3e:00:00:01 -nettap

輸入root/root便可登入qemu mips虛擬機,爲了更便操作mips虛擬機,可在unbuntu中新開啓一個終端,ssh連接到qemu mips:

固件模擬運行

從DLink官網下載包含漏洞版本的路由器固件: ftp://ftp2.dlink.com/PRODUCTS/DIR-859/DIR-859_REVA_FIRMWARE_v1.05B03.zip ,使用binwalk-Me直接解壓固件可得到文件系統文件:

固件模擬運行由兩種方式可以考慮:① 將文件系統上傳到qemu mips虛擬機中運行;② 藉助firmadyne工具運行固件(當然也可以嘗試使用AttifyOS VM):

① 使用scp命令將squashfs-root目錄上傳到qemu mips虛擬機:

chroot /root/squashfs-root sh

② 藉助firmadyne工具運行固件

Firmadyne是一款自動化和可裁剪的嵌入式Linux系統固件分析框架,它支持系統固件逆向QEMU嵌入式系統模擬執行,使用其可模擬路由器固件、執行路由器。安裝和使用方法詳見 https://github.com/firmadyne/firmadyne 。注意:Firmadyne安裝之前,先安裝firmware-analysis-toolkit,安裝方法詳見 https://github.com/attify/firmware-analysis-toolkit ,安裝完成之後在firmware-analysis-toolkit目錄中創建firmadyne目錄並下載安裝Firmadyne。各自全部安裝完成後如下所示(注意兩個工具須完全按照步驟安裝完成,否則後續固件運行會出錯):

首先將firmware-analysis-toolkit目錄下的fat.py和reset.py文件移動到firmadyne目錄;接着進入firmadyne修改firmadyne.config設置路徑如下:

將固件bin文件拷貝至firmadyne目錄,繼續執行以下命令:

rm -rf images*
python3 reset.py
sudo -u postgres createdb -O firmadyne firmware
sudo -u postgres psql -d firmware < ./database/schema
./sources/extractor/extractor.py -b Dlink -sql 127.0.0.1 -np-nk "DIR859Ax_FW105b03.bin" images
./scripts/getArch.sh ./images/1.tar.gz
./scripts/makeImage.sh 1
./scripts/inferNetwork.sh 1
./scratch/1/run.sh

Ubuntu中打開瀏覽器,輸入192.168.0.1即可訪問仿真路由器:

2、遠程調試

路由器固件已成功得以運行,接下來可以對目標程序進行調試,此時可藉助物理機中IDA進行遠程調試(當然,IDA也可以安裝在ubuntu中)。調試仍然有兩種思路:

① 在qemu mips虛擬機中,藉助靜態gdbserver和遠程IDA的“remote GDB debugger”功能對目標mips程序進行動態調試,此處需要注意的是靜態gdbserver文件格式必須和mips系統的大/小端完全對應,可用file命令查看固件的相關信息:

因此須首先交叉編譯得到32bit MSB格式的靜態gdbserver文件,交叉編譯可用選擇Openwrt或Buildroot,此處省略。

② 在ubuntu解出固件文件系統後,使用chroot命令,配合qemu-mips-static運行目標文件(cgibin爲目標文件),然後附件遠程IDA進行動態調試,首先在ubuntu中執行以下命令:

chroot ../qemu-mips-static -g 1235./htdocs/cgibin

接着在物理集中打開IDA調試器,進行如下操作:

最終可成功進行遠程調試:

3、漏洞分析

在路由器運行狀態下,文件系統中的/htdocs/cgibin的genacgi_main()函數在UPnP請求處理過程中,存在遠程執行代碼漏洞。UPnP是專用網絡中設備之間的通信協議,實現了智能設備端到端網絡連接結構。它也是一種架構在TCP/IP和HTTP技術之上的,分佈式、開放的網絡結構,以使得在聯網的設備間傳遞控制和數據。UPnP不需要設備驅動程序,因此使用UPnP建立的網絡是介質無關的。同時UPnP使用標準的TCP/IP和網絡協議,使它能夠無縫的融入現有網絡。構造UPnP應用程序時可以使用任何語言,並在任何操作系統平臺上編譯運行。

嘗試靜態下使用IDA反彙編cgibin文件,然後F5查看僞代碼,發現操作失敗,故換用Ghidra(NSA發佈的、基於Java開發的、適用於Windows、Mac和Linux的跨平臺反彙編工具),發現可快速定位genacgi_main()函數並查看僞碼(貌似反彙編能力優於IDA?):

從僞碼中可以看到,sprintf()函數設置了一個包含所有值的緩衝區,其中函數參數 ?service=及其值,被xmldbc_ephp()函數(最後調用send())將“buffer_8”中包含的數據發送給PHP:

可看出sprintf()用於連接多個變量的值,用於填充一個緩衝區,設置要傳遞的新變量,其中SHELL_FILE將以格式%s_%d.sh進行傳遞,主要用於爲新的shell腳本命名。緩衝區中的數據經過xmldbc_ephp處理,由PHP文件run.NOTIFY.php進行處理,如下:

程序的調用流程爲:buf_8 ->xmldbc_ephp->FUN_0041420c ->FUN_0041372c -> socket。

關於run.NOTIFY.php內容:

其中可見調用了PHP函數 GENA_subscribe_new(),並傳遞cgibin程序中genacgi_main()函數獲得的變量,還包括變量SHELL_FILE。搜索GENA_subscribe_new()發現其定義在gena.php文件中,分析GENA_subscribe_new功能可知其並不修改$shell_file變量,

其傳遞 $shell_file到GENA_notify_init函數,也就是shell_file最終處理的地方:通過調用PHP函數fwrite()創建新文件,且fwrite()函數被使用了兩次:

fwrite()函數第一次創建文件,文件名由可控的SHELL_FILE變量(uri_service)以及getpid()組成:

第二次調用fwrite()向文件中添加刪除命令”rm -f”.$shell_file.”\n”,攻擊時,只需要插入一個反引號包裹的系統命令,將其注入到shell腳本中,當腳本執行rm命令時遇到反引號將失敗,繼續執行引號裏面的系統命令,從而達到遠程命令執行漏洞的觸發。因此,控制好”/gena.cgi?service=shell_file”中shell_file的內容爲反引號包裹的系統命令,就可以觸發漏洞。

4、漏洞重現

根據漏洞原理,執行以下PoC腳本:

由此可見漏洞利用後,目標路由器的telnetd服務被開啓,獲得維持訪問shell。

*本文原創作者:ww5466064,本文屬於FreeBuf原創獎勵計劃,未經許可禁止轉載

相關文章