我是如何反編譯D-Link路由器固件程序并發現它的后門的
英文原文: Reverse Engineering a D-Link Backdoor
OK,又是周末晚上,沒有約會,只有一大瓶 Shasta 汽水和全是快節奏的音樂…那就研究一下程序吧。
一時興起,我下載了D-link 無線路由器(型號:DIR-100 revA)的固件程序 v1.13。使用工具 Binwalk,很快的就從中發現并提取出一個只讀 SquashFS 文件系統,沒用多大功夫我就將這個固件程序的 web server (/bin/webs)加載到了 IDA 中:
/bin/webs 中的字符信息
基于上面的字符信息可以看出,這個/bin/webs 二進制程序是一個修改版的 thttpd,提供路由器管理員界面操作功能。看起來是經過了臺灣明泰科技(D-Link 的一個子公司)的修改。他們甚至很有心計的將他們很多自定義的函數名都輔以“alpha”前綴:
明泰科技的自定義函數
這個alpha_auth_check函數看起來很有意思!
這個函數被很多地方調用,最明顯的一個是來自alpha_httpd_parse_request函數:
調用 alpha_auth_check 函數
我們可以看到alpha_auth_check函數接收一個參數(是存放在寄存器$s2 里);如果alpha_auth_check返回-1(0xFFFFFFFF),程序將會跳到alpha_httpd_parse_request的結尾處,否則,它將繼續處理請求。
寄存器$s2 在被alpha_auth_check函數使用前的一些操作代碼顯示,它是一個指向一個數據結構體的指針,里面有一個 char*指針,會指向從 HTTP 請求里接收到的各種數據;比如 HTTP 頭信息和請求地址 URL:
$s2 是一個指向一個數據結構體的指針
我們現在可以模擬出alpha_auth_check函數和數據結構體的大概樣子:
struct http_request_t { char unknown[0xB8]; char *url; // At offset 0xB8 into the data structure };int alpha_auth_check (struct http_request_t *request);</pre>
alpha_auth_check本身是一個非常簡單的函數。它會針對http_request_t結構體里的一些指針進行字符串strcmp比較操作,然后調用check_login函數,實際上就是身份驗證檢查。如果一旦有字符串比較成功或check_login成功,它會返回1;否者,它會重定向瀏覽器到登錄頁,返回-1;
alpha_auth_check 函數代碼片段
這些字符串比較過程看起來非常有趣。它們提取請求的 URL 地址(在http_request_t數據結構體的偏移量 0xB8 處),檢查它們是否含有字符串“graphic/” 或 “public/”。這些都是位于路由器的 Web 目錄下的公開子目錄,如果請求地址包含這樣的字符串,這些請求就可以不經身份認證就能執行。
然而,這最后一個 strcmp 卻是相當的吸引眼球:
alpha_auth_check 函數中一個非常有趣的字符串比較
這個操作是將http_request_t結構體中偏移量 0xD0 的字符串指針和字符串“xmlset_roodkcableoj28840ybtide”比較,如果字符匹配,就會跳過check_login函數,alpha_auth_check操作返回1(認證通過)。
我在谷歌上搜索了一下“xmlset_roodkcableoj28840ybtide”字符串,只發現在一個俄羅斯論壇里提到過它,說這是一個在/bin/webs 里一個“非常有趣”的一行。我非常同意。
那么,這個神秘的字符串究竟是和什么東西進行比較?如果回顧一下調用路徑,我們會發現http_request_t結構體被傳進了好幾個函數:
事實證明,http_request_t結構體中處在偏移量 0xD0 處的指針是由httpd_parse_request函數賦值的:
檢查 HTTP 頭信息中的 User-Agent 值
將 http_request_t + 0xD0 指針指向頭信息 User-Agent 字符串
這代碼實際上就是:
if(strstr (header, "User-Agent:") != NULL) { http_request_t->0xD0 = header + strlen ("User-Agent:") + strspn (header, " \t"); }知道了http_request_t偏移量 0xD0 處的指針指向 User-Agent 頭信息,我們可以推測出alpha_auth_check函數的結構:
#define AUTH_OK 1 #define AUTH_FAIL -1 int alpha_auth_check (struct http_request_t *request) { if(strstr (request->url, "graphic/") || strstr (request->url, "public/") || strcmp (request->user_agent, "xmlset_roodkcableoj28840ybtide") == 0) { return AUTH_OK; } else { // These arguments are probably user/pass or session info if(check_login (request->0xC, request->0xE0) != 0) { return AUTH_OK; } }return AUTH_FAIL;
}</pre>
換句話說,如果瀏覽器的 User-Agent 值是“xmlset_roodkcableoj28840ybtide”(不帶引號),你就可以不經任何認證而能訪問 web 控制界面,能夠查看/修改路由器的設置(下面是D-Link 路由器(DI-524UP)的截圖,我沒有 DIR-100 型號的,但 DI-524UP 型號使用的是相同的固件):
訪問型號 DI-524UP 路由器的主界面
基于 HTML 頁上的源代碼信息和 Shodan 搜索結果,差不多可以得出這樣的結論:下面的這些型號的D-Link 路由器將會受到影響:
- DIR-100
- DI-524
- DI-524UP
- DI-604S
- DI-604UP
- DI-604+
- TM-G5240 </ul>
- BRL-04UR
- BRL-04CW </ul>
除此之外,幾款 Planex 路由器顯然也是用的同樣的固件程序:
你很酷呀,D-Link。
腳注:萬能的網友指出,字符串“xmlset_roodkcableoj28840ybtide”是一個倒 序文,反過來讀就是“editby04882joelbackdoor_teslmx”——edit by 04882joel backdoor _teslmx,這個后門的作者真是位天才!