Analysis of CVE-2011-0041 vulnerability in GDI+

Abysssec Research

we tried for other case in exploit bounty this time for a 500$ one .

no luck for successful exploitation and to be honest we didn’t tried so hard . at least we got a PoC and here is our analysis for this cool bug.

1) Advisory information

 

  Title                   :  GDI+ CreateDashedPath Integer overflow in gdiplus.dll  

  Discovery         :  Nicolas july from vupen

  Analysis            :  Abysssec.com

  Vendor             :  http://www.microsoft.com

  Impact              :  High

  Contact            :  info  [at] abysssec.com

  Twitter             : @abysssec

  CVE                   : CVE-2011-0041

2) Vulnerable version

Gdiplus.dll 5.2.6001.22319

 

3) Vulnerability information

 

Class

        1-Integer overflow

Impact

Successfully exploiting this issue allows remote attackers to execute arbitrary code in the context of vulnerable application or cause denial-of-service conditions.

Remotely Exploitable

Yes

Locally Exploitable

Yes

4) Vulnerabilities detail

 

The vulnerability exists in gdiplus!GpPath::CreateDashedPath function of gdiplus.dll that is responsible for bitmap drawing and other 2d graphic rendering. EMF+ file is one of the image file format that is rendered by the library. And the vulnerability is based on some floating point calculation of an EMF+ path object.

We made the following proof of concept to trigger the issues and it will be explained more:

 

A little taste of file format we simply put a EMF_COMMENT record (id = 0×00000046) and embed and emf+ geraphic object ( id = 0×00004008 ) . For simplicity we ripped out a valid graphic object from another file and started to play with it. The record have two important area that we highlighted them in the above picture.

 

Here is the faulty code:

.text:4ECFCBAD loc_4ECFCBAD:                     

.text:4ECFCBAD                 mov     eax, esi

.text:4ECFCBAF                 shl     eax, 3

.text:4ECFCBB2                 cmp     [ebp+lpMem], 0

.text:4ECFCBB6                 push    eax             ; dwBytes

.text:4ECFCBB7                 jz      short loc_4ECFCBCE

.text:4ECFCBB9                 push    [ebp+lpMem]     ; lpMem

.text:4ECFCBBC                 call    GpRealloc(x,x)

.text:4ECFCBC1                 test    eax, eax

.text:4ECFCBC3                 jz      loc_4ECFCCDB

.text:4ECFCBC9                 mov     [ebp+lpMem], eax

.text:4ECFCBCC                 jmp     short loc_4ECFCBDE

.text:4ECFCBCE ; —————————————————————————

.text:4ECFCBCE

.text:4ECFCBCE loc_4ECFCBCE:                      

.text:4ECFCBCE                 call    GpMalloc(x)

.text:4ECFCBD3                 test    eax, eax

.text:4ECFCBD5                 mov     [ebp+lpMem], eax

.text:4ECFCBD8                 jz      loc_4ECFCCDB

 

The above code uses the eax register as arguments to the GpMalloc function. GpMalloc is simply a gdi version of heapAlloc function. The value of eax register is based on various floating point calculation that is not simple to examine at first look.

But I traced the value of eax register and it seems the calculations are based on our values mentioned earlear in the file.  And it doesn’t bound checked well, by changing the path value tricky it is possible when the “shl    eax, 3” instruction multiply the value by 8 we get an integer overflow and in turn a faulty heap allocation.

 

I dynamically traced the values with my proof of concept file. Eax register is equall to eax + [ebp-38] * 10 and as there are a lot of values and calculations before that, for better consideration I made the following diagram:

 

 

 

 

It took a lot of time explanation of all of the variables above but, the important one is the GpPath object that is in the code a clone of the object is made to later be manipulated for drawings.

.text:4ECFC9D9 loc_4ECFC9D9:                           ; CODE XREF: GpPath::CreateDashedPath(DpPen const *,GpMatrix const *,float,float,float,int)+1AAj

.text:4ECFC9D9                 fld     dword ptr [esi+eax*4]

.text:4ECFC9DC                 fmul    [ebp+arg_0]

.text:4ECFC9DF                 fstp    dword ptr [esi+eax*4]

.text:4ECFC9E2                 inc     eax

.text:4ECFC9E3                 cmp     eax, [ebp+arg_4]

.text:4ECFC9E6                 jl      short loc_4ECFC9D9

.text:4ECFC9E8

.text:4ECFC9E8 loc_4ECFC9E8:                      

.text:4ECFC9E8                 mov     ecx, [ebp+var_18] ; Src

.text:4ECFC9EB                 call    GpPath::Clone(void)

.text:4ECFC9F0                 mov     edi, eax

.text:4ECFC9F2                 test    edi, edi

.text:4ECFC9F4                 jz      loc_4ECFCDBA

.text:4ECFC9FA                 mov     eax, [edi]

.text:4ECFC9FC                 mov     ecx, edi

.text:4ECFC9FE                 call    dword ptr [eax+4]

 

After calling the clone, it checks whether it is a valid clone or not at address 4ECFC9FE.

The offset +34h of the object contains a pointer to our 4byte path object values.

0:000> dd ecx

0e03ca50  4ec67e58 68745031 00000000 00000000

0e03ca60  0e03ca74 0e03ca74 00000010 00000010

0e03ca70  00000002 00000100 00000000 00000000

0e03ca80  00000000 0e03ca98 0e03ca98 00000010

0e03ca90  00000010 00000002 449a8eab 458ac500

0e03caa0  449a8eab 4e0000fe 00000000 00000000

0e03cab0  00000000 00000000 00000000 00000000

0e03cac0  00000000 00000000 00000000 00000000

 

Our floating point values in the file format:

0e03ca98  449a8eab 458ac500 449a8eab 4e0000fe

0e03caa8  00000000 00000000 00000000 00000000

 

But there are some modifications on our values before we get the faulty code. First after the clone is performed GpPath::Flatten function made some changes to our values based on a transform matrix in the file. So this is cause of the highlighted 6 DWORDs in the file.­­­

.text:4ECFC9FE                 call    dword ptr [eax+4]

.text:4ECFCA01                 test    eax, eax

.text:4ECFCA03                 jz      loc_4ECFCDBA

.text:4ECFCA09                 fld     ds:flt_4ECB80FC

.text:4ECFCA0F                 push    ecx             ; float

.text:4ECFCA10                 lea     eax, [ebp+var_F8]

.text:4ECFCA16                 fstp    [esp+108h+var_108]

.text:4ECFCA19                 push    eax             ; int

.text:4ECFCA1A                 mov     ecx, edi

.text:4ECFCA1C                 call    GpPath::Flatten(GpMatrix const *,float)

.text:4ECFCA21                 cmp     [ebp+var_2C], 0

 

Flattened GpPath object values:

0:000> dd poi(edi+34)

0e03cd18  449a7eab 458ac100 449a7eab 4e0000fd

0e03cd28  00000000 00000000 00000000 00000000

 

And after that our changed GpPath object is sent to calculateGradiantArray and some array of floating point values are made based on its calculation.

There are many other default floating point values has effects on the value of the overflowing size for GpMalloc that are not so interesting and I’ve just shown them on the diagram.

After the calculation integer wrapped, the heap allocated by the gpMalloc function is not big enough to hold our data. So in next uses of the wrapped allocated heap the corruption occurs. But it seems there is not a straight way of exploiting such heap corruptions using a standalone file. .

PoC link   : http://abysssec.com/files/GDI_PoC.zip

			
Get Adobe Flash playerPlugin by wpburn.com wordpress themes