试想:某一天,你的基友给你了一个视频文件,号称是陈老师拍的苍老师的老师题材的最新电影.avi,你满心欢喜,在确定文件格式确实为avi格式后,愉快的脱下裤子准备欣赏,打开后却发现什么也没有,而随后你的基友就控制了你的电脑,把你辛辛苦苦珍藏了二十年的片源全部偷走了…….
本文作者:i春秋作家——降草
今天我们分析的漏洞就是一个利用播放器解压缩时处理不当引起的远程执行漏洞,这个漏洞并没有大规模流行,我们只是从技术角度解析漏洞成因。
0x 00漏洞介绍
CVE 2010-2553漏洞,也称为MicrosoftWindows Cinepak 编码解码器解压缩漏洞,影响的操作系统版本有:Microsoft Windows XP SP2和SP3,WindowsVista SP1和SP2,以及Windows 7。
漏洞原因在于Cinepak 编码解码器对媒体文件解压缩时代码控制不恰当,可导致远程代码执行。如果用户打开特制的媒体文件,此漏洞可能允许执行代码。如果用户使用管理用户权限登录,成功利用此漏洞的攻击者便可完全控制受影响的系统。
漏洞利用wmplay.exe,而wmplay.exe这个播放器在国内很少有人使用,如果被攻击者使用了第三方的视频播放软件,很难攻击成功,这可能也是这一漏洞不被分析重视的一大原因。
0x 01漏洞触发
本文分析环境如下:
操作系统 | Xp sp3 |
---|---|
iccvid.dll版本 | 1.10.0.12 |
通过在exploit-db网站上得到触发漏洞的python脚本,运行python脚本后,生成可触发漏洞的poc.avi,这就是我们分析的样本文件。(python脚本在文末的附件中)
通过公告可知,这个漏洞是个堆溢出漏洞,在分析堆漏洞时,肯定是hpa + ust大法好。所以,首先我们要开启hpa、ust
使用windbg加载wmplay.exe,使用g命令,运行wmplay.exe
将poc.avi拖入wmplay中,windbg会触发异常
通过崩溃信息猜测是堆中的内存被破坏了,我们看下edi的值,并看下这个值是不是堆地址
可以看到堆底地址为: 76ad000+600=76b3000,这个地址也正好是edi的地址,这正是由于我们使用glags.exe开启了页堆检查,堆管理器会在堆块中增加不可访问的栅栏页,当溢出覆盖到栅栏页时就触发了异常。
崩溃的指令为rep movs指令,我们看下此时movs的内存大小保存在ecx,内存大小为:
只能知道此时,是因为向edi中拷贝800大小字节的内容时,导致了堆溢出。
在rep movs这条指令的上一条指令下断,重新运行
bu iccvid!CVDecompress+0×118:
第一次断下后,查看edi,ecx的值:
走过rep movs指令后,此时并没有崩溃,这就说明,并不是一次rep movs就导致了堆溢出,而是通过多次运行rep movs指令,逐渐到到达堆尾,然后就溢出了。。。。
第二次断下的,
第二次调用rep movs时,还是没有到达堆尾,还没有溢出
第三次断下时,
这时,可以看到,edi=76b3000, 76b3000这个就是我们在一开始崩溃的地方啊!!!
在这里,可以看下esi的值
可以看到,现在用来覆盖目标地址的数据并不直接就是我们在poc.avi中填充的数据,而是一些不知来自何处去向哪里的数据。这点就造成了我们对这个漏洞的利用不能向cve 2010 0158之类的漏洞利用一样通过修改文件内容即可实现覆盖。
0x 02 漏洞分析
定位函数
现在我们就定位到漏洞所在的函数,然后通过ida分析漏洞所在函数的功能。
在崩溃位置通过kb进行栈回溯来定位所在的函数
我们so easy的就把漏洞所在的函数找到了,这个函数就是iccvid!CVDecompress函数。
使用IDA查看iccvid.dll文件,找到函数73b7cbee,发现ida并不能识别出函数为CVDecompress函数,纳尼??这一定是在逗我
这是因为IDA没有找到pdb文件,但是我们windbg却找到了pdb文件,我们将windbg的pdb文件拷贝出来,
在windbg中查看pdb文件路径
使用ida file — load file —pdb file选择pdb文件路径,就可以在ida中看到函数名称了。
效果如图
分析函数在函数73B7CAD6头下断点后,重新加载程序,断下后,可以看到CVDecompress函数有七个参数:
还记得上面分析的rep movs指令吗?调用它第三次后就会崩溃,而第一次调用这条指令时的edi的值为076af000,这个076af000是什么鬼呢?来自于哪里呢?
答案就是它是CVDecompress函数的从第一个参数,偏移1c的值(076ad000)加上2000后得到的……
CVDecompress函数的第三个参数68,代表了未解压的数据长度。
这个函数首先会对cinepak的压缩格式结构进行判断,随后会按照cinepak压缩格式解析结构。
Cinepak 压缩格式的总体框架如下:
+———————–+
| Frame Header |
+———————–+
| Strip 1 Header |
+———————–+
| Strip 1 Codebooks |
+———————–+
| Strip 1 Frame Vectors |
+———————–+
| Strip 2 Header |
+———————–+
| Strip 2 Codebooks |
+———————–+
| Strip 2 Frame Vectors |
+———————–+
| Strip 3 Header |
其中 Frame Header的结构如下:
7 6 5 4 3 2 1 0 Field Name Type
+—————+
0 | | | Flags Byte
+—————+
1 | | Length of CVID data Unsigned
+- -+
2 | |
+- -+
3 | |
+—————+
4 | | Width of coded frame Unsigned
+- -+
5 | |
+—————+
6 | | Height of coded frame Unsigned
+- -+
7 | |
+—————+
8 | | Number of coded strips Unsigned
+- -+
9 | |
+—————+
函数首先判断未解压缩的数据长度是不是小于20H大小
再判断未解压缩的数据长度是不是小于FrameHeader中的数据长度
比较Frame Header中的Number of coded strips是不是小于0
然后就会对每个strip进行遍历,以下都是在对每个strip的处理中
对未解压的数据大小做比较
对编码条数据大小做判断
判断编码条ID为10还是11:
对strip header中的底部Y坐标与顶部Y坐标做差,结果乘以一个数后存储起来。
当strip header中的编码条ID为10时,会向堆中拷贝数据。
最后,会指向下一个stripHeader结构。上面这些是对每个strip的处理
结合poc.avi的内容,与上面IDA中的结果
每次当解析到chunkID为20时,此时,不会向堆里覆盖内容,当解析到chunkid=0×1100时,就会向堆数据中复制数据。
因为poc.avi中有三处chunkid为11的数据块,因此向堆中复制了三次数据,而正是第三次复制时,使堆溢出而崩溃。
0x 04 漏洞利用
在metasploit
平台中暂时没有该漏洞利用的相关模块,在互联网搜索引擎中也暂未找到相关利用样本。本人感觉这个漏洞利用最大的难点在于,拷贝时触发堆溢出时,拷贝的内容很难通过文件内容进行控制,因而无法很好的控制EIP指针,无法精准的执行payload。怎样精准的控制esi中的内容,是我以后将在研究学习的内容。本文不再深入。
附件:链接:http://pan.baidu.com/s/1bLLx98 密码:mlbj
0x 05 参考资料
http://www.cvedetails.com/cve/CVE-2010-2553/
https://technet.microsoft.com/library/security/ms10-055
http://www.cnblogs.com/Ox9A82/p/5715673.html
http://cve.scap.org.cn/CVE-2010-2553.html
https://www.exploit-db.com/moaub-26-microsoft-cinepak-codec-cvdecompress-heap-overflow-ms10-055/
http://multimedia.cx/mirror/cinepak.txt
《漏洞战争》83页-90页