-
-
[原创]借鉴CVE-2017-0213思路,挖掘到另外一种方法成功获取到System的Token,新的0day
-
发表于: 2018-3-16 19:01 5690
-
我讲一下我的实现思路, 在打满所有补丁的server2008或win7下情况下IBackgroundCopyJob->SetNotifyInterface根据CVE-2017-0213的原理会加载一个指定com组件的typelib(以sysytem权限),可以指定任意typlelib然后bits服务调用loadregtypelib这个ole32下函数,然后loadregtypelib会把com组件的typelib中指定的文件名作为一个filemoniker解析(调用),因为文件被锁定了(见使用方法),所以它loadregtypelib调用mkpaersedisplayname来createfilemoniker失败,同时我在poc中实现了一个和这个filemoniker相同displaynmame的moniker并在Running Object Table注册一个自定义的typelib,所以mkpaersedisplayname失败后会把在Running Object Table注册的moniker指定的typlelib对象(可以是任意对象)作为filemoniker应该调用bindtoobject返回的对象(也就是替换),然后bits服务会调用这个指定的typlelib对象上的一些方法,这个时候在我的typlelib上调用coimpersonateclient返回的token就是system的,和截图一样,但是这个token模拟级别是SecurityIdentification类型的无法创建新进程无法操作文件(返回1346错误),另外说一点,我分析到是,通过修改注册表中typelib对于的文件名路径,如果bits服务调用loadregtypelib对应typelib指定的文件名是一个scrptletmoniker是可以直接启动一个system的cmd.exe,问题是注册表非管理员无法修改,这个只是验证说明调用方确实是system的bits服务,暂时得出的结论是如果bits服务调用loadregtypelib返回的scrptletmoniker是在他自己本身内部实现的所以启动cmd.exe是可行的,
,我认识到了SecurityIdentification模拟等级的token利用的相关知识,另外一种利用方式是在调用方发起一个导致代码执行的反序列化,我通过逆向ole32的代码发现确实有类似回调对象的东西,有关微软官方文档59dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7$3c8F1i4K6u0W2L8h3W2U0M7X3!0K6L8$3k6@1i4K6u0W2j5$3!0E0i4K6u0r3k6h3&6Q4x3X3c8#2M7#2)9J5c8X3I4A6j5Y4u0S2M7Y4W2Q4x3V1k6%4K9h3&6V1L8%4N6K6i4K6u0r3k6r3g2K6K9%4c8G2M7q4)9J5c8X3#2K6y4U0R3$3y4U0t1^5i4K6t1^5N6W2)9K6c8s2k6K6i4K6u0W2z5o6g2Q4x3U0W2Q4x3X3g2S2M7%4m8^5i4@1f1#2i4K6R3#2i4@1t1$3i4@1f1@1i4@1t1^5i4@1q4p5i4@1f1^5i4@1q4r3i4@1t1@1i4@1f1#2i4K6R3^5i4@1t1H3d9h3k6Q4x3U0k6F1j5Y4y4H3i4K6y4n7M7X3W2A6k6q4)9J5y4X3&6T1M7%4m8Q4x3@1u0A6M7H3`.`. set to IID_IEnterActivityWithNoLock, the function is executed without an activity lock.是否意味着只要是unmarshal 的objref中可以序列还出来这种类型iid的回调就可以绕过com代理不同套间(apartment)的限制,以下我是逆向ole32的结果,不知道是否有可行性:
HRESULT __stdcall UnmarshalObjRef(tagOBJREF *objref, void **ppv, int fBypassActLock, CStdMarshal **ppStdMarshal)
{
HRESULT v4; // eax
CObjectContext *v5; // eax
tagOBJREF *v7; // edi
HRESULT v8; // esi
CStdMarshal *v9; // esi
CStdIdentity *v10; // eax
void **v11; // edi
tagStdUnmarshalData StdData; // [esp+Ch] [ebp-1Ch]
int fLightNAProxy; // [esp+24h] [ebp-4h]
v7 = objref;
fLightNAProxy = CrossAptRefToNA(objref);
v8 = FindStdMarshal(v7, 0, (CStdMarshal **)&objref, fLightNAProxy);
if ( v8 < 0 )
{
if ( v7->u_objref.u_standard.std.cPublicRefs )
ReleaseMarshalObjRef(v7);
}
else
{
v9 = (CStdMarshal *)objref;
v10 = *(CStdIdentity **)objref->iid.Data4;
StdData.pobjref = v7;
v11 = ppv;
StdData.pStdID = v10;
StdData.ppv = ppv;
StdData.pClientCtx = GetCurrentContext();
if ( ppStdMarshal )
{
*ppStdMarshal = v9;
v9->vfptr->AddRef((IUnknown *)&v9->vfptr);
}
v5 = CStdMarshal::ServerObjectCallable(v9);
if ( v5 )
{
StdData.fCreateWrapper = v11 != 0;
if ( fBypassActLock )
v4 = PerformCallback(v5, UnmarshalSwitch, &StdData, &IID_IEnterActivityWithNoLock, 2u, 0);
else
v4 = PerformCallback(v5, UnmarshalSwitch, &StdData, &IID_IMarshal, 6u, 0);
}
else
{
StdData.fCreateWrapper = fLightNAProxy;
v4 = UnmarshalSwitch(&StdData);
}
v8 = v4;
}
return v8;
}
这个有一个fBypassActLock是安全主体的构造验证
UnmarshalSwitch是可以序列化出来的回掉函数
具体序列还方式 是:
HRESULT __stdcall UnmarshalSwitch(void *pv)
{
void **v1; // eax
int v2; // edi