OpenWrt是一款應用于嵌入式設備如路由器等的Linux操作系統。類似于kali等linux系統中的apt-get等,該系統中下載應用使用的是opgk工具,其通過非加密的HTTP連接來下載應用。但是其下載的應用使用了SHA256sum哈希值來進行檢驗,所以將下載到的數據包進行哈希值的比對即可知道是否下載的數據包被修改,所以理論上來說是沒有安全隱患的。
學習參考:
OPENWRT中的遠程命令執行漏洞(CVE-2020-7982)-安全客 - 安全資訊平臺
Uncovering OpenWRT Remote Code Execution (CVE-2020-7982) | Mayhem
我們對于這個漏洞將進行幾個步驟,具體的目錄如下:
目錄
分析學習漏洞以及利用條件
搭建OpenWrt環境并啟動
模擬漏洞利用和攻擊
漏洞的相關修復
分析學習漏洞以及利用條件
分析漏需要相應的源代碼,參考源代碼的地址為:
https://git.openwrt.org/?p=project/opkg-lede.git;a=blob;f=libopkg/pkg_parse.c;h=0baa4db396569be816386b50568c57e12d1cd98c;hb=80d161eb5b95ceb51db989196405eaa00950e03b#l312
也可以直接clone到本地學習代碼:
git clone https://git.openwrt.org/project/opkg-lede.git
首先對于源代碼中這個位置
針對哈希值采用了SHA256sum的情況,會調用函數pkg_set_sha256來進行處理。傳遞給該函數的字符串是字符串SHA256sum后面的字符串。該函數為:
https://git.openwrt.org/?p=project/opkg-lede.git;a=blob;f=libopkg/pkg.c;h=e5bfe6f61b67583c00e528fb381162ace308dc13;hb=80d161eb5b95ceb51db989196405eaa00950e03b#l244
其會繼續使用函數checksum_hex2bin來進行校驗處理。如果最終檢驗的結果是0或者文件的長度不為32,就會出現相應的錯誤,返回值為NULL,從而不會保存相應的哈希值。繼續進入函數checksum_hex2bin:
https://git.openwrt.org/?p=project/opkg-lede.git;a=blob;f=libopkg/file_util.c;h=61ff736cd2c82a224cb10f48d14532b8224bd792;hb=80d161eb5b95ceb51db989196405eaa00950e03b#l234
其中函數isxdigit是檢查其是否為十六進制數字字符,而isspace是檢查是否是空格。在這個函數中,最開始指針s和指針src是指向同一個位置的,而如果src所指向的內容出現空格,其會循環直到把空格去掉。也就是說,如果存在空格字符,也就是字符串SHA256sum后面的字符串的開頭是一個空格,src和s所指向的地址就不同了。但是在256行開始的循環中,判斷用到的字符是isxdigit(s[0]),依然用的是指針s所指向的內容。所以如果存在空格,此時循環會直接終止,指針len的長度為0,然后函數執行完畢。
也就是說,通過上面這樣的操作,我們就可以使checksum_hex2bin函數最終處理的len值長度為0,所以pkg_set_sha256函數也會返回NULL,最終其哈希值就沒有被成功設置。
接下來包列表解析就算完成了,下一步會開始HTTP下載包,然后會進入相應的驗證步驟。
首先要求下載的軟件包必須等于列表中指定好的大小,如下:
https://git.openwrt.org/?p=project/opkg-lede.git;a=blob;f=libopkg/opkg_install.c;h=27c9484cfb8189e42cbc073eaa14a67c71c3507a;hb=80d161eb5b95ceb51db989196405eaa00950e03b#l1379
檢查相應的文件大小。且還要求如果指定了軟件的哈希值,則其也需要匹配:
但是由于剛才checksum_hex2bin沒有對其進行hash編碼,所以這里1416行的if語句被直接跳過,不進行哈希驗證。這就是相應的漏洞存在的位置。
漏洞利用
為了利用這個漏洞,我們需要實現兩件事。首先讓被攻擊的電腦下載時重定向到我們有惡意軟件包的服務器,而不是直接與downloads.openwrt.org服務器進行通信,這個需要我們能夠做到更改本地的DNS或者基于ARP欺騙等策略。其次,兩重檢查中,哈希檢查已經被繞過了,就還剩一個數據包大小的檢查需要應對。那么參考文章中提供了一種很有效的方法:
1.創建一個受損的軟件包,但是其大小要小于原軟件包
2.計算兩者之間的大小差異
3.最受損包的末尾用0字節進行填充,使其相同大小