by phperl ,zzf,nine9 of code audit labs of vulnhunt.com

在2013年9月3日,翰海源捕获到一个针对中国政府部门的钓鱼邮件定向攻击事件(参考我们之前的文章) 。我们发现该攻击利用了一个WPS 2012/2013的0day漏洞,之后我们在第一时间通知被攻击客户,以及联系金山WPS相关部门处理该问题。金山WPS对于我们反映的问题,做出迅速响应,与昨天(2013年12月10日)修补该漏洞,并发布新的版本WPS。请大家及时更新WPS的最新版本,下面是我们针对本次0day攻击事件的技术分析一些摘要。

在WPS处理rtf时,遇到\*\fchars元素时处理不当,导致堆溢出,成功利用,攻击者可以执行任意代码。

在处理rtf时,遇到\*\fchars元素时会将其后形如\u16705格式的字符串转换成字符后使用wcscat追加到缓冲区末尾,直到遇到‘}’字符为止,由于没有检测字符串的长度,导致heap缓冲区溢出。缓冲区位于C++对象的内部,紧跟在缓冲区后面的是虚表指针,覆盖了虚表指针后,可以跳转到用户控制的地址,构造ROP绕过DEP可以执行任意代码。

asm code in rtfreader.dll 9.1.0.4249
.text:10033296                 mov     [ebp+arg_0], eax
.text:10033299                 call    ds:isalpha
.text:1003329F                 pop     ecx
.text:100332A0                 test    eax, eax
.text:100332A2                 jz      short loc_1003326B
.text:100332A4                 lea     eax, [ebp+var_1C]
.text:100332A7                 push    eax
.text:100332A8                 push    ebx
.text:100332A9                 call    read_num  //ebp-1c为转换前的字符串长度
.text:100332AE                 cmp     [ebp+var_1C], 496h
.text:100332B5                 jnz     short loc_100332C8
.text:100332B7                 push    [ebp+var_18]  //ebp-18为转换后的字符
.text:100332BA                 push    [ebp+arg_4]
.text:100332BD                 push    ebx
.text:100332BE                 call    sub_10032A2C
.text:100332C3                 jmp     loc_1003304E
 
.text:10011D2C ; int __stdcall sub_10011D2C(int, void *Src, int)
.text:10011D2C sub_10011D2C    proc near               ; DATA XREF: .rdata:10038644o
.text:10011D2C                                         ; .rdata:100386F8o
.text:10011D2C
.text:10011D2C Dst             = dword ptr -20h
.text:10011D2C var_C           = dword ptr -0Ch
.text:10011D2C var_4           = dword ptr -4
.text:10011D2C arg_0           = dword ptr  8
.text:10011D2C Src             = dword ptr  0Ch
.text:10011D2C arg_8           = dword ptr  10h
.text:10011D2C
.text:10011D2C                 push    ebp
.text:10011D2D                 mov     ebp, esp
.text:10011D2F                 sub     esp, 20h
.text:10011D32                 mov     eax, ___security_cookie
.text:10011D37                 xor     eax, ebp
.text:10011D39                 mov     [ebp+var_4], eax
.text:10011D3C                 mov     eax, [ebp+Src]
.text:10011D3F                 push    esi
.text:10011D40                 push    [ebp+arg_8]     ; Dst
.text:10011D43                 mov     esi, [ebp+arg_0]
.text:10011D46                 push    eax             ; Src
.text:10011D47                 lea     ecx, [ebp+Dst]
.text:10011D4A                 call    sub_1000FF9B
.text:10011D4F                 cmp     [ebp+var_C], 8
.text:10011D53                 mov     eax, [ebp+Dst]
.text:10011D56                 jnb     short loc_10011D5B
.text:10011D58                 lea     eax, [ebp+Dst]
.text:10011D5B
.text:10011D5B loc_10011D5B:                           ; CODE XREF: sub_10011D2C+2Aj
.text:10011D5B                 push    eax             ; Source
.text:10011D5C                 mov     eax, [esi+8]
.text:10011D5F                 add     eax, 18D8h
.text:10011D64                 push    eax             ; Dest
.text:10011D65                 call    ds:wcscat    //追加到缓冲区末尾,此处会导致缓冲区溢出
.text:10011D6B                 pop     ecx
.text:10011D6C                 pop     ecx
.text:10011D6D                 push    0               ; int
.text:10011D6F                 push    1               ; char

漏洞利用分析

利用上面的方式在堆上填充大量0×030a4a2c,该地址为指向dbghelp.dll中切换堆栈的指令,将堆栈切换到发生溢出的缓冲区中,从而利用dbghelp.dll中的指令构造ROP绕过DEP。

0:000> u 030a4a2c
dbghelp!dia::CDiaLoadCallback::InitExeRead+0x43:
030a4a2c 95              xchg    eax,ebp
030a4a2d c0eb02          shr     bl,2
030a4a30 b001            mov     al,1
030a4a32 5e              pop     esi
030a4a33 c9              leave
030a4a34 c3              ret

溢出的缓冲区的内容为:

  1. ROP链

  2. Shellcode

  3. NOP指令0×41414141

  4. 0×030a4a2c在堆中的地址

重现方法如下:

ba e1 030a4a2c
eax=035fbc48 ebx=03648008 ecx=00200404 edx=035d65e7 esi=0012cda0 edi=00000071
eip=030a4a2c esp=0012ccdc ebp=0012ccf8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
dbghelp!MiniDumpReadDumpStream+0x4eb7c:
030a4a2c 95              xchg    eax,ebp
0:000> db eax-20
035fbc28  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
035fbc38  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
035fbc48  04 04 20 00 8e c5 0b 03-f0 f4 ff ff 84 0f 0c 03  .. .............
035fbc58  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
035fbc68  00 00 00 00 58 9c f1 01-00 00 00 00 00 00 00 00  ....X...........
0:000> dd 200404
00200404  030a4a2c 030a4a2c 030a4a2c 030a4a2c
00200414  030a4a2c 030a4a2c 030a4a2c 030a4a2c
00200424  030a4a2c 030a4a2c 030a4a2c 030a4a2c

ROP链分析

将堆栈指针切换到溢出缓冲区

执行VirtualProtect,将栈变为可执行

返回到jmp esp指令,开始执行shellcode

先是shellcode解码头

035fb254 0fb6c0          movzx   eax,al
035fb257 01c7            add     edi,eax
035fb259 3017            xor     byte ptr [edi],dl          ds:0023:035fb260=f5
035fb25b 47              inc     edi
035fb25c 49              dec     ecx
035fb25d 75fa            jne     035fb259

循环遍历句柄,调用GetFileSize,成功则调用CreateFileMapping、MapViewOfFile,搜索11222211和33444433,找到则开始解密,将解密后的内容写入临时文件的IE7.exe文件,并使用WinExec执行该文件,执行后会释放到临时目录win32_453B.dll。

shellcode使用LoadLibrary加载释放的dll,并调用dll导出函数mail。

源链接

Hacking more

...