安全路透社
当前位置:安全路透社 > 网络转载 > 正文

一个冷门类型混淆漏洞CVE-2017-0213的技术分析

1.   引言

CVE-2017-0213 是一个比较冷门的COM 类型混淆 (Type Confusion)漏洞。巧妙的利用该漏洞,可以实现本地的提权。该漏洞由著名的Google Project zero 发现。漏洞信息原文可参见【1】

然而原文对漏洞的描述有些过于任性,尽管笔者熟悉好几国英文J,反复读了好几遍还是觉得云山雾罩。因此决定亲自分析下,和读者共同分享一下。

2.   技术分析

2.1 DCOM 简介

这个漏洞要从DCOM 谈起了。相信大家对Windows的组件对象模型(COM) 都已经非常熟悉了。而DCOM可能相对来说要陌生一些。DCOM是 分布式的COM, 类似于CORBA, 也就是说调用的COM 可以在远程主机上。

DCOM的详细信息可参见

https://msdn.microsoft.com/en-us/library/cc226801.aspx

在COM模型中,我们知道所有的COM 接口都要继承 IUnkown 接口。通过QueryInterface函数,可以查询任意接口。

而在DCOM模型中,对应于IUnknown的接口为IRemunkown 和IRemUnkown2 两个远程接口。

相应的,QueryInterface对应的方法为:

IRemUnknown::RemQueryInterface([in] REFIPIDripid,

  [in] unsigned long cRefs,

  [in] unsigned short cIids,

  [in, size_is(cIids)] IID* iids,

  [out, size_is(,cIids)] PREMQIRESULT* ppQIResults

)

IRemUnknown2::RemQueryInterface2([in]REFIPID ripid,

  [in] unsigned short cIids,

  [in, size_is(cIids)] IID* iids,

  [out, size_is(cIids)] HRESULT* phr,

  [out, size_is(cIids)] PMInterfacePointerInternal* ppMIF

)

两者的主要区别在于返回的对象类型上。

IRemUnknown::RemQueryInterface 通过最后一个参数[out,size_is(,cIids)] PREMQIRESULT* ppQIResults 来返回对象。

看一下PREMQIRESULT的定义

typedef struct tagREMQIRESULT {

   HRESULT hResult;

   STDOBJREF std;

 } REMQIRESULT;

typedef [disable_consistency_check]REMQIRESULT* PREMQIRESULT

STDOBJREF 通常包含OXID,IPID, OID 这些信息。

IRemUnknown2::RemQueryInterface2

通过最后又一个参数PMInterfacePointerInternal 来返回对象.

而 PMInterfacePointerInternal  的定义

 typedef [disable_consistency_check]MInterfacePointer* PMInterfacePointerInternal;

根据MSDN的解释 (https://msdn.microsoft.com/en-us/library/cc226826.aspx)  

MInterfacePointer is an NDR-marshaled structure that MUST contain a hand-marshaled OBJREF.

MInterfacePointer是一个NDR装组(marshal)的对象引用。

不难看出,IRemUnknown::RemQueryInterface 只是返回了对象的部分信息,而IRemUnknown2::RemQueryInterface2返回了整个对象的信息。

2.2 漏洞分析

CVE-2017-0213的问题出现在 IRemUnknown2::RemQueryInterface2的 代码中

代码调用CStdMarshal::Finish_RemQIAndUnmarshal2来完成对返回对象解组(Unmarshal)

对于每一个MInterfacePointer指针,函数 CStdMarshal::UnmarshalInterface 对其进行解组,即从 IStream的数据中解组出相应的接口。问题出现在这里 ,解组的时候,解组代理是根据IStreamde数据中的OBJREF(IID) 来解组的,而并非 IRemUnknown2::RemQueryInterface2 中指定的 IID 。也就是说,这里没有对OBJREF IID IRemUnknown2::RemQueryInterface2中指定的IID 进行一致性检查。,如果在 IStream中的IID 和调用 IRemUnknown2::RemQueryInterface2 时指定的IID 不一致的时候,就会发生类型混淆。

2.3  漏洞利用

类型混淆的漏洞通常可以通过内存损坏的方式来进行利用.然而漏洞发现者在利用时并未采用内存损坏的方式来进行漏洞利用。按照漏洞发现者的说法内存损坏的利用方式需要对内存进行精心布局,即便如此 ,在Windows 10上也可能会触发CFG(Control Flow Guard)。

漏洞发现者另辟其径,采用了一种基于LoadTypeLibrary来利用的方法。

背景知识:

如果将COM 接口注册PSOAInterface或者PSDispatch后,oleaut32.dll 会查找注册的Type Library信息(存放在注册表中),如果找到的话,将调用LoadTypeLibrary 来加载 Type Library. TypeLibrary在加载的时候,有个很有趣的行为:  首先会按GUID查找,如果查找失败的话,会按文件名来查找。如果按文件名查找也失败的话,这时会按照Moniker 来查找。这时,我们只需将包含scriptlet的Moniker注入到一个Type Library 文件中。就可以执行这段scriptlet。漏洞发现者采用的ScriptLet如下图所示。

 一个冷门类型混淆漏洞CVE-2017-0213的技术分析

现在我们知道,可以利用这个漏洞来成功加载JS, 从而达到执行任意文件的目的。

那么如何来利用这个漏洞来进行提权呢?  我们注意到,BITS 服务运行在 SYSTEM 完整性等级(IntegrityLevel)上如果调用其

IBackgroundCopyJob::SetNotifyInterface(IUnknown *pNotifyInterface)

并传入一个精心构造的COM 接口,引发类型混淆,便可利用该漏洞来加载一个TypeLibrary 这里,漏洞利用程序选择了COM 接口 IID_ITMediaControl(GUID {C445DDE8-5199-4BC7-9807-5FFB92E42E09}),其TypeLibGUID为 {21D6D480-A88B-11D0-83DD-00AA003CCABD}, 注册的DLL为 tapi3.dll。那么如何才能达到加载自己定义的tapi3.dll的目的呢?Tapi3.dll位于 %system32%目录下,覆盖此文件显然不可能。漏洞利用程序使用了这样一个技巧:利用NtCreateSymbolicLink重定向C:\ 到当前目录 在当前目录下创建windows\system32\tapi3.dll即可。具体过程可参见漏洞利用源代码【2

最后上一张成功利用的截图。Windows 7 SP1 下成功弹出一个admin权限的cmd窗口。

一个冷门类型混淆漏洞CVE-2017-0213的技术分析

3.   总结

“天下漏洞,唯冷不破”。CVE-2017-0213的无论从挖掘和利用,感觉都有些剑走偏锋,正属于这种比较冷门的一类。这种漏洞似乎难以通过fuzzing的方式来发现。通常这种漏洞的发现,需要对Windows的代码非常熟悉。而从漏洞的利用的角度来看,思路亦是非常巧妙。从这个漏洞的发现到利用,可见漏洞发现者在Windows 操作系统方面的造诣非同一般。

4.   参考文献

1.  https://bugs.chromium.org/p/project-zero/issues/detail?id=1107

2.  https://github.com/WindowsExploits/Exploits/blob/master/CVE-2017-0213/Source/CVE-2017-0213.cpp

*本文作者:兰云科技银河实验室,转子请注明来自 FreeBuf.COM

未经允许不得转载:安全路透社 » 一个冷门类型混淆漏洞CVE-2017-0213的技术分析

赞 (0)
分享到:更多 ()

评论 0

评论前必须登录!

登陆 注册