CVE-2009-3127: Are we safe now?

by Bing Liu
January 6, 2010 at 12:58 pm

Microsoft released bulletin MS09-067 on Nov 10, 2009. Same as in 2008, this last bulletin for Microsoft Office Excel in 2009 gives a total number of 17 vulnerabilities for this popular product. As the biggest contributor, Fortinet is credited for seven of these vulnerabilities in 2009. Our topic today is the vulnerability referred as CVE-2009-3127. It is one of the eight vulnerabilities that were fixed in Bulletin MS09-067. I found this vulnerability by fuzzing (automatic crafted files creation) in April and when I analyzed it I found it is different from other vulnerabilities and so does the patch from Microsoft: the patched Excel is still crashing when proof of concept file is opened! What’s going on!? Does the patch work? You will find the answer in this blog post. My test environment is Microsoft Office 2003 SP3 under Windows XP SP3. The patch updates the Excel.exe file from version 11.0.8307.0 to 11.0.8316.0.

First we need to know what’s the CVE-2009-3127 is. What causes this vulnerability? The following is cited from bulletin MS09-067:

“The vulnerability exists in the way that Microsoft Office Excel parses
the Excel spreadsheet file format when opening a specially crafted
Excel spreadsheet.

The spreadsheet format mentioned above is Excel Binary File Format (.xls). Regarding CVE-2009-3127, when Excel parses a crafted record SXDB(0xC6) in pivot cache stream (refer to page 53 of MS-XLS), if member cfdbdb is greater than cfdbTot (refer to the highlighted value in Figure 1), it will crash or execute code if the file is well-crafted.

d8bjwg5_10hmns7nhs_b

Figure 1: crafted Excel file details

You may think this vulnerability is due to a lack of
sufficient sanitization on SXDB record. Let’s see the associated code in unpatched Excel.exe (11.0.8307.0). The crafted SXDB record is process at offset 0x301B5926.

.text:301B5926 sub_301B5926    proc near               ; CODE XREF: sub_300E45E9+D1779p
.text:301B5926
.text:301B5926                 push    ebp
.text:301B5927                 lea     ebp, [esp-304h]
.text:301B592E                 sub     esp, 384h

.text:301B5AFC                 push    eax
.text:301B5AFD                 push    14h
.text:301B5AFF                 push    0C6h———————————-expected record type: SXDB(0xC6)
.text:301B5B04                 push    edi
.text:301B5B05                 call    sub_300DA264 ————————Read in record SXDB, edi point to the record data
.text:301B5B0A                 test    eax, eax
.text:301B5B0C                 mov     [ebp+304h+var_33C], eax
.text:301B5B0F                 js      loc_30274DA9
.text:301B5B15                 mov     esi, [ebp+304h+var_330]————-esi point to structure created for this pivot cache stream
.text:301B5B18                 mov     [esi], ebx
.text:301B5B1A                 movsx   eax, word ptr [edi+8]
.text:301B5B1E                 mov     [esi+10h], eax
.text:301B5B21                 mov     eax, [edi]
.text:301B5B23                 mov     [esi+14h], eax
.text:301B5B26                 movsx   eax, word ptr [edi+0Ah]
.text:301B5B2A                 mov     [esi+24h], eax————————-store cfdbdb
.text:301B5B2D                 movsx   eax, word ptr [edi+0Ch]
.text:301B5B31                 mov     [esi+28h], eax————————-store cfdbTot

.text:301B5C19                 mov     eax, [esi+24h]
.text:301B5C1C                 cmp     eax, [esi+28h]————————-compare cfdbdb with cfdbTot
.text:301B5C1F                 ja      loc_301B5CEC

.text:301B5CEC                 push    ebx
.text:301B5CED                 push    ebx
.text:301B5CEE                 push    esi
.text:301B5CEF                 call    sub_30602D11—————————clear the structure pointed by esi!!!

As you can see, cfdbdb value is compared with cfdbToc value and the associate structure (remember this structure, we will refer to it later) is cleared if it is illegal. This is the unpatched version! It is not vulnerable. Let’s see whether the patched version improved this function. The function moves to address 301ABE5A in version 11.0.8316.0 and nothing changed! Now it is clear that the function handling SXDB record is not responsible for this vulnerability. But how cfdbdb can be the attack vector of this vulnerability?

Let’s see the real vulnerable code in unpatched Excel.exe(11.0.8307.0). The record SXVI(0xB2) in WorkSheet is processed at offset 0x301C0C2B

.text:301C0C2B sub_301C0C2B    proc near               ; CODE XREF: sub_301C0F83+E9p
.text:301C0C2B
.text:301C0C2B                 push    ebp
.text:301C0C2C                 mov     ebp, esp

.text:301C0C8F                 push    8
.text:301C0C91                 push    0B2h————————————expected record type: SXVI(0xB2)
.text:301C0C96                 push    edi
.text:301C0C97                 call    sub_300DA264 ————————-Read in  record SXVI

.text:301C0D4C                 test    word ptr [esi], 8800h
.text:301C0D51                 jnz     loc_302767F6

.text:302767F6 loc_302767F6:                           ; CODE XREF: sub_301C0C2B+126j
.text:302767F6                 movsx   eax, word ptr [esi+4]
.text:302767FA                 push    eax
.text:302767FB                 push    [ebp+arg_18]————————–The SXVD(0xB1) record number
.text:302767FE                 call    sub_301B0A05————————-The real vulnerable function!
.text:30276803                 test    byte ptr [esi+1], 8
.text:30276807                 jz      short loc_3027680D
.text:30276809                 or      byte ptr [eax+9], 8———————-eax register is controllable by changing SXVD(0xB1) record numbers!

As I comment inline, function at 0x301B0A05 is responsible for this vulnerability:

.text:301B0A05 sub_301B0A05    proc near               ; CODE XREF: sub_301B0A3F+E3p
.text:301B0A05
.text:301B0A05                 mov     ecx, [esp+arg_0]
.text:301B0A09                 mov     eax, dword_30896958—————–The structure that have been cleared in 301B5926,remember it?
.text:301B0A0E                 cmp     ecx, [eax+24h]————————-compare ecx=0×89 with [eax+24] which is cfdbdb (0 since the structure was cleared)
.text:301B0A11                 jge     loc_3029425C—————————-go to wrong path and the return result is controllable

.text:3029425C                 mov     edx, [eax+2Ch]
.text:3029425F                 imul    ecx, 1E4h——————————–SXVD(0xB1) record numbers
.text:30294265                 mov     eax, [esp+arg_4]
.text:30294269                 inc     eax
.text:3029426A                 imul    eax, 0Ch
.text:3029426D                 add     eax, [edx+ecx+1A8h]
.text:30294274                 jmp     locret_301B0A3C

Now, we are clear about this vulnerability: The function processing SXDB record cleared the structure when it found malformed SXDB record, but the code using this structure doesn’t handle this case. The cooperation of the producer and consumer failed.

Let’s see how Microsoft improves the function at offset 0x301B0A05 in the patched version. The function moved to address 301A7431.

.text:301A7431 sub_301A7431    proc near               ; CODE XREF: sub_301A7474+E3p
.text:301A7431
.text:301A7431                 mov     ecx, [esp+arg_0]
.text:301A7435                 mov     eax, dword_308960A8
.text:301A743A                 cmp     ecx, [eax+28h]—————————compare ecx=0×89 with [eax+28] which is cfdbTot (0 since the structure was cleared)
.text:301A743D                 jnb     loc_30294818——————————patch point, jump to address
30294818 in our case
.text:301A7443                 cmp     ecx, [eax+24h]
.text:301A7446                 jge     loc_3029481F

.text:30294818                 xor     eax, eax————————————-clear eax
.text:3029481A                 jmp     locret_301A7471

Without handling this 0 return value, Excel crash at address 30276DC1:

.text:30276DB6                 call    sub_301A7431——————————return 0
.text:30276DBB                 test    byte ptr [esi+1], 8
.text:30276DBF                 jz      short loc_30276DC5
.text:30276DC1                 or      byte ptr [eax+9], 8————————-Excel crashes with an access violation exception, the crash is non-exploitable

The patch is very simple. It just adds one more validation for cfdbdb when handling SXVI record and return zero if the validation fail. Excel doesn’t handle this zero value smoothly and crashes again. This is acceptable for Excel since the crash becomes non-exploitable. As a conclusion, the patch for CVE-2009-3127 is unshaped but we are safe now.

Author bio: Bing Liu works as a senior researcher/IPS manager for Fortinet. 10+ years work experience in the field of Information Security/CISSP.

Leave a Reply