导语:Symantec Endpoint Protection(SEP)用户域服务公开的RPC端点之一中存在本地特权升级漏洞,有特权的本地用户可以利用此功能执行任意代码。
Symantec Endpoint Protection(SEP)用户域服务公开的RPC端点之一中存在本地特权升级漏洞,有特权的本地用户可以利用此功能执行任意代码。任意文件移动允许用户将文件从一个受控位置移动到另一个位置,这可被利用来在SYSTEM上下文下获得任意代码执行。此漏洞已通过ZDI被公开,分别是ZDI-20-228和CVE-2020-5825,已在SEP的14.2.5569.2100版本中修复。大多数系统现在应该已经自动打补丁了,但是用户需要立即修补。
该漏洞是由FusionX研发团队独立发现的,并于2020年初由z0mb1e披露给ZDI。
分析过程
SEP的体系结构可以通过下图描述:
使用14.2.5323.2000版本执行所有分析,虽然在这个小版本之后出现了一些架构上的变化,但它们还不足以改变上述的架构。
SymCorpUI是用于与SEP接口、检查策略、启动扫描和更改本地实例的用户界面GUI。几乎所有的请求都通过COM对象代理回ccSvcHst进行处理。这个特权服务ccSvcHst是SEP的本地hivemind,处理所有扫描、配置、隔离等的执行。
ccSvcHst服务有各种各样的输入界面,包括COM对象(LocalServer和InprocServer)、RPC端点、TCP端口、扩展的服务控制代码等。它另外接口与大约13个不同的内核驱动程序通过IO控制代码加载的应用程序。
漏洞从ccSvcHst暴露的RPC服务器开始被发现,任何经过身份验证的本地用户都可以连接到它。它注册了六个函数,如下面的IDL所述:
为了调用它们,我们首先必须获得一个上下文句柄。这允许ccSvcHost跟踪RPC调用之间的状态信息,无论它们是直接到RPC服务器、COM还是通过其他传输。你可以在这里阅读更多关于MSDN上RPC上下文句柄的信息。在我们的例子中,Proc0是用于获取上下文句柄的函数。我们首先需要生成唯一的GUID并将其发送到服务,然后将使用它来跟踪我们的会话。
为了获得句柄,我们向Proc0函数发送一个经过设计的缓冲区:
lpHandle现在将包含一个上下文句柄,要使调用成功,必须将其传递给每个RPC函数,我们待会儿再讲这些。
除了这些函数调用之外,RPC服务器还注册了五个不同的端点。它们由每次启动服务时动态生成的GUID表示,可以从注册表中提取当前端点:
每个端点都有注册的通道,也可以从注册表中提取通道:
但是在五个RPC端点之间注册了大约37个通道。可以通过标准的win32 RPCRT4函数连接到RPC端点,有关详细信息,其详细信息可以在附带源代码的CreateBindingHandle函数中找到。
通道在运行时向ccIPC.dll注册,该文件充当系统服务加载的RPC服务器。然后,每个通道都会注册一个命令处理程序,该命令处理程序使其可以在调用期间动态地处理请求。通道可以根据需要注册任意数量的命令处理程序。该架构总结如下:
由AVHostPlugin.dll托管的由字符串{BFADC982-75E5-497A-A114-95856CCE9A33}标识的一个通道注册了一个名为CRTVScanIPCCommandHandler的处理程序,并处理四个不同的命令:HandleStillInfectedOpState,HandleOpState,KickOffSMRScan和DoCOM。最终处理程序DoCOM由子处理程序ProcessOneRequest提供服务,它提供了对大约40个附加函数的支持。其中的COM_ACT_ON_FILE是子命令类型17,它支持5个子命令:移动文件、重命名文件、删除目录、解除链接和某种类型的文件加密/解密功能。下面是子命令处理程序的相关部分:
如果可以到达此处理程序,则可以滥用第一种情况来控制MoveFileExA的源和目标,从而以SYSTEM用户身份移动任意文件。
为了达到这个处理程序,我们需要返回到RPC函数。一旦从Proc0检索到客户端上下文句柄,就需要使用Proc6。这个函数处理解析请求并将其发送到适当的通道;其原型如下:
简单地说,lpInputBuf是包含路由请求所需的所有必要信息的请求缓冲区,而lpInputBuf2是发送到命令处理程序进行处理的缓冲区(尽管它由ccIPC进行了部分处理)。
请求缓冲区采用以下形式:
第一个字符串是我们请求的通道,第二个是注册到插件的处理程序的GUID,最后一个字符串传递给通道来执行GUID绑定的任何函数。
第二缓冲区由序言和嵌入式有效载荷缓冲区组成,这个序言包含协议版本(总是0x1)、参数类型和有效载荷长度。在序言和主要用于路由请求的有效载荷之间有一些字节。
内嵌的有效载荷包含到达目的地所需的所有信息;这包括子命令(64)、客户端PID、源文件名和目标文件名,每个文件名都以长度作为前缀。两个字符串都应该是ANSI。结果如下:
在这里,我们可以看到,我们正在移动文件c:users“users”“setup.dll”到c:windows“sysnative”“setup. dll“。Sysnative是一个虚拟文件夹,它允许我们访问64位的System32文件夹,而不是SysWOW64。因为SEP是一个32位应用程序,所以到System32的任何路径都将映射到SysWOW64,这是我们不想做的。
漏洞利用
文件移动过程很简单,在Windows 10 1903年之前,James Forshaw的DiagHub策略是我们的首选策略。简单地说,Microsoft Diagnostics Hub标准收集器服务(DiagHub)是一个收集跟踪信息的服务,并通过DCOM编程公开。该DCOM对象可用于将DLL加载到系统进程中,前提是该DLL存在于c:windows模块system32目录中。这非常适合于利用任意文件移动,因为我们可以简单地调用此服务,并在非必要的特权系统进程中安全执行代码。
从1903版及更高版本开始,DiagHub无法再用于加载任意DLL。可以使用更新的策略UsoLoader。这类似于DiagHub,但使用Update Session Orchestrator将DLL加载到System32之外的特权进程中。当然这里也存在其他选择。由于我们完全控制了写入的目的地,因此我们可以将DLL劫持到Windows本身和SEP本身的任何数量的系统服务中。
最终,在14.0和14.2版本之间的某个时间,Symantec确认此插件特别敏感,并进行了验证检查。一旦请求到达AVHostPlugin,SEP将验证该请求是否来自Symantec签名的进程。以下是相关部分:
它使用RpcServerInqCallAttributesA获取发送请求的RPC客户端的进程ID。然后使用另一个库ccSvrTrst验证请求进程的签名。但是,这很容易绕开。不会对正在运行的进程的令牌进行任何检查,只需检查它是否由Symantec签名即可。通过生成Symantec二进制文件并通过某种形式的代码注入或DLL劫持将其注入其中,我们可以从该托管进程发出所有RPC请求并通过检查。
我们的概念证明是作为标准DLL实施的,期望用户将滥用DLL加载路径来获取Symantec签名二进制文件中的代码执行。一个示例DevViewer.exe可用于加载DLL。通过将可执行文件复制到用户控制的位置,我们的利用DLL可以放在同一路径中,并重命名为TextInputFramework.dll。这将在启动时加载到DevViewer进程中,并允许我们将有效请求发送到AVHostPlugin接口。
漏洞修复
SEP的14.2.5569.2100版本修复了文件移动漏洞,补丁很简单;他们在AVHostPlugin中添加了新的检查:
如果DO_COM子代码小于125,我们调用CheckAdminMember,它将执行以下操作:
如果我们的子代码是5个值之一,它将检查发出请求的过程令牌是否具有本地管理员组成员身份。如果允许,则允许该请求,否则将被拒绝。这是针对此特定漏洞的适当补丁,因为它只能由系统管理员执行,但仍在通道以及注册到端点的所有其他通道中公开各种子代码功能。
在发布本文的同时,我们还将发布概念验证漏洞。由于RPC接口具有特殊的性质,因此在使用此代码之前,你可能需要提取特定版本的IDL GUID并进行编译。尽管我们提供了多个版本的IDL,但是每个新的次要版本都具有不同的界面GUID,并且需要与编译到有效载荷中的IDL相匹配。幸运的是,这是一个非常简单的过程。首先,你需要从注册表中获取GUID,这是一个关键:
因此,我们的IDL GUID为{D8E0573B-6B4C-4DC0-8F5C-4764B8E079F9},查看包含的IDL以了解在何处切换GUID。
本文翻译自:https://www.accenture.com/us-en/blogs/cyber-defense/exploiting-arbitrary-file-move-in-symantec-endpoint-protection如若转载,请注明原文地址: