OK,又是週末晚上,沒有約會,只有一大瓶Shasta汽水和全是快節奏的音樂…那就研究一下程序吧。php
一時興起,我下載了D-link無線路由器(型號:DIR-100 revA)的固件程序 v1.13。使用工具Binwalk,很快的就從中發現並提取出一個只讀SquashFS文件系統,沒用多大功夫我就將這個固件程序的web server(/bin/webs)加載到了IDA中:web
/bin/webs中的字符信息瀏覽器
基於上面的字符信息能夠看出,這個/bin/webs二進制程序是一個修改版的thttpd,提供路由器管理員界面操做功能。看起來是通過了臺灣明泰科技(D-Link的一個子公司)的修改。他們甚至頗有心計的將他們不少自定義的函數名都輔以「alpha」前綴:session
明泰科技的自定義函數數據結構
這個alpha_auth_check函數看起來頗有意思!ide
這個函數被不少地方調用,最明顯的一個是來自alpha_httpd_parse_request函數:wordpress
調用alpha_auth_check函數函數
咱們能夠看到alpha_auth_check函數接收一個參數(是存放在寄存器$s2裏);若是alpha_auth_check返回-1(0xFFFFFFFF),程序將會跳到alpha_httpd_parse_request的結尾處,不然,它將繼續處理請求。工具
寄存器$s2在被alpha_auth_check函數使用前的一些操做代碼顯示,它是一個指向一個數據結構體的指針,裏面有一個char*指針,會指向從HTTP請求裏接收到的各類數據;好比HTTP頭信息和請求地址URL: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);
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; }
換句話說,若是瀏覽器的User-Agent值是「xmlset_roodkcableoj28840ybtide」(不帶引號),你就能夠不經任何認證而能訪問web控制界面,可以查看/修改路由器的設置(下面是D-Link路由器(DI-524UP)的截圖,我沒有 DIR-100型號的,但DI-524UP型號使用的是相同的固件):
訪問型號DI-524UP路由器的主界面
基於HTML頁上的源代碼信息和Shodan搜索結果,差很少能夠得出這樣的結論:下面的這些型號的D-Link路由器將會受到影響:
除此以外,幾款Planex路由器顯然也是用的一樣的固件程序:
你很酷呀,D-Link。
腳註:萬能的網友指出,字符串「xmlset_roodkcableoj28840ybtide」是一個倒序文,反過來讀就是「editby04882joelbackdoor_teslmx」——edit by 04882joel backdoor _teslmx,這個後門的做者真是位天才!