利用未公开COM接口实现跨会话NTLM中继攻击的技术剖析

本文深入分析了如何通过未公开的IStandardActivator接口结合会话标识符与IStorage激活,实现跨会话DCOM/NTLM中继攻击的技术细节,包括COM激活机制剖析和PoC代码实现原理。

会话0的局限与新攻击思路

近期@decoder_it和@splinter_code披露了新型DCOM/RPC NTLM中继攻击技术:当用户在会话0(如PowerShell远程会话)登录时,调用CoGetInstanceFromIStorage会使DCOM激活器在最低交互会话而非会话0创建对象。初始解组IStorage对象时,系统会使用对应会话的认证用户身份——若该用户是域管理员等特权账户,即可通过中继NTLM认证攻击远程服务器。

此技术的瓶颈在于必须处于会话0环境。虽然非管理员用户可能通过PowerShell远程登录,但相比终端服务器多用户场景,这种机会更罕见。理想方案是能自由选择对象创建会话。

会话标识符的隐藏潜力

系统其实存在跨会话激活机制:会话标识符(session moniker)可激活非会话0的跨会话对象(笔者曾多次利用此特性进行跨会话攻击[1][2][3])。微软始终未修复此非管理员也能使用的激活路径。

但根据文档,会话标识符无法与IStorage激活结合使用——COM API仅允许二选一。深入研究DCOM协议规范后发现,这两者在技术层面是独立的:

  • 会话激活通过SpecialPropertiesData激活属性的dwSessionId字段实现
  • 编组IStorage对象可通过InstanceInfoData激活属性的ifdStg字段传递

理论上可将这些属性打包发送至IRemoteSCMActivator接口的RemoteGetClassObjectRemoteCreateInstance方法,但需验证可行性。

逆向系统原生激活机制

由于直接实现DCOM激活复杂度过高(需NDR编组激活属性且本地激活存在特殊限制),我们转向分析系统现有机制。关键突破口在于观察会话标识符的激活流程:

  1. 解析标识符字符串
    MkParseDisplayName函数调用链中,FindSessionMoniker函数解析"Session:X"格式字符串,创建CSessionMoniker实例:

    1
    2
    3
    4
    5
    6
    7
    
    HRESULT FindSessionMoniker(LPBC pbc, LPCWSTR pszDisplayName, 
                              ULONG *pchEaten, LPMONIKER *ppmk) {
      if (wcsnicmp(pszDisplayName, L"Session:", 8)) 
        return MK_E_UNAVAILABLE;
      // 解析会话ID或Console标识
      *ppmk = new CSessionMoniker(dwSessionId, bConsole);
    }
    
  2. 构建复合标识符
    示例字符串Session:3!clsid:0002DF02-...会生成由会话标识符(会话3)和类标识符(浏览器代理CLSID)组成的复合标识符。

  3. 激活链调用
    类标识符的BindToObject方法调用左侧会话标识符的BindToObject请求IClassActivator接口,继而调用:

    1
    2
    3
    4
    5
    6
    
    HRESULT CSessionMoniker::GetClassObject(REFCLSID pClassID, ...) {
      CoCreateInstance(&CLSID_ComActivator, ..., IID_IStandardActivator, &pActivator);
      pActivator->QueryInterface(IID_ISpecialSystemProperties, &pSpecialProperties);
      pSpecialProperties->SetSessionId(m_sessionid, m_console, TRUE);
      return pActivator->StandardGetClassObject(...);
    }
    

实现IStorage混合激活

关键发现:IStandardActivator接口存在未公开方法:

1
2
3
HRESULT StandardGetInstanceFromIStorage(COSERVERINFO* pServerInfo, 
  REFCLSID pclsidOverride, IUnknown* punkOuter, CLSCTX dwClsCtx,
  IStorage* pstg, int dwCount, MULTI_QI pResults[]);

这证实了会话激活与IStorage激活可混合使用。笔者已用C#编写概念验证代码(详见GitHub),但尚未在实际漏洞场景中测试。

本文揭示了通过未文档化COM接口突破安全限制的技术本质,为防御复杂化的DCOM攻击提供了新视角。


参考文献
[1] 跨会话注入示例1
[2] 会话令牌操纵技术
[3] COM激活路径绕过案例

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