Analysis CVE-2011-0978 Microsoft Office Excel Axis Properties Record Parsing Buffer Overflow

Author: instruder of Code Audit Labs of vulnhunt.com
Analysis ID: CALA-2011-001
Time: 2011/8/8
url:
http://blog.vulnhunt.com/index.php/2011/08/08/analysis-cve-2011-0978/

1 Affected Products
=================
测试版:Micrsoft Office Excel 2003 (11.8307.8221) SP3
漏洞编号:CVE-2011-0978
2 Vulnerability Details
=====================
Microsoft Office Excel在解析Axis Properties Record属性时,采用了有符号扩展,将WORD扩展成一个DWORD,同时在后面使用这个数组索引时,虽然有判断,但是采用了有符号比较,导致被绕过,允许攻击者索引任意DWORD,而这个DWORD指向的内存中前2个字节是拷贝的长度,后面是拷贝的源,源和拷贝长度都可以控制,理论上可以利用,从而导致恶意代码的执行可能。

3 Analysis
=====================

载入poc样本后 用windbg挂上后,点击关闭excel,弹出是否需要保存框,点击保存,触发crash(也可以直接点击cw 表也可以触发),信息如下:

代码:
(848.b24): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=05b4629c ebx=05b40460 ecx=00000000 edx=ffff5554 esi=00000000 edi=00000001
eip=30177d15 esp=00137938 ebp=00137944 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for E:\Program Files\Microsoft Office\OFFICE11\EXCEL.EXE - 
EXCEL!Ordinal41+0x177d15:
30177d15 8b0490          mov     eax,dword ptr [eax+edx*4] ds:0023:05b1b7ec=????????
0:000> u 
EXCEL!Ordinal41+0x177d15:
30177d15 8b0490          mov     eax,dword ptr [eax+edx*4]
30177d18 3bc6            cmp     eax,esi
30177d1a 741e            je      EXCEL!Ordinal41+0x177d3a (30177d3a)
30177d1c 0fb708          movzx   ecx,word ptr [eax]
30177d1f 894d10          mov     dword ptr [ebp+10h],ecx
30177d22 41              inc     ecx
30177d23 51              push    ecx
30177d24 ff750c          push    dword ptr [ebp+0Ch]
0:000> dd eax
05b4629c  05b462e4 05b462fc 05b46314 05b4632c
05b462ac  05b46344 05b4635c 05b46374 05b4638c
05b462bc  05b463a4 00000001 00000001 00000001
05b462cc  00000001 00000001 00000001 00000001
05b462dc  00000001 00000001 00630009 0061006c
05b462ec  00730073 006f0077 006b0072 0e000000
05b462fc  00630009 0061006c 00730073 006f0077
05b4630c  006b0072 0e000000 00630009 0061006c

由上面crash信息可知edx是数组的索引,变成了FFFF5554,同时根据exploitdb 上面这个漏洞的概述知道5554 这个字段是在poc中的0x39E7处,猜测可能是有符号扩展导致由5554变成了FFFF5554.

转至IDA中查看 asm in Excel.exe 
.text:30177CDE sub_30177CDE    proc near               ; CODE XREF: sub_30173D14+33A p
.text:30177CDE                                         ; sub_30175B4C+309 p ...
.text:30177CDE
.text:30177CDE arg_0           = dword ptr  8
.text:30177CDE Dst             = dword ptr  0Ch
.text:30177CDE arg_8           = dword ptr  10h
.text:30177CDE arg_C           = dword ptr  14h
.text:30177CDE arg_10          = dword ptr  18h
.text:30177CDE arg_14          = dword ptr  1Ch
.text:30177CDE
.text:30177CDE ; FUNCTION CHUNK AT .text:30324E3C SIZE 000000C9 BYTES
.text:30177CDE
.text:30177CDE                 push    ebp
.text:30177CDF                 mov     ebp, esp
.text:30177CE1                 mov     ecx, [ebp+arg_0]
.text:30177CE4                 mov     eax, [ecx+40h]
.text:30177CE7                 mov     edx, [ebp+arg_10]
.text:30177CEA                 push    esi
.text:30177CEB                 xor     esi, esi
.text:30177CED                 mov     dword_3088D744, esi
.text:30177CF3                 cmp     edx, [eax+0Ch] //edx是数组索引
.text:30177CF6                 jge     loc_30324E3C//关键 有符号比较,导致如果edx为负数就可绕过限制。
.text:30177CFC                 cmp     [ebp+arg_14], esi
.text:30177CFF                 push    ebx
.text:30177D00                 push    edi
.text:30177D01                 jz      loc_30324E59
.text:30177D07                 mov     ecx, [ebp+arg_C]
.text:30177D0A                 cmp     ecx, esi
.text:30177D0C                 jg      loc_30324EFA
.text:30177D12
.text:30177D12 loc_30177D12:                           ; CODE XREF: sub_30177CDE+1AD222 j
.text:30177D12                 mov     eax, [eax+10h]
.text:30177D15                 mov     eax, [eax+edx*4] ; edx为索引
.text:30177D18                 cmp     eax, esi
.text:30177D1A                 jz      short loc_30177D3A
.text:30177D1C                 movzx   ecx, word ptr [eax]//前2个字节是拷贝长度
.text:30177D1F                 mov     [ebp+arg_8], ecx
.text:30177D22                 inc     ecx
.text:30177D23                 push    ecx             ; int
.text:30177D24                 push    [ebp+Dst]       ; Dst //指向堆栈
.text:30177D27                 add     eax, 2
.text:30177D2A                 push    eax             ; Src //后面是拷贝的源
30177D2B    E8 6345E9FF     CALL EXCEL.3000C293


此时堆栈:
0013792C   05B4633E  >c?                   //SRC    
00137930   001379EA   .   UNICODE "classwork"        //DST
00137934   00006349  Ic..                    //SIZE


3000C293    8B4424 0C       MOV EAX,DWORD PTR SS:[ESP+C]
3000C297    03C0            ADD EAX,EAX
3000C299    50              PUSH EAX
3000C29A    FF7424 0C       PUSH DWORD PTR SS:[ESP+C]
3000C29E    FF7424 0C       PUSH DWORD PTR SS:[ESP+C]
3000C2A2    E8 8EF4FFFF     CALL EXCEL.3000B735
3000C2A7    C2 0C00         RETN 0C

此时堆栈:
0013791C   05B4633E  >c?                  //SRC
00137920   001379EA   .   UNICODE "classwork"        //DST
00137924   0000C692  ..                  //SIZE


3000B735    55              PUSH EBP
3000B736    8BEC            MOV EBP,ESP
3000B738    F645 13 80      TEST BYTE PTR SS:[EBP+13],80
3000B73C    0F85 8E7D2100   JNZ EXCEL.302234D0
3000B742    FF75 10         PUSH DWORD PTR SS:[EBP+10]               ; SIZE
3000B745    FF75 08         PUSH DWORD PTR SS:[EBP+8]                ; SRC
3000B748    FF75 0C         PUSH DWORD PTR SS:[EBP+C]                ;DST
3000B74B    E8 82FBFFFF     CALL <JMP.&MSVCRT.memmove>
3000B750    83C4 0C         ADD ESP,0C
3000B753    0345 10         ADD EAX,DWORD PTR SS:[EBP+10]
3000B756    5D              POP EBP
3000B757    C2 0C00         RETN 0C

看到这里是个拷贝,[ebp+c]指向了堆栈,[ebp+10]是可以控制的(数组过界,向上溢出,可以控制索引的数据,拷贝的长度.拷贝的源)

此时堆栈:
00137908   001379EA   .   |dest = 001379EA              //指向堆栈
0013790C   05B4633E  >c?   |src = 05B4633E              //索引的源
00137910   0000C692  ..   \n = C692 (50834.)              //size

….
拷贝前:
001379E8   00630009  ..c.   ----》001379EA
001379EC   0061006C  l.a.
001379F0   00730073  s.s.
001379F4   006F0077  w.o.
001379F8   006B0072  r.k.
…….
00137A30   00000037  7...
00137A34   05B41908    ?
00137A38   0000012F  / ..
00137A3C   0000007E  ~...
00137A40   05B4259C  ??
00137A44   3017BC61  a?0   返回到 EXCEL.3017BC61 来自 EXCEL.30171240

拷贝后堆栈:
001379E8   05B40009  ..?
001379EC   05B4636C  lc?
001379F0   05B461A8  ?
001379F4   05B46390  ?    UNICODE "\tclasswork"
………
00137A2C   00000001   ...
00137A30   00000001   ...
00137A34   00000001   ...
00137A38   00000001   ...
00137A3C   00630009  ..c.
00137A40   0061006C  l.a.
00137A44   00730073  s.s.---返回地址被覆盖
从上面分析可知,由于数组索引越界导致索引恶意的内存,从这个内存中取前2个字节作为size,用这个(size+1)*2来进行拷贝指定的地址(由数组索引控制)到固定的堆栈空间,导致堆栈溢出漏洞。

4 Causes of vulnerability

通过一层层往上追溯,重启excel n次之后终于追踪到源头。
代码:
301B72E8   .  0FBF4E 02            MOVSX ECX,WORD PTR DS:[ESI+2]//esi指向文件中的0x95F3偏移处(poc更改后的)
301B72EC   .  8948 04              MOV DWORD PTR DS:[EAX+4],ECX//有符号扩展
从CB50扩展到FFFFCB50  这个FFFFCB50就是上面提到的数组索引EDX
301B72EF   .  0FBF06               MOVSX EAX,WORD PTR DS:[ESI]
301B72F2   .  8B8D C4E7FFFF        MOV ECX,DWORD PTR SS:[EBP-183C]
301B72F8   .  8941 10              MOV DWORD PTR DS:[ECX+10],EAX
301B72FB   .  0FBF46 04            MOVSX EAX,WORD PTR DS:[ESI+4]
301B72FF   .  8B8D C4E7FFFF        MOV ECX,DWORD PTR SS:[EBP-183C]
301B7305   .  8941 0C              MOV DWORD PTR DS:[ECX+C],EAX
301B7308   .  8A4E 06              MOV CL,BYTE PTR DS:[ESI+6]
实际跟踪过程图:
 


5 exploit
5.1 about shellcode position

这个poc里面有好几张表,我在最后一张表中,随便找个表格添加许多的字符”jjjjjjjjjjj” 
然后点击保存。再次打开后,点击第二个表“” 一样会崩溃。这样就可以用od载入excel,然后搜索字符串”jjjjjjjjjjjjjjjjjj” 找到这个在内存中的位置(一般是unicode类型)。(shellcode最好按这种方式添加,先用字符串站位,直接在excel中用二进制文件打开写不一定行,很容易写坏文件格式或者写了之后根本不读入内存)(个人看法,不知道别人是不是这样:)。

 

这里后面会填入shellcode,先作为标记。

这里回到上面分析的地方30177D15
30177D15   .  8B0490        MOV EAX,DWORD PTR DS:[EAX+EDX*4]==eax=05B46250 
30177D18   .  3BC6          CMP EAX,ESI
30177D1A   .  74 1E         JE SHORT EXCEL.30177D3A
30177D1C   .  0FB708        MOVZX ECX,WORD PTR DS:[EAX]
30177D1F   .  894D 10       MOV DWORD PTR SS:[EBP+10],ECX
30177D22   .  41            INC ECX
30177D23   .  51            PUSH ECX
30177D24   .  FF75 0C       PUSH DWORD PTR SS:[EBP+C]
30177D27   .  83C0 02       ADD EAX,2
30177D2A   .  50            PUSH EAX
30177D2B   .  E8 6345E9FF   CALL EXCEL.3000C293
这里我们需要构造这样的数据:
EAX+EDX*4 指向的内存中我们的shellcode,而且这个内存的前2个字节是要拷贝的长度。

测试中发现这个EDX中的CC不能改成C6,改成80以下都不行。
而BB可以改成任意值。

(FFFF0000+XX<<8+YY)*4
XX>=0x80;
Y 属于N

这里就要我们自己构造这样的EDX了 同时要保证索引后指向的内存里面存放了我们shellcode的地址,我们可以在excel中添加更多的垃圾数据来定位,多试验几次。

我这里设置的是edx= FFFFCB50
如下图:
 

(好像不是很通用,有时地址会变….:)

5.2 about exploit

此时拷贝的源和大小我们都可以控制了,接下来开始利用了

由于excel对字符的处理,这里要用unicode的shellcode来进行利用。同时返回地址利用的jmp esp(或其他指令)需要时unicode类型的.,同时momove拷贝之后,还需要经过很长的路才能执行到返回地址处,中间就会导致异常,故打算采用SEH的方式来进行利用


 
可知最近的SEH处理函数时处于堆栈0x0013F890,只要覆盖这个SEH即可。(必须是UNICODE)
找一个指令序列是pop xx popxx retn(不仅限于)即可返回的时候跳到堆栈0013F890处执行,此处已经被我们的控制。

覆盖SEH时,各寄存器值以及堆栈值
 

过SEH可以使用的指令
Pop xx
Pop xx
Retn

Call dword ptr [ebp]
Jmp dword ptr [ebp]
Call dword ptr [esp+2c]
Call dword ptr [esp+8]
…..
Ps :暂时并没有找到合适的地址,没有成功利用… 接下来就看你的了 :)