如何实现微软“照片”应用Raw 格式图像编码器漏洞 CVE-2021-24091的技术分析
如何实现微软"照片"应用Raw 格式图像编码器漏洞 CVE-2021-24091的技术分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
前言
2020年12月和2021年2月,微软两次针对"照片"应用的Raw格式图像编码器发布安全更新,其中2月9日修复的是CVE-2021-24091。笔者从事文件格式方面的安全研究工作,找到研究人员提供的poc 后,对该漏洞进行了漏洞验证和分析。
根据MSRC 和漏洞发现者公开的信息,该漏洞存在于Windows Imaging Component解码Olympus E300 相机拍摄的原始图像的相关函数中。由于互联网并没有过多公开资源介绍 E300 RAW 格式(笔者仅找到一份公开资料,见https://myolympus.org/E300/#RAW),所以本文将从漏洞产生机制的角度,分析漏洞产生的原因。
0x00 漏洞验证
1、在Win10 1903 x64系统上,使用gflags工具为图片app开启页堆,双击图片文件打开(图片默认应用为照片App)。一段时间后,App退出进程。
2、使用Windbg附加照片App(Windbg 调试UWP方法详见微软文档),敲击g运行程序。一段时间后,进程崩溃。如下图所示:
0x01 漏洞分析
使用ida pro 加载崩溃的dll,可以确认崩溃发生在一个将数据写入缓冲区的循环之中。
通过这段代码,可初步大致判断循环体条件语句导致循环次数过多,造成越界写入。函数部分变量的初始化如下:
结合函数开始时局部变量的初始化和变量交叉引用的情况来看,可以得出:
1、代码通过读取某个类型对象的成员值,并加以运算,计算结果即为需要申请的缓冲区的大小;
2、缓冲区分为两部分,一部分为size 为*(this+12320*4) * 2的数据块(chunk2)另一部分数据块(chunk1)的大小为*(this+0x12320*4) * 16 / 10个字节。
3、执行初始化后,代码首先执行一个for循环,在这个循环体的内部执行另一个for循环,向chunk2内写入数据。
所以,这段代码的伪代码如下:
chunk2_size = this->mem_12320;chunk1_size = chunk2_size * 16 / 10;char * data = (char *)malloc(chunk1_size + 2 * chunk2_size);for (char *i = data+chunk1_size; v12 < this->mem_12325; a5 = v12){…expresions;…for (char *pdata = data, char *j = i; j < chunk+chunk1_size+2*chunk2_size; pdata += 3, j += 4){if ((pdata - data) ) pdata++;*(word *)j = pdata[1] << 8 | pdata[0]; //写入两个字节*(word *)(j+1) = pdata[2] << 4 | pdata[1] >> 4; //写入两个字节 }…expressions;…}
按照上面的伪代码,每次循环都写入四个字节,循环次数应该是(chunk2_size * 2 / 4)向上取整的值。在第一个for循环中,当 i = &data[chunk1_size],即从第二个chunk头部开始循环写入字节时,如果chunk2_size为奇数,循环次数 * 4 将大于chunk2_size。也就是说,最后一次循环中,写入后两个字节时,将造成越界,产生访问违例。
0x02 漏洞调试
使用windbg 附加App进程,并在崩溃函数设置断点:
bu WindowsCodecsRaw!COlympusE300LoadRaw::olympus_e300_load_raw
图片App 加载poc 文件时,获取的chunk2_size为0xd79,是一个奇数。
通过上文的伪代码可得:
chunk1_size = 0x158e
data 指向的内存区域是一个大小为0x3080的缓冲区。
代码执行到第二个for循环时,需要写入数据的指针存放在r15中,即为chunk2 缓冲区的起始地址(r15 == data + chunk1_size):
所以,在这种情况下,循环次数应为⌈ (0xd79 * 2 / 4) ⌉,即为1725 次。而缓冲区只有2 * chunk2_size, 共6898个字节,不能支持1725*4 = 6900个字节的写入。由此可知,最后一次循环将产生两个字节的越界。至此,漏洞分析完毕。
循环次数记录如下:共命中725次,与分析无误。
0x03 关于这段代码的来源
该漏洞的发现者提到:通过函数名查找,这段代码与LibRaw Lite库的同名函数有较大的相似性,但是这个库目前已经停止维护和更新了,源代码下载地址失效,所以笔者在github上找到了类似的代码片段。(https://github.com/coolshou/DIR-850L_A1/blob/92b64054ac75795429b9a6678baef5b3e69dfc10/progs.gpl/image_tools/netpbm-10.35.81/converter/other/cameratopam/camera.c)
对比可知,这段代码与漏洞函数在实现上基本一致,所以微软的代码应该是在此基础上重新实现了一遍。
因此,基于代码供应链安全的考量,建议使用LibRaw Lite 库函数的代码,由相关人员自行更新补丁。
0x04 微软代码补丁
微软官方在2月9日推出的补丁内容如下:
这个补丁比较简单粗暴,即:复制第二个像素(第二次写入双字节)时,判断指针是否指向缓冲区末端。
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注行业资讯频道,感谢您对的支持。