漏洞报告者
Zhou Aiting(@zhouat1) of Qihoo 360 Vulcan Team
1. 漏洞描述
漏洞编号:CVE-2018-6120
影响版本:Chrome Version < 66.0.3359.170
2. 漏洞分析
2.1 漏洞类型
运行poc文件,获取崩溃信息栈:
图一
2.2 漏洞成因
1)崩溃点对应的代码如图二所示:
由于 m_nOrigOutputs 的值超出数组申请空间范围,图二代码行 #55 处赋值时将造成越界写。
2) 数组声明及分配的大小:
调试器结合崩溃的函数栈,可以定位到如下信息:数组的大小由以下函数的返回值决定。
3. 漏洞利用
由于相关变量(m_nOrigOutputs、m_Exponent)可以在 pdf 文件通过控制相应的域进行精确控制,我们可以对下面的赋值操作语句进行精简。控制 m_Exponent=0 , 则 FXSYS_pow(input[i], m_Exponent) 始终为1。
图五
而 m_pEndValues 的值来自 pdf 文件的可控内容,漏洞利用变得简单。
4. 效果演示
5. 漏洞修复
使用 FX_SAFE_UINT32 代替之前的 uint32_t,内存中表现为: 高四个字节是unsigned int的值,低四个字节保存数据溢出标识。
图十
由于重载了运算符,在进行该类型的数值计算时,会自动检查溢出,确保不会发生上溢和下溢。具体的检查方法是使用编译器内置的溢出检测函数__builtin_add_overflow。发生溢出后,原本 result_array 所在的函数直接 return。(见图十一)
6. 再次突破
影响版本:Chrome Version < 67.0.3396.99
在官方修复 CVE-2018-6120 后,我们关注到一个这样的数据类型: CFX_FixedBufGrow<float, 16>,它的构造函数见图十二:
CFX_FixedBufGrow<float, 16> result_array(total_results) 的逻辑:
(1)当需要的空间不大于16时,开辟16个float类型的栈空间;
(2)否则使用参数(total_results)在堆上开辟一片内存。
问题在于,此处传入的实参是 unsigned int, 而形参却是 int 。CVE-2018-6120 越界写漏洞可以再次被触发 🙂
由于最新稳定版本中,此章节介绍的利用方式已经不可用,我们遂决定将细节在此公开。
7. 文末彩蛋
More than three years of functional discussion once again accidentally killed the bug.
Chrome 上个月的一次非安全更新,意外地导致我们#6中的越界写漏洞不再可用。其原因是:一系列性能测试通过后,Chrome 移除了 CFX_FixedBufGrow类型,使用 vector 代替。更多信息,请参考文末的 链接 。
nice work, Google Chrome Team 🙂
图十三