MS09-019漏洞深度解析:IE8的"pwn2own"漏洞技术细节

本文详细分析了CVE-2009-1532漏洞的技术原理,包括IE8中对象删除后使用(UAF)漏洞的代码级分析,DEP/ASLR绕过机制,以及安全区域配置对.NET程序集加载的影响,并提供了注册表修改建议和长期解决方案。

MS09-019 (CVE-2009-1532): “pwn2own"漏洞分析

IE8行为说明

MS09-019包含了针对Nils在CanSecWest pwn2own竞赛中负责任披露的IE8漏洞修复(CVE-2009-1532)。

Nils利用此漏洞的IE8版本允许在Internet区域加载.NET程序集。最终发布的IE8版本不允许在Internet区域加载.NET程序集。IE8对.NET程序集的行为很重要,因为Dowd/Sotirov的ASLR+DEP绕过[DowdSotirov08]需要.NET将shellcode放置在具有正确页面权限的已知位置。我们在三月份发布了关于此绕过的博客文章。

我们不期望在Vista或更高版本上看到此漏洞被利用,因为(a)发布的IE8版本不允许从Internet区域加载.NET程序集,以及(b)IE8默认启用DEP。

您可以更改IE8在不同区域加载.NET程序集的行为。默认情况下,不允许在Internet区域加载,但允许在Intranet区域加载。如果您想在Intranet区域禁用.NET程序集,请将此注册表项设置为3(禁用):

1
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1\2005

如果您希望允许IE8在Internet区域加载.NET程序集,可以将此注册表项更改为0(启用):

1
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3\2005

如上所述,如果您需要重新启用IE8在Internet区域加载.NET程序集,我们建议您仅将其作为短期解决方案,因为它会暴露攻击面。如果您使用需要在Internet区域使用.NET的应用程序,我们建议您将其迁移到ClickOnce部署或Windows Presentation Foundation(WPF)。

漏洞技术细节

此漏洞的根本原因是删除对象后继续使用该对象(EIP指向堆)。由于未能检查错误代码,我们最终调用了这个已经释放的对象。

让我们关注以下代码片段来理解错误代码检查失败:

 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
HRESULT CElementCollectionBase::VersionedGetDispID(BSTR bstrName, DWORD grfdex, __out DISPID *pdispidMember, __in IUnknown *pUnkContext, OMVersion version, OMVersionFlag versionFlags, __in PFNGETDISPID *pfnTearoffGetDispID)
{
    HRESULT hr = S_OK;

    if (!SecurityContextAllowsAccess())
        return E_ACCESSDENIED;

    hr = THR(_pCollectionCache->EnsureAry(_lIndex)); // 由于各种原因,hr将为FALSE,因为对象不可用
                                                     // 请注意S_FALSE = 1 而 FALSE = 0

    if (hr)                                          // 但是我们检查是否为S_FALSE=1
       goto Cleanup;                                 // 我们继续执行而不直接转到清理部分

    hr = DispatchGetDispIDCollection(this,
                                     NULL,
                                     _pCollectionCache,
                                     _lIndex,
                                     bstrName,
                                     grfdex,
                                     pdispidMember);

    // 我们传入NULL,然后在版本化方式中自行处理
    if ( hr || (!hr && *pdispidMember == DISPID_UNKNOWN) )
    {
        hr = super::VersionedGetDispID(bstrName, grfdex, pdispidMember, pUnkContext, version, versionFlags, NULL);
    }

Cleanup:
    RRETURN(hr);
}

当对象不再可用时,IE7在上述调用中返回S_FALSE(1)而不是FALSE(0)。使用S_FALSE,IE7正确进入清理代码而不引用此已删除的对象,因此不受影响。

为了清理类似问题的区域,我们开发了一些静态分析工具来检测这种错误检查失败(S_FALSE != FALSE)。这些分析工具将包含在未来不同产品版本的安全测试阶段中,这样我们就不会再犯同样的错误。

参考文献:[DowdSotirov08] Bypassing browser memory protections in Windows Vista, Alexander Sotirov and Mark Dowd

Fermin J. Serna and Chengyun, MSRC Engineering 发布内容"按原样"提供,不提供任何保证,也不授予任何权利。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计