欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

如何借助COM对Windows受保护进程进行代码注入(第二部分)

来源:本站整理 作者:佚名 时间:2018-12-06 TAG: 我要投稿

在之前的文章中,我们讨论了一种将任意代码注入PPL-Windows TCB进程的技术,该技术结合了我此前发现并向Microsoft报告的许多漏洞。由于一些原因,我们之前讨论的技术不适用于具有较强保护的受保护进程(Protected Processes,PP)。本篇文章主要为了解决这一问题,并提供详细信息,说明如何在不具备管理员权限的情况下劫持完整的PP-Windows TCB流程。本文侧重于技术探讨,我们尝试是否能在一个完整的PP中执行代码,因为在PP中通过PPL可以做的事情并不多。
首先,我们对上一次攻击实验进行简单回顾,目前我们能够确定一个以PPL运行的进程,并且该进程暴露了一个COM服务。具体来说,该服务是“.NET运行时优化服务”(.NET Runtime Optimization Service),该服务包含在.NET框架中,并在CodeGen级别使用PPL将缓存的签名级别应用于AOT编译的DLL,从而允许它们用于用户模式代码完整性(UMCI)。通过修改COM代理配置,可能导致类型混淆的发生,从而允许我们劫持已知DLL配置,来加载任意DLL。一旦在PPL中成功运行代码,我就可以滥用缓存签名功能中的漏洞,来创建一个签名,并加载到任何PPL中的DLL,从而升级到PPL-Windows TCB级别。
寻找新目标
我首先考虑对完整的PP进行漏洞利用,并借助我们在PPL-Windows TCB上运行代码时获得的额外访问权限。大家可能认为,可以滥用缓存的已签名DLL来绕过安全检查,从而加载到完整的PP中。但不幸的是,内核的代码完整性模块忽略了完整PP的缓存签名级别。那么,用已知DLL呢?如果我们在PPL-Windows TCB中以管理员权限运行代码,那么我们可以直接写入已知DLL对象目录,并尝试让PP加载任意DLL。然而,正如我在上一篇博客中提到的,这个方法也不起作用,因为完整的PP忽略了已知DLL。即使确实加载了已知的DLL,我们的目标也不是通过获得管理员权限来将代码注入进程。
因此,我决定重新研究之前编写的PowerShell脚本,以发现哪些可执行文件将作为完整的PP在什么级别运行。在Windows 10 1803上,有大量可执行文件以PP-Authenticode级别运行,但只有4个可执行文件以更高权限级别启动,如下表所示。
C:\windows\system32\GenValObj.exe(运行级别Windows)
C:\windows\system32\sppsvc.exe(运行级别Windows)
C:\windows\system32\WerFaultSecure.exe(运行级别Windows TCB)
C:\windows\system32\SgrmBroker.exe(运行级别Windows TCB)
由于我们目前还没有从PP-Windows级别提升到PP-Windows TCB级别的方法,无法像之前对PPL进行的操作那样,因此在这4个可执行文件中,只有WerFaultSecure.exe和SgrmBroker.exe这两个文件是我们潜在的目标。我将这两个可执行文件与已知的COM服务注册相关联,并尝试寻找这些可执行文件是否暴露了COM的攻击面。回想我上次利用的.NET可执行文件并没有注册其COM服务,因此我进行了一些基本的逆向工程,来寻找COM的使用。
我们发现,SgrmBroker可执行文件似乎没有什么用,这是一个独立的用户模式应用程序的封装,作为Windows Defender System Guard的一部分,用于实现系统的运行时环境证明(Runtime Attestation),并且不需要调用任何COM API。WerFaultSecure似乎也不会调用COM,但它可以加载COM对象。因为我了解到,Alex Ionescu使用我原来的COM脚本小程序(Scriptlet)代码执行攻击,通过劫持WerFaultSecure中的COM对象加载过程,成功获取了PPL-Windows TCB级别。尽管WerFaultSecure没有公开的服务,但如果它可以初始化COM,那么我是否也可以滥用它来运行任意代码呢?要掌握COM的攻击面,首先我们需要了解COM是如何实现进程外服务器(Out-of-process COM Servers)和远程处理(COM Remoting)的。
深入研究COM Remoting内部
COM客户端和COM服务器之间的通信,是通过MSRPC协议进行的,该协议基于Open Group的DCE/RPC协议。对于本地通信,是通过高级本地过程调用端口(ALPC)进行传输。对于更高级别的通信,客户端和服务器之间的通信过程如下图所示:

为了使客户端能够找到服务器的位置,该进程在RPCSS中使用DCOM激活器(DCOM Activator)来注册ALPC终端。该终端与服务器的对象导出ID(Object Exporter ID,OXID)共同注册,后者是由RPCSS分配的64位随机生成编号。当客户端想要连接服务器时,必须首先要求RPCSS将服务器的OXID解析为RPC终端。在知道ALPC RPC终端的情况下,客户端可以连接到服务器,并调用COM对象上的方法。
OXID值可以在进程外(OOP)COM激活结果中找到,也可以在编组后的对象引用(OBJREF)结构中找到。客户端在RPCSS的IObjectExporter RPC接口上调用ResolveOxid方法。ResolveOxid的原型如下:
interface IObjectExporter {
  // ...
  error_status_t ResolveOxid(
    [in] handle_t hRpc,
    [in] OXID* pOxid,
    [in] unsigned short cRequestedProtseqs,
    [in] unsigned short arRequestedProtseqs[],
    [out, ref] DUALSTRINGARRAY** ppdsaOxidBindings,
    [out, ref] IPID* pipidRemUnknown,
    [out, ref] DWORD* pAuthnHint
);
在原型中,我们可以看到要解析的OXID会在pOxid参数中传递,服务器返回一个Dual String Bindings数组,表示要连接到此OXID值的RPC终端。此外,服务器还返回另外两条信息,一个是我们可以安全忽略的身份验证级别提示(pAuthnHint),另一个是不应该忽略的IRemUnknown接口的IPID(pipidRemUnknown)。
IPID是一个名为接口进程ID的GUID值。它表示服务器内部COM接口的唯一标识符,并且需要与正确的COM对象进行通信,因为它允许单个RPC终端通过一个连接复用多个接口。IRemUnknown接口是每个COM服务器必须实现的默认COM接口,该接口用于查询现有对象上的新IPID(使用RemQueryInterface),并维护远程对象的引用计数(使用RemAddRef和RemRelease方法)。无论是否导出实际的COM服务器,是否可以通过解析服务器的OXID来发现IPID,这个接口都始终存在。因此,我想知道这个接口还支持其他哪些方法,看看是否有哪些地方可以用于获得代码执行。

[1] [2] [3] [4]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载