CVE-2018-0952:Windows Standard Collector Service中的权限提升漏洞

 

一、前言

如果大家不想深入了解这个漏洞的发现过程,可以简单阅读一下这篇文章以及相关的PoC代码

我在研究及研发方面非常喜欢使用Process Monitor这款工具。在开发攻击型安全工具时,我经常使用Procmon来监控这些工具如何与Windows交互以及相应的检测方法。今年早些时候,当我使用Visual Studio来调试一些代码并使用Procmon来监控代码行为时,我注意到了一些有趣的行为。通常情况下我会在Procmon中设置针对Visual Studio进程的例外过滤器,降低输出中的噪音事件,但在设置过滤器之前,我注意到有个SYSTEM进程会往用户目录中写入数据。

图1. StandardCollector.Service.exe往用户Temp目录中写入数据

如果某个特权服务会往用户资源中写入数据,就很有可能存在符号链接(symlink)攻击向量,比如我之前发现的Cylance权限提升漏洞一样。为了确认我们如何才能影响该服务的具体行为,我查看了服务已加载的库,开始深入研究Standard Collector Service。

图2. StandardCollector.Service.exe加载的Visual Studio DLL文件

 

二、发现过程

根据这些程序库的具体路径,我们可以判断出Standard Collector Service是Visual Studio的一款诊断工具。查看相关目录中的库及可执行文件后,我发现其中某些程序使用的是.NET语言来开发,比如其中有个独立的CLI工具(VSDiagnostics.exe),该工具的帮助信息如下所示:

图3. VSDiagnostics CLI工具的帮助信息

我们可以使用dnSpy加载VSDiagnostics,了解该工具的一些信息,发现工具如何与Standard Collector Service交互。首先,应用会获取IStandardCollectorService的一个实例并使用会话配置来创建ICollectionSession

图4. 配置diagnostics collection session的初始步骤

接下来使用CLSID以及DLL名称将agent添加到ICollectionSession中,这种行为也是用户可以控制的一种有趣的行为,我还记得之前也曾通过这种DLL加载行为来利用漏洞。目前看来,Visual Studio Standard Collector Service貌似与Windows 10自带的Diagnostics Hub Standard Collector Service非常相似或者完全相同。为了验证这一点,我使用OleViewDotNet来查询这些服务所支持的接口:

图5. OleViewDotNet中显示的Windows Diagnostics Hub Standard Collector Service

查看IStandardCollectorService的代理定义后,我们可以找到其他一些熟悉的接口,尤其是VSDiagnostics中的ICollectionSession接口:

图6. OleViewDotNet中的ICollectionSession接口定义

记下接口ID信息(“IID”),然后返回.NET interop库,比较这两个接口的IID,发现这些值并不一致:

图7. Visual Studio ICollectionSession使用了不同的IID

进一步深入分析.NET代码,我发现Visual Studio的这些特定接口会通过代理DLL来加载:

图8. VSDiagnostics.exe中用来加载DLL的函数

快速查看DiagnosticsHub.StandardCollector.Proxy.dll中的ManualRegisterInterfaces函数后,我们可以发现其中有一段简单的循环代码,用来遍历一组IID,其中就包含ICollectionSession对应的一个IID:

图9. 代理DLL中的ManualRegisterInterfaces函数

图10. 待注册的IID数组中包含Visual Studio的ICollectionSession IID

进一步理解Visual Studio Collector Service后,我想试一下能否复用同样的.NET interop代码来控制Windows Collector Service。为了与正确的服务进行交互,我需要将Visual Studio的CLSID以及IID替换为Windows Collector Service对应的CLSID以及IID,使用修改后的代码来生成一个客户端,该客户端的作用是使用collector service创建并启动一个诊断会话:

图11. 与Collector Service交互的客户端代码片段

启动Procmon,运行客户端后我们可以在看到有些文件和目录会在C:\Temp临时目录中创建。在Procmon中分析这些日志后,我们可以看到第一次目录创建操作其实使用到了client impersonation技术:

图12. 通过身份模拟(impersonation)方式在临时目录中创建会话文件夹

虽然首次创建目录时使用了用客户端身份,但后续文件及目录创建操作并没有遵循这个原则:

图13. 未使用身份模拟来创建目录

进一步分析其他文件操作后,我又找到了几个比较突出的信息。Standard Collector Service执行了各种文件操作,如下图所示,我在图中做了相应注释:

图14. Standard Collector Service执行的各种文件操作

这里最有趣的操作就是在诊断报告生成期间执行的文件复制操作,该操作对应的调用栈以及事件如下图所示:

图15. Standard Collector Service执行的CopyFile操作

 

三、编写PoC

现在我们已经找到能被用户影响的操作,我构想了一个可能利用的任意文件创建过程,包括如下几步:

1、一旦服务调用CloseFile,就立刻获取ETL文件({GUID}.1.m.etl)的op-lock锁;

2、查找对应的子目录并将转成指向C:\Windows\System32的挂载点;

3、将{GUID}.1.m.etl的内容替换成恶意DLL;

4、释放op-lock,允许通过挂载点来拷贝ETL文件;

5、将拷贝的ETL作为agent DLL来启动新的collection session,提升权限执行代码。

为了编写利用代码,我扩展了客户端的功能,利用James Forshaw编写的NtApiDotNet C#库来创建op-lock以及挂载点。请求op-lock的代码片段以及Procmon中对应的事件如以下两图所示:

图16. 获取.etl文件op-lock的代码片段

图17. 使用op-lock赢得竞争条件

获取文件的op-lock最终会停止CopyFile竞争操作,使目标内容可以被覆盖,这样在CopyFile操作时也能执行我们所需的操作。接下来漏洞利用程序会查找Report目录,扫描该目录,找到需要转换为挂载点的随机子目录。一旦成功创建挂载点,.etl的内容会被替换成恶意DLL文件。最后,利用程序会关闭.etl文件,释放op-lock,使CopyFile操作能继续进行。相应的代码片段以及Procmon的输出下图所示:

图18. 创建挂载点、覆盖.etl文件然后释放op-lock的代码片段

图19. 利用挂载点目录实现任意文件写入

有多种方法可以利用任意文件写入实现权限提升,但在这个利用程序中,我选择使用Collector服务的agent DLL加载功能使利用过程保持在同一个服务上下文中。在上图中大家可能会注意到一点,那就是我没有使用挂载点+符号链接的技巧将文件后缀名改成.dll,这是因为DLL在加载时可以使用任意扩展名。在利用过程中,DLL文件只需位于System32目录就可以被Collector服务加载。最终利用程序会被成功执行,如下图所示:

图20. SystemCollector.exe利用程序的输出信息

相应的Procmon事件如下图所示:

图21. 成功利用漏洞时的Procmon输出

以上两图显示利用程序是以“Admin”用户的权限来运行,下面我使用“bob”这个低权限用户来运行漏洞利用程序,动图如下:

图22. 以低权限用户运行漏洞利用程序

大家可以自己尝试运行SystemCollector PoC代码,将PoC代码转换成可以实际使用的攻击武器就留待大家来完成。NtApiDotNet库是一个PowerShell模块,使用起来非常方便。

 

四、漏洞修复

这个漏洞已于2018年8月的补丁星期二中被修复,我逆向分析了相应的补丁。与我预期的一样,补丁只是简单地在存在漏洞的文件操作前(即DiagnosticsHub.StandardCollector.Runtime.dll中的CommitPackagingResult函数)添加了CoImpersonateClient调用:

图23. 使用身份模拟来创建Report目录

图24. 在DiagnosticsHub.StandardCollector.Runtime.dllCommitPackagingResult函数中添加CoImpersonateClient

 

五、总结

我在Cylance权限提升的write-up中曾提到过,防范符号链接攻击虽然看上去可能比较简单,但经常被人们忽视。只要特权服务会以用户的身份来执行文件操作,就需要正确使用身份模拟操作,避免存在此类攻击风险。

发现这个漏洞后,我向MSRC提交了漏洞细节以及PoC,MSRC反应非常快,迅速标识并确认了这个漏洞,并通过定期更新修复了这个问题,完整的披露时间线可以参考此处链接

该漏洞的CVE编号为CVE-2018-0952,如有任何疑问或者建议,欢迎随时联系我:@ryHanson。

(完)