详解cve-2010-2553

来源:互联网 发布:淘宝客服的服务用语 编辑:程序博客网 时间:2024/06/03 08:43
我的调试环境是win7旗舰版32位+wmpalyer+windbg+IDA。

poc见: https://www.exploit-db.com/exploits/15112/
wmpalyer设置页堆:
C:\Program Files\Debugging Tools for Windows (x86)>gflags.exe -i wmplayer.exe +hpa +htcCurrent Registry Settings for wmplayer.exe executable are: 02000010    htc - Enable heap tail checking    hpa - Enable page heap
C:\Program Files\Debugging Tools for Windows (x86)>gflags.exe -i wmplayer.exeCurrent Registry Settings for wmplayer.exe executable are: 02000010    htc - Enable heap tail checking    hpa - Enable page heap
打开wmplayer,windbg附加进程,wmplayer中打开poc,windbg成功断下:
0:015> g(f14.efc): Access violation - code c0000005 (first chance)First chance exceptions are reported before any exception handling.This exception may be expected and handled.eax=113f1000 ebx=113ef000 ecx=00000040 edx=00000000 esi=113ef000 edi=113f1000eip=76faa05b esp=1163f510 ebp=1163f518 iopl=0         nv up ei pl nz na po nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202msvcrt!__ascii_strnicmp+0x99:76faa05b 660f7f07        movdqa  xmmword ptr [edi],xmm0 ds:0023:113f1000=????????????????????????????????
此时查看栈回溯及113f1000所在堆的信息:
0:027> kvn # ChildEBP RetAddr  Args to Child              00 1163f518 76faa00b 113f1000 113ef000 00002000 msvcrt!__ascii_strnicmp+0x99 (FPO: [3,0,0])01 1163f548 70ae3ba2 113f1000 113ef000 00002000 msvcrt!_VEC_memcpy+0x52 (FPO: [3,0,0])02 1163f588 70aeeeda 00000004 00000000 00000068 iccvid!CVDecompress+0x141 (FPO: [Non-Fpo])03 1163f5b8 70ae80f8 0ddd0f60 00000000 10ed2fd8 iccvid!Decompress+0x128 (FPO: [Non-Fpo])04 1163f604 71f01759 0ddd0f60 00000001 0000400d iccvid!DriverProc+0x1bf (FPO: [Non-Fpo])05 1163f628 6ce78639 71f1c7c0 0000400d 1163f640 MSVFW32!ICSendMessage+0x31 (FPO: [Non-Fpo])06 1163f658 6ce789c4 71f1c7c0 00000000 10ed2fd8 quartz!CVFWDynLink::ICDecompress+0x3e (FPO: [Non-Fpo])07 1163f710 6cf26cbe 1107cfa8 111bafb8 00000000 quartz!CAVIDec::Transform+0x2b0 (FPO: [Non-Fpo])08 1163f73c 6cf26910 1107cfa8 00000000 0e956ee0 quartz!CVideoTransformFilter::Receive+0x120 (FPO: [Non-Fpo])09 1163f750 6ce60472 0e9aef44 1107cfa8 1163f790 quartz!CTransformInputPin::Receive+0x33 (FPO: [Non-Fpo])0a 1163f760 6cf2d61e 1107cfa8 00040103 0e956ee0 quartz!CBaseOutputPin::Deliver+0x22 (FPO: [Non-Fpo])0b 1163f790 6cf2d830 1163f7c0 1163f7bc 00000000 quartz!CBaseMSRWorker::TryDeliverSample+0x102 (FPO: [Non-Fpo])0c 1163f7d4 6cf2deba 00000000 0e956ee0 0e956ee0 quartz!CBaseMSRWorker::PushLoop+0x15b (FPO: [Non-Fpo])0d 1163f7ec 6cf2e46a 00000000 6ce35735 00000000 quartz!CBaseMSRWorker::DoRunLoop+0x44 (FPO: [Non-Fpo])0e 1163f7f4 6ce35735 00000000 00000000 1163f810 quartz!CBaseMSRWorker::ThreadProc+0x39 (FPO: [0,0,4])0f 1163f804 76811174 0e956ee0 1163f850 7720b3f5 quartz!CAMThread::InitialThreadProc+0x15 (FPO: [Non-Fpo])10 1163f810 7720b3f5 0e956ee0 6779fde2 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])11 1163f850 7720b3c8 6ce35720 0e956ee0 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])12 1163f868 00000000 6ce35720 0e956ee0 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])0:027> !heap -p -a 113f1000    address 113f1000 found in    _DPH_HEAP_ROOT @ b1000    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)                                10e53c64:         113eb000             6000 -         113ea000             8000    6fe58e89 verifier!AVrfDebugPageHeapAllocate+0x00000229    77274ea6 ntdll!RtlDebugAllocateHeap+0x00000030    77237d96 ntdll!RtlpAllocateHeap+0x000000c4    772034ca ntdll!RtlAllocateHeap+0x0000023a    754a7589 KERNELBASE!LocalAlloc+0x0000005f    70ae3d93 iccvid!CVDecompressBegin+0x00000092    70aee2a2 iccvid!DecompressBegin+0x000002cf    70ae80d1 iccvid!DriverProc+0x00000198    71f01759 MSVFW32!ICSendMessage+0x00000031    6ce79925 quartz!CAVIDec::StartStreaming+0x0000027a    6cf266fb quartz!CTransformFilter::Pause+0x00000060    6ce782a4 quartz!CAVIDec::Pause+0x0000002f    6ce29e03 quartz!CFilterGraph::Pause+0x00000223    6ce2c8b1 quartz!CFGControl::Cue+0x00000032    6ce35c40 quartz!CFGControl::CImplMediaControl::StepPause+0x0000004c    6ce35be9 quartz!CFGControl::CImplMediaControl::Pause+0x0000002d    6d4aaac6 qedit!CMediaDet::EnterBitmapGrabMode+0x00000114    6d4aa64b qedit!CMediaDet::GetBitmapBits+0x000000ac    6893d32a wmp!SelectPoster+0x000000c3    6893d585 wmp!EhGetVideoThumbnail+0x000000c5    68601358 wmp!CWMPThumbnailRetriever::ComputeAndCacheThumbnail+0x00000449    6891026c wmp!CArtHandler::_RunMLSJob+0x000002a7    689115ef wmp!CArtHandler::_RunJob+0x00000038    68911693 wmp!CArtHandler::_BackgroundArtThreadLoop+0x00000044    68911899 wmp!BackgroundArtWorkProc+0x00000050    771c6cf5 ntdll!TppWorkpExecuteCallback+0x0000010f    771de8d1 ntdll!TppWorkerThread+0x00000572    76811174 kernel32!BaseThreadInitThunk+0x0000000e    7720b3f5 ntdll!__RtlUserThreadStart+0x00000070    7720b3c8 ntdll!_RtlUserThreadStart+0x0000001b
看到栈回溯中msvcrt!_VEC_memcpy+0x52 我们应该猜到是复制数据的时候出现了问题。

继续往上看函数的调用,查看iccvid!CVDecompress+0x141处函数调用:
0:027> ub iccvid!CVDecompress+0x141iccvid!CVDecompress+0x127:70ae3b88 8b461c          mov     eax,dword ptr [esi+1Ch]70ae3b8b 8b4dfc          mov     ecx,dword ptr [ebp-4]70ae3b8e 03c1            add     eax,ecx70ae3b90 6800200000      push    2000h70ae3b95 8d8800e0ffff    lea     ecx,[eax-2000h]70ae3b9b 51              push    ecx70ae3b9c 50              push    eax70ae3b9d e834d60000      call    iccvid!memcpy (70af11d6)
可以看到问题出现在iccvid!CVDecompress函数中,其中调用了 iccvid!memcpy引发了异常,那么就重点分析一下函数iccvid!CVDecompress吧
我们在函数iccvid!CVDecompress上断点,重新加载,运行并查看此时函数的参数情况:
0:005> teax=00000001 ebx=119bfcf0 ecx=fffb95f0 edx=00000120 esi=112c7f60 edi=10086a10eip=70d4eed5 esp=119bfca0 ebp=119bfcc8 iopl=0         nv up ei pl zr na pe nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246iccvid!Decompress+0x123:70d4eed5 e8874bffff      call    iccvid!CVDecompress (70d43a61)0:005> dd esp119bfca0  11306fc0 11148af8 00000068 10040000119bfcb0  00046e00 10086a10 fffffc10 00000001119bfcc0  112c7f60 112c7f60 119bfd14 70d480f8119bfcd0  112c7f60 00000000 112eafd8 11148af8119bfce0  00000000 00000000 ffffffff ffffffff119bfcf0  00046e00 10040000 00000068 00000000119bfd00  ffffffff ffffffff 119bfd50 733ec7dc119bfd10  0ff80fa8 119bfd38 733d1759 112c7f600:005> dd 11148af811148af8  68000000 20016001 00101000 0000100011148b08  60000000 00206001 00110000 4141100011148b18  41414141 41414141 00114141 4141100011148b28  41414141 41414141 00114141 4141100011148b38  41414141 41414141 00114141 0041100011148b48  31786469 00000010 63643030 0000001011148b58  00000004 00000068 c0c0c0c0 c0c0c0c011148b68  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0


我们可以看到第二个参数就是poc中cinepak_codec_data1开始的数据。
用IDA打开 iccvid.dll查看函数iccvid!CVDecompress的伪c代码(详见附表):
可以看到当满足v26 && !BYTE3(a3) && *(_BYTE *)v14 == 17时进行内存数据的复制
每次复制v26+1 a3即函数的第三个参数,00000068取一个字节所以等于0,v14=a2+10 v14+=*(_BYTE *)(v14 + 3) | ((*(_BYTE *)(v14 + 2) | (*(_BYTE *)(v14 + 1) << 8)) << 8)
在未进入循环前,我们看下此时的v14布局:
0:005> dd 0x11148af8+0x0a11148b02  10000010 00000000 60016000 0000002011148b12  10000011 41414141 41414141 4141414111148b22  10000011 41414141 41414141 4141414111148b32  10000011 41414141 41414141 4141414111148b42  10000011 64690041 00103178 3030000011148b52  00106364 00040000 00680000 c0c0000011148b62  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
第一次时,*(byte*)v14=0x10=16!=17所以不会进行复制数据操作
然后v14=v14+*(_BYTE *)(v14 + 3) | ((*(_BYTE *)(v14 + 2) | (*(_BYTE *)(v14 + 1) << 8)) << 8)
此处*(byte*)(v14+3)=0x10 *(byte*)(v14+2)=0x0 *(byte*)(v14+1)=0x0
所以进行操作后v14=v14+0x10 根据内存布局 后续的几次循环其实都是加上0x10
此时*v14=0x10000011,*(byte*)v14=0x11 符合复制数据的条件,进行内存数据复制操作。

而且内存复制还包含在一个大的循环里边,即当v26<v13时进行循环:
v26从0开始,每次循环加一,v13等于*(_BYTE *)(a2 + 9) | (*(_BYTE *)(a2 + 8) << 8)这是一个固定值0x10
iccvid!CVDecompress+0x7b:70d43adc c1e008          shl     eax,870d43adf 895df4          mov     dword ptr [ebp-0Ch],ebx70d43ae2 0bc1            or      eax,ecx70d43ae4 8d5f0a          lea     ebx,[edi+0Ah]70d43ae7 8945e0          mov     dword ptr [ebp-20h],eax70d43aea 895df0          mov     dword ptr [ebp-10h],ebx70d43aed 0f8ed2010000    jle     iccvid!CVDecompress+0x264 (70d43cc5)70d43af3 8365fc00        and     dword ptr [ebp-4],00:005> bp 70d43ae40:005> gBreakpoint 2 hiteax=00000010 ebx=00000000 ecx=00000010 edx=00000120 esi=11306fc0 edi=11148af8eip=70d43ae4 esp=119bfc6c ebp=119bfc98 iopl=0         nv up ei pl nz na po nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202iccvid!CVDecompress+0x83:70d43ae4 8d5f0a          lea     ebx,[edi+0Ah]



最近在步入函数iccvid!CVDecompress时做个虚拟机快照,这样方便以后调试,也可以避免每次启动带来的数据变化。

我们在函数70ae3b9d e834d60000 call iccvid!memcpy处下断,看他执行几次出现异常:
0:005> uiccvid!CVDecompress+0x12a:70d43b8b 8b4dfc          mov     ecx,dword ptr [ebp-4]70d43b8e 03c1            add     eax,ecx70d43b90 6800200000      push    2000h70d43b95 8d8800e0ffff    lea     ecx,[eax-2000h]70d43b9b 51              push    ecx70d43b9c 50              push    eax70d43b9d e834d60000      call    iccvid!memcpy (70d511d6)70d43ba2 83c40c          add     esp,0Ch0:005> bp 70d43b9d0:005> bl 0 e 70d4eeda     0001 (0001)  0:**** iccvid!Decompress+0x128 1 e 70d4eebf     0001 (0001)  0:**** iccvid!Decompress+0x10d 2 e 70d43ae4     0001 (0001)  0:**** iccvid!CVDecompress+0x83 3 e 70d43b9d     0001 (0001)  0:**** iccvid!CVDecompress+0x13c0:005> bd 0,1,20:005> bl 0 d 70d4eeda     0001 (0001)  0:**** iccvid!Decompress+0x128 1 d 70d4eebf     0001 (0001)  0:**** iccvid!Decompress+0x10d 2 d 70d43ae4     0001 (0001)  0:**** iccvid!CVDecompress+0x83 3 e 70d43b9d     0001 (0001)  0:**** iccvid!CVDecompress+0x13c0:005> gBreakpoint 2 hiteax=115e0000 ebx=11148b12 ecx=115de000 edx=00000041 esi=11306fc0 edi=00000010eip=70d43b9d esp=119bfc60 ebp=119bfc98 iopl=0         nv up ei pl nz na pe nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206iccvid!CVDecompress+0x13c:70d43b9d e834d60000      call    iccvid!memcpy (70d511d6)0:005> dd esp l4119bfc60  115e0000 115de000 00002000 10086a100:005> gBreakpoint 3 hiteax=115e2000 ebx=11148b22 ecx=115e0000 edx=00000041 esi=11306fc0 edi=00000010eip=70d43b9d esp=119bfc60 ebp=119bfc98 iopl=0         nv up ei pl nz na pe nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206iccvid!CVDecompress+0x13c:70d43b9d e834d60000      call    iccvid!memcpy (70d511d6)0:005> dd esp l4119bfc60  115e2000 115e0000 00002000 10086a100:005> gBreakpoint 3 hiteax=115e4000 ebx=11148b32 ecx=115e2000 edx=00000041 esi=11306fc0 edi=00000010eip=70d43b9d esp=119bfc60 ebp=119bfc98 iopl=0         nv up ei pl nz na pe nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206iccvid!CVDecompress+0x13c:70d43b9d e834d60000      call    iccvid!memcpy (70d511d6)0:005> dd esp l4119bfc60  115e4000 115e2000 00002000 10086a100:005> g(f2c.a3c): Access violation - code c0000005 (first chance)First chance exceptions are reported before any exception handling.This exception may be expected and handled.eax=115e4000 ebx=115e2000 ecx=00000040 edx=00000000 esi=115e2000 edi=115e4000eip=76faa05b esp=119bfc20 ebp=119bfc28 iopl=0         nv up ei pl nz na po nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202msvcrt!__ascii_strnicmp+0x99:76faa05b 660f7f07        movdqa  xmmword ptr [edi],xmm0 ds:0023:115e4000=????????????????????????????????


可以看到当执行第三次内存复制时出现异常
通过异常处堆的信息我们可以看到,此处堆起始于115de000,大小为0x6000,也就是115de000-115e4000
而每次复制的内存大小为0x2000,第三次复制时内存的起始地址已经是115e4000,复制数据时肯定导致堆溢出了。


再来分析一下函数iccvid!memcpy吧 IDA的部分伪代码如下:
memcpy((void *)(v28 + *(_DWORD *)(v7 + 28)), (const void *)(v28 + *(_DWORD *)(v7 + 28) - 0x2000), 0x2000u);


先看一下这个函数,第一次参数是目的地址,第二个参数是原地址,第三个参数是复制长度。
一开始v28=0 *(_DWORD *)(v7 + 28)= *(_DWORD *)(a1 + 28) 也就是函数iccvid!CVDecompress第一个参数偏移0x1c处保存的地址就是函数memcpy要复制到的地址。
每次复制后v28+0x2000.
0:005> teax=00000001 ebx=119bfcf0 ecx=fffb95f0 edx=00000120 esi=112c7f60 edi=10086a10eip=70d43a61 esp=119bfc9c ebp=119bfcc8 iopl=0         nv up ei pl zr na pe nccs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246iccvid!CVDecompress:70d43a61 8bff            mov     edi,edi0:005> dd esp119bfc9c  70d4eeda 11306fc0 11148af8 00000068119bfcac  10040000 00046e00 10086a10 fffffc10119bfcbc  00000001 112c7f60 112c7f60 119bfd14119bfccc  70d480f8 112c7f60 00000000 112eafd8119bfcdc  11148af8 00000000 00000000 ffffffff119bfcec  ffffffff 00046e00 10040000 00000068119bfcfc  00000000 ffffffff ffffffff 119bfd50119bfd0c  733ec7dc 0ff80fa8 119bfd38 733d17590:005> dd 11306fdc l411306fdc  115de000 115de000 00000000 01200150
地址0x115de000 就是memcpy复制的目的地址
原地址为0x115de000向前0x2000处保存的数据,但是由于第一次的时候if语句没有成立(v14不等于0x11),所以真正的复制是以0x115e0000 为目的地址,0x115de000 为原地址开始的。


而且这三次复制每次的数据都是一样的 都是来自地址0x115de000的复制



真正的堆溢出利用需要控制0x115de000中的数据,正好覆盖115e4000开始处内存中的虚表指针等重要结构,可以达到任意代码执行的效果。






















signed int __stdcall CVDecompress(unsigned int a1, int a2, unsigned int a3, int a4, int a5, int a6, int a7){  unsigned int v7; // esi@1  int v8; // edi@1  int v9; // ST18_4@2  signed int result; // eax@4  int v11; // edi@5  int v12; // eax@5  int v13; // eax@7  int v14; // ebx@7  int v15; // edi@10  __int16 v16; // dx@14  int v17; // ecx@18  bool v18; // cf@18  int v19; // eax@18  int v20; // edi@19  int v21; // [sp+Ch] [bp-20h]@7  int v22; // [sp+10h] [bp-1Ch]@10  int v23; // [sp+14h] [bp-18h]@18  int v24; // [sp+18h] [bp-14h]@18  int v25; // [sp+1Ch] [bp-10h]@7  int v26; // [sp+20h] [bp-Ch]@7  unsigned int v27; // [sp+24h] [bp-8h]@6  int v28; // [sp+28h] [bp-4h]@8  v7 = a1;  v8 = *(_DWORD *)(a1 + 36);  if ( v8 )  {    v9 = a7;    *(_DWORD *)(a1 + 36) = 0;    CVDecompress(v7, v8, 0x2446u, 0, 0, 0, v9);    LocalFree((HLOCAL)v8);  }  if ( a3 < 0x20    || (v11 = a2,        v12 = *(_BYTE *)(a2 + 3) | ((*(_BYTE *)(a2 + 2) | (*(_BYTE *)(a2 + 1) << 8)) << 8),        (signed int)a3 < v12)    || (BYTE3(a3) = *(_BYTE *)a2, ULongSub(v12, 0xAu, (int)&v27) < 0) )  {LABEL_4:    result = 0;  }  else  {    v26 = 0;    v13 = *(_BYTE *)(v11 + 9) | (*(_BYTE *)(v11 + 8) << 8);    v14 = v11 + 10;    v21 = v13;    v25 = v11 + 10;    if ( v13 > 0 )    {      v28 = 0;      do      {        if ( v27 < 0x16 )          break;        v15 = *(_BYTE *)(v14 + 3) | ((*(_BYTE *)(v14 + 2) | (*(_BYTE *)(v14 + 1) << 8)) << 8);        v22 = v15;        if ( v27 < v15 )          break;        if ( *(_BYTE *)v14 == 16 || *(_BYTE *)v14 == 17 )        {          if ( ULongSub(v15, 0xCu, (int)&a1) < 0 )            goto LABEL_4;          v16 = *(_BYTE *)(v14 + 5);          a2 = (unsigned __int16)(*(_WORD *)(v7 + 46)                                * (_byteswap_ushort(*(_WORD *)(v14 + 8)) - _byteswap_ushort(*(_WORD *)(v14 + 4))));          if ( v26 && !BYTE3(a3) && *(_BYTE *)v14 == 17 )            memcpy((void *)(v28 + *(_DWORD *)(v7 + 28)), (const void *)(v28 + *(_DWORD *)(v7 + 28) - 0x2000), 0x2000u);          v17 = v25 + 12;          v18 = a1 < 4;          *(_DWORD *)(v7 + 56) = v28 + *(_DWORD *)(v7 + 32);          v19 = v14 + 12;          v24 = v14 + 12;          v23 = v25 + 12;          *(_DWORD *)(v7 + 60) = a7;          if ( !v18 )          {            do            {              v20 = *(_BYTE *)(v19 + 3) | ((*(_BYTE *)(v19 + 2) | (*(_BYTE *)(v19 + 1) << 8)) << 8);              if ( a1 < v20 )                break;              switch ( *(_BYTE *)v19 )              {                case 0x20:                case 0x21:                case 0x24:                case 0x25:                  (*(void (__stdcall **)(int, _DWORD, _DWORD, _DWORD))v7)(                    v17,                    *(_DWORD *)(v7 + 56),                    *(_DWORD *)(v7 + 52),                    *(_DWORD *)(v7 + 48));                  break;                case 0x22:                case 0x23:                case 0x26:                case 0x27:                  (*(void (__stdcall **)(int, int, _DWORD, _DWORD))(v7 + 4))(                    v17,                    *(_DWORD *)(v7 + 56) + 4096,                    *(_DWORD *)(v7 + 52),                    *(_DWORD *)(v7 + 48));                  break;                case 0x30:                  (*(void (__stdcall **)(unsigned int, int, int, int, int, int, int))(v7 + 8))(                    v7,                    v17 + 4,                    v20 - 4,                    a4,                    a5,                    a6,                    a2);                  break;                case 0x31:                  (*(void (__stdcall **)(unsigned int, int, int, int, int, int, int))(v7 + 16))(                    v7,                    v17 + 4,                    v20 - 4,                    a4,                    a5,                    a6,                    a2);                  break;                case 0x32:                  (*(void (__stdcall **)(unsigned int, int, int, int, int, int, int))(v7 + 12))(                    v7,                    v17 + 4,                    v20 - 4,                    a4,                    a5,                    a6,                    a2);                  break;                default:                  break;              }              v19 = v20 + v24;              v17 = v20 + v23;              v24 += v20;              v23 += v20;              if ( (unsigned int)v20 <= 1 )                v20 = 1;              a1 -= v20;            }            while ( a1 >= 4 );            v15 = v22;          }          a6 += a7 * (signed __int16)a2;          ++v26;          v28 += 0x2000;          v13 = v21;        }        v25 += v15;        v27 -= v15;        v14 += v15;      }      while ( v26 < v13 );    }    result = 1;  }  return result;}


原创粉丝点击