0x01 前言

  • 微软提供一个叫 Cinepak 的视频解码器,通过调用 iccvid.dll 这个动态链接库文件可以使用这个解码器;微软自带的 Windows Media Player(视频音频软件)通过调用 iccvid.dll 解析有漏洞的 RIFF 音频文件格式时会触发 CVE-2010-2553 这个漏洞
  • 该漏洞的成因是由于 iccvid.dll 中的 CVDecompress 这个函数在解析漏洞文件时没有对 cvid 格式编码条中的 Chunk 数量做限制,导致连续复制数据到堆空间,最终超出,导致堆溢出

0x02 调试环境

  • 虚拟机:Windows XP sp3,版本:11.0.8211(提取码:woi9)
  • 调试工具:Windbg(Windbg32Windbg64)、ODIDA(提取码:v0pt)、C32Asm(16进制分析文件工具,提取码:4sj8)
  • 漏洞程序:Windows Media Player(提取码:07n9)
  • 实验样本:能触发漏洞的 .avi 格式的 POC 文件(提取码:5ilg)

》每台机器调试时的地址可能会不一样

0x03 关于 cvid 的格式

  • cvid 是一种压缩格式,嵌入在 .avi 格式之中,在使用它这个格式时需要对其进行解压缩
  • 下图就是 cvid 的格式,由格式头(Frame Header)和 body 组成,body 里面就是顺序排列的编码条,每一个编码条都包含一个编码条头(Strip Header)和多个 Chunk ID + 对应数据的 Cvid Chunk 组成的结构,这些结构按顺序排列在编码条头之后

  • 这个就是样本中对应的 cvid 格式

Flag:00(1个字节)

Cvid 数据长度:00 00 68(3个字节)

编码帧宽度:01 60

编码帧高度:01 20

编码条数量:00 10




编码条 ID:10 00

编码条数据大小:00 10

顶部 X 坐标:00 00

顶部 Y 坐标:00 00

底部 X 坐标:00 60

底部 Y 坐标:01 60

Chunk ID:20 00

Chunk 数据大小:00 00

Chunk ID:11 00

Chunk 数据大小:00 10

Chunk 数据:AAAAAAAAAAAA(12个字节,0x10 - 4 的结果)

Chunk ID:11 00

Chunk 数据大小:00 10

Chunk 数据:AAAAAAAAAAAA

Chunk ID:11 00

Chunk 数据大小:00 10

Chunk 数据:AAAAAAAAAAAA


0x04 根据异常定位漏洞函数

  • 打开 Windows Media Player 软件,用 Windbg 附加进程

  • 开启堆页保护之后运行,之后将 POC 拖入 Windows Media Player 内,成功捕获异常,出问题的动态链接库就是 iccvid.dll,该链接库在 system32 中;因为开启了堆页保护,所以可以断定 rep 循环复制命令复制了超量的数据导致了堆溢出

  • 使用 !Heap 列出程序使用的堆空间列表,查看 edi 的值,发现在第一个堆中;为什么查看 edi 的值呢,rep 指令将 esi 指向的数据复制到 edi 的地址之中,因为造成了堆溢出,所以此时 edi 指向的地址一定在堆中

  • 之后使用 !Heap -a 0090000 查询堆中的堆块信息,发现 edi 所指向的地址在这一个堆块当中,0x00156e40 这个堆块就是有问题的堆块,该堆块的下面还有一个 0x15ce48 的堆块,继续溢出的话会对这个堆块造成影响

  • 将 system32 中的 iccvid.dll 载入到 IDA 中,找到 0x73b722cc 这个地址,F5 翻译成伪 C 代码



  • 找到了问题函数 memcpy,这个就是 CVE-2010-2553 漏洞触发的根源

0x05 根据样本调试分析漏洞成因

  • 与以往的漏洞不太一样,该漏洞所调用的 memcpy 函数并不是一次性的将数据复制到堆中,而是循环调用该函数复制数据到堆中,直到堆中数据溢出
  • OD 载入程序可以选择先打开程序(也可以使用 Windbg 或 Immunity Debugger 调试,根据个人喜好),再附加进程,就像这样,你也可以找到源程序再拖入 OD 运行,一个道理

  • 附加完进程之后,这时下 0x73b722cc 这个异常断点是断不下来的,因为此时程序还没有加载 iccvid.dll 这个动态链接库(0x73b722cc地址是动态链接库里面的)
  • 这里可以采用等程序异常终止以后再下这个断点,就像下面这样,此时已经加载了 iccvid 动态链接库并且可以下断点

  • 如图所示,已经在异常处断下
  • 在断点断下后,需要找到函数的入口,从函数入口调试有利于理解运行流程
  • 如何找到函数的入口,很简单,可以查看栈中返回值

  • 查看栈,找到一个返回值,使用 enter 键跳到这个地址
  • 假如有些调试过程中这个地址可能不是想要寻找的函数地址,这时可以继续沿栈向下查找返回值,多试几次就可以了(当然,在栈中的数据完好不被恶意覆盖时可以这么做)

  • 可以发现就是这个函数调用了 memcpy 将数据复制到栈上的
  • 下断点之后重新运行

  • 之后 F7 进入这个函数,来看看函数对样本数据做了哪些操作:
  • 首先第一步>>>先对比 Cvid 数据长度是否大于 0x20,之后会将 Cvid 数据长度的第一个字节和第二个字节分别放入寄存器 eax 的高位和地位,我们将此时的 eax 中的数据暂且称为 result1
  • 然后将 result1 和 Cvid 数据长度的第三个字节做积或运算,我们将运算的结果称为result2

  • 如果 Cvid数据长度小于 result2 或者 UlongSub 函数的返回值小于 0 的话就进入 if 语句

  • ULongSub 函数的功能是将第一个参数的值减去第二个参数的值赋到第三个参数的地址中,如果第一个参数大于第二个参数就返回负数,反之则返回 0

  • 第二步>>>判断编码条的数量是否大于 0

  • v11 存放的是 POC 数据的地址,v13 的值是 POC 地址偏移 0x8 个字节,刚好是编码条数量的地址

  • 第三步>>>比较未解压缩数据的长度是否小于 0x16

  • 此时未解压数据的大小为 0x5E,由 UlongSub 函数计算未解压数据的大小

  • 第四步>>>取出编码条 ID 的第二个字节和编码条数据大小的第一个字节分别放入寄存器的高低字节,我们暂且将这个值称为 res1
  • 之后 res1 和编码条数据大小的第二个字节(0x10)做积或运算,运算完的值称为 res2
  • 最后判断未解压数据的大小是否小于 res2
  • 第五步>>>判断编码条 ID 的第一个字节是否等于 0x10 或者 0x11

  • v11 指向 POC 的地址,v14 是 v11 的地址加 10(0xA) 后地址的值,用于读取 POC 样本中的数据
  • v14 指向的 POC 地址为编码条 ID 的地址 + 0x1值,也就是编码条的第二个字节 0x10

好像确实有点复杂,多调试几次就可以了

  • 最后一步>>>首先判断引用计数是否不为 0,由此可知 do - while 循环第一次并没有执行 memcpy 函数,其次判断 Cvid 数据长度的第三个字节是否不为 0(BTYE3 函数取目标的第三个字节),最后判断 Chunk ID 的第一个字节是否等于 0x11(十进制 17)
  • 在满足上述所有条件后才会执行 memcpy 函数



  • 逻辑图如下图所示,只列出了相对重要的步骤

  • do - while 循环结尾如下图所示,v28 是引用计数,v32 控制着 memcpy 函数的第一个和第二个参数的值

  • 下面就是 memcpy 这个函数,v32 每次递增 0x2000;参数一和参数二由 v7 和 v32 控制,参数三也就是复制数据的大小为固定的 0x2000
  • 所以按理说执行条件满足后执行 3 次就会造成堆溢出(上面 Windbg 调试出堆的大小为 6000,因为堆中还要存放其他数据,所以 3 次足够了),由于初次进入循环时引用计数为 0,所以并没有执行 memcpy 函数,所以加上这一次,在 do - while 执行到第四次循环的时候才真正的溢出

注意堆虽然会溢出,但是并不代表一定触发异常

0x06 漏洞是否可以利用

  • 反观 memcpy 函数,发现只有 v7 的值相对可以被控制,下面是函数的追根溯源
  • v7 = a1,a1 是 CVDecompress 的第一个参数

  • CVDecompress 的第一个参数由 a1 控制

  • a1 由 Decompress 的第一个参数传入

  • 第一个参数由 v5 控制

  • v5 又是 DriverProc 函数的 dwDriverIdentifier 参数传入,貌似传入的是一个地址

  • 调用关系就是 dwDriverIdentifier() -> Decompress() -> CVDecompress() -> memcpy()
  • 那么 dwDriverIdentifier 是怎么传进来的呢,答案是由源程序传入,并不是 iccvid.dll 中的数据,也就是说程序在调用 iccvid.dll 链接库时才将 dwDriverIdentifier 传进来,故漏洞利用的难度是非常大的
  • 再往上追根溯源的话就已经超出了 iccvid.dll 动态链接库的范围了,与本文主题不符,故不做过多阐述
  • 参考资料:0day安全:软件漏洞分析技术 + 漏洞战争

本次对于 CVE-2010-2553 堆溢出漏洞的分析到此结束,如有错误,欢迎指证

CVE-2010-2553:Microsoft Cinepak Codec CVDecompress 函数堆溢出漏洞调试分析的更多相关文章

  1. CVE-2012-0003:Microsoft Windows Media Player winmm.dll MIDI 文件堆溢出漏洞调试分析

    0x01 蜘蛛漏洞攻击包 前言:2012 年 2月,地下黑产中流行着一款国产名为蜘蛛漏洞的攻击包 -- "Zhi-Zhu Exploit Pack",该工具包含 5 个漏洞,都是在 ...

  2. CVE-2018-0802:Microsoft office 公式编辑器 font name 字段二次溢出漏洞调试分析

    \x01 前言 CVE-2018-0802 是继 CVE-2017-11882 发现的又一个关于 font name 字段的溢出漏洞,又称之为 "第二代噩梦公式",巧合的是两个漏洞 ...

  3. CVE-2013-0077:Microsoft DirectShow quartz.dll m2p 文件堆溢出漏洞简单分析

    0x01 前言 2012 年 10 月 5 日,exploit-db 漏洞公布站点上发布了 QQplayer.exe 3.7.892 m2p quartz.dll Heap Pointer OverW ...

  4. CVE-2012-0158:Microsoft Office MSCOMCTL.ocx 栈溢出漏洞调试分析

    0x01 Lotus Blossom 行动 在 2015 年 6 月,国外安全厂商 Palo Alto Networks 的威胁情报团队 Unit42 发现了一起针对东南亚政府的一次间谍行为,试图获取 ...

  5. Samba ‘dcerpc_read_ncacn_packet_done’函数缓冲区溢出漏洞

    漏洞名称: Samba ‘dcerpc_read_ncacn_packet_done’函数缓冲区溢出漏洞 CNNVD编号: CNNVD-201312-169 发布时间: 2013-12-12 更新时间 ...

  6. Linux kernel ‘qeth_snmp_command’函数缓冲区溢出漏洞

    漏洞名称: Linux kernel ‘qeth_snmp_command’函数缓冲区溢出漏洞 CNNVD编号: CNNVD-201311-423 发布时间: 2013-11-29 更新时间: 201 ...

  7. Linux kernel ‘xfs_attrlist_by_handle()’函数缓冲区溢出漏洞

    漏洞名称: Linux kernel ‘xfs_attrlist_by_handle()’函数缓冲区溢出漏洞 CNNVD编号: CNNVD-201311-392 发布时间: 2013-11-29 更新 ...

  8. Linux kernel ‘uio_mmap_physical’函数缓冲区溢出漏洞

    漏洞名称: Linux kernel ‘uio_mmap_physical’函数缓冲区溢出漏洞 CNNVD编号: CNNVD-201311-154 发布时间: 2013-11-13 更新时间: 201 ...

  9. Apache mod_fcgid fcgid_header_bucket_read函数缓冲区溢出漏洞

    漏洞名称: Apache mod_fcgid fcgid_header_bucket_read函数缓冲区溢出漏洞 CNNVD编号: CNNVD-201310-455 发布时间: 2013-10-21 ...

随机推荐

  1. 记一次Drone无法触发构建的问题

    问题 好巧不巧,当你晚上准备上线的时候,在下午临近下班的时候CI&CD工具出问题了,提交代码不能触发构建,不能上线了,Drone平台那边也下班了,正好CICD依赖的公司git仓库也出问题了(就 ...

  2. P2014 选课 题解(树形DP)

    题目链接 P2014 选课 解题思路 树形动归,用\(f[i][j]\)表示以\(i\)为根,\(j\)个子节点(不包括自己)的最大学分 首先根据题意建图,用根节点\(0\)将森林连成树. 从根节点开 ...

  3. python 实现输出一个等腰三角形

    这个问题实际上是一个数学问题,我们主要找出每行的规律就可以根据规律来书写代码 """ 2 代码实现输出一个等腰三角形,实际上就是一个等差数列求各项的一个数学> 问题 ...

  4. MyEclipse安装过程

    1.安装JDK并配置环境变量 下载地址: https://www.oracle.com/technetwork/java/javase/downloads/index.html ①点击download ...

  5. PTA 中序输出度为2的结点

    6-10 中序输出度为2的结点 (10 分)   本题要求实现一个函数,按照中序遍历的顺序输出给定二叉树中度为2的结点. 函数接口定义: void InorderPrintNodes( BiTree ...

  6. 3、Spring教程之IOC创建对象方式

    1.通过无参构造方法来创建 1.User.java public class User { private String name; public User() { System.out.printl ...

  7. 清明|TcaplusDB持续为您保驾护航

    清明将至,又到一年休闲踏青,祭拜祖先的时机. 清明假期期间,TcaplusDB不停歇,我们将一如既往地守护您的数据,继续做您最坚实的后盾.  在未来,TcaplusDB还将以国产键值型数据库领航者的身 ...

  8. ELK查询命令详解总结

    目录 ELK查询命令详解 倒排索引 倒排索引原理 分词器介绍及内置分词器 使用ElasticSearch API 实现CRUD 批量获取文档 使用Bulk API 实现批量操作 版本控制 什么是Map ...

  9. Istio安全-证书管理(实操一)

    Istio安全-证书管理 目录 Istio安全-证书管理 插入现有CA证书 插入现有证书和密钥 部署Istio 配置示例services 校验证书 卸载 Istio的DNS证书管理 DNS证书的提供和 ...

  10. 201871010129-郑文潇 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    项目 内容 课程班级博客 https://edu.cnblogs.com/campus/xbsf/2018CST 这个作业要求链接 https://www.cnblogs.com/nwnu-daizh ...