171 lines
7 KiB
Text
Executable file
171 lines
7 KiB
Text
Executable file
Abysssec Research
|
|
|
|
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 =
|
|
0x00000046) and embed and emf+ geraphic object ( id = 0x00004008 ) .
|
|
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 ?shr 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. .
|
|
|
|
feel free to contact us at : info [at] abysssec.com
|
|
|
|
PoC link : http://abysssec.com/files/GDI_PoC.zip
|
|
PoC Mirror : http://www.exploit-db.com/sploits/GDI_PoC.zip
|
|
|
|
|