CVE-2011-0065-Firefox 3.6.16 mChannel 释放重引用漏洞

环境

win7 32
windbg

漏洞分析

先开启hpa,再打开poc

1
2
3
4
C:\Program Files\Debugging Tools for Windows (x86)>gflags.exe /i "C:\Program Files\Mozilla Firefox\f
irefox.exe" +hpa
Current Registry Settings for firefox.exe executable are: 02000000
hpa - Enable page heap

打开后崩溃信息如下

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
0:000> g
(918.be8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=07b43210 ebx=05a966c4 ecx=0a54f800 edx=07c83910 esi=804b0002 edi=80000000
eip=07289634 esp=003cf07c ebp=003cf28c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
07289634 2001 and byte ptr [ecx],al ds:0023:0a54f800=50
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Mozilla Firefox\xul.dll -
0:000> kv
ChildEBP RetAddr Args to Child
WARNING: Frame IP not in any known module. Following frames may be wrong.
003cf078 645a4e75 07b43210 804b0002 00000000 0x7289634
003cf28c 645a5659 05a966c4 079acab0 00000001 xul!gfxFontUtils::ReadNames+0x14735
003cf2bc 645a6155 05a966c4 003cf374 00000001 xul!gfxFontUtils::ReadNames+0x14f19
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Mozilla Firefox\nspr4.dll -
003cf428 6b07d120 20a8e5d0 00360e14 0000000a xul!gfxFontUtils::ReadNames+0x15a15
003cf460 645a61a3 05a966a0 00000001 63e62902 nspr4!PR_Now+0x40
003cf46c 63e62902 00000001 09c07540 073f3700 xul!gfxFontUtils::ReadNames+0x15a63
003cf488 63e621d2 00000048 00000000 00000000 xul!gfxMatrix::HasNonTranslation+0x2c52
00000000 00000000 00000000 00000000 00000000 xul!gfxMatrix::HasNonTranslation+0x2522
0:000> ub 645a4e75
xul!gfxFontUtils::ReadNames+0x1471f:
645a4e5f 8bce mov ecx,esi
645a4e61 e81a6991ff call xul!NS_CycleCollectorSuspect2_P+0x2a0 (63ebb780)
645a4e66 8b4350 mov eax,dword ptr [ebx+50h]
645a4e69 8b08 mov ecx,dword ptr [eax]
645a4e6b be02004b80 mov esi,804B0002h
645a4e70 56 push esi
645a4e71 50 push eax
645a4e72 ff5118 call dword ptr [ecx+18h]

可以看到上层调用基本是一个虚函数调用,很有可能是一个uaf漏洞

不知道为何我这配置好后下载不了firefox的符号,还是比较头疼

所以我并不能像作者那样这么愉快地详细分析了

只能看源码(https://hg.mozilla.org/releases/mozilla-1.9.2/rev/c24f21581d77)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -1010,18 +1010,19 @@ nsObjectLoadingContent::GetInterface(con
}

// nsIChannelEventSink
NS_IMETHODIMP
nsObjectLoadingContent::OnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
PRUint32 aFlags)
{
- // If we're already busy with a new load, cancel the redirect
- if (aOldChannel != mChannel) {
+ // If we're already busy with a new load, or have no load at all,
+ // cancel the redirect.
+ if (!mChannel || aOldChannel != mChannel) {
return NS_BINDING_ABORTED;
}

if (mClassifier) {
mClassifier->OnRedirect(aOldChannel, aNewChannel);
}

mChannel = aNewChannel;

修补方式是增加了对mChannel的判断,如果为空指针就return了

如果不return下面会对mChannel赋值,由于aNewChannel不再使用,所以会free掉,即mChannel会被free掉,

1
mChannel = aNewChannel;

再次引用,那么就会崩溃了

具体在nsObjectLoadingContent::LoadObject里面引用(1192行:https://hg.mozilla.org/releases/mozilla-1.9.2/file/c24f21581d77/content/base/src/nsObjectLoadingContent.cpp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// From here on, we will always change the content. This means that a
// possibly-loading channel should be aborted.
if (mChannel) {
LOG(("OBJLC [%p]: Cancelling existing load\n", this));

if (mClassifier) {
mClassifier->Cancel();
mClassifier = nsnull;
}

// These three statements are carefully ordered:
// - onStopRequest should get a channel whose status is the same as the
// status argument
// - onStopRequest must get a non-null channel
mChannel->Cancel(NS_BINDING_ABORTED);
if (mFinalListener) {
// NOTE: Since mFinalListener is only set in onStartRequest, which takes
// care of calling mFinalListener->OnStartRequest, mFinalListener is only
// non-null here if onStartRequest was already called.
mFinalListener->OnStopRequest(mChannel, nsnull, NS_BINDING_ABORTED);
mFinalListener = nsnull;
}
mChannel = nsnull;
}

reference

《漏洞战争》

自愿打赏专区