CVE-2020-1088:Windows权限提升漏洞分析与利用

本文详细分析了CVE-2020-1088漏洞的技术细节,这是一个基于符号链接重定向的Windows权限提升漏洞,允许攻击者通过Windows错误报告服务任意删除系统文件,涉及ETW会话处理和文件操作安全机制。

CVE-2020-1088 — 又一个任意删除权限提升漏洞

2020年1月,我发现并报告了一个权限提升(EoP)漏洞,该漏洞允许通过Windows错误报告服务任意删除文件。该漏洞已在2020年5月的Windows更新中得到修复。

CVE-2020-1088是另一个基于Windows特权服务中符号链接重定向的漏洞。如果你对这类漏洞不熟悉,我推荐阅读@clavoillotte的《Windows特权文件操作滥用入门》,其中解释了这些漏洞的工作原理。当然,这一切都离不开James Forshaw的研究,他持续揭露Windows特权服务的攻击面,因此对他的工作表示衷心感谢。

Windows错误报告(WER)在过去一年左右出现了许多漏洞。仅在2020年,WER就修复了10个漏洞,在此之前,Gal De Leon在BlueHatIL上发表了"利用Windows错误报告中的错误"的演讲(视频/幻灯片),展示了更多漏洞。

WER在Windows中被分成几个不同的应用程序。例如,当应用程序崩溃时,WerFault.exe将处理该应用程序的错误报告。这与运行崩溃应用程序的用户具有相同的权限。同时,Windows错误报告服务(WerSvc)在LocalSystem用户下启动。WerFault.exe将通过原始ALPC调用与WerSvc通信。该服务的实现可以在%SystemRoot%\System32\WerSvc.dll中找到。

CVE-2020-1088是一个经典的任意文件删除漏洞,我们可以欺骗WerSvc删除我们选择的文件。该漏洞发生在ETW会话在CWerService::SvcCollectETWLogs中被刷新时。在这里,ETW会话从注册表项HKLM\Software\Microsoft\Windows\Windows Error Reporting\EtwSessionsHKLM\Software\Microsoft\Windows\Windows Error Reporting\DynamicEtwSessions中添加,如下面的代码片段所示:

WerSvc!CWerService::SvcCollectETWLogs - 来自注册表的会话

我不太确定这些注册表项何时被填充,但我最好的猜测是通过许多Windows诊断设置之一。在我的情况下,我有一个键值为WPR_initiated_DiagTrackMiniLogger_OneTrace User Logger 20200113 1 Event Collector_0,很可能与Windows性能记录器相关(因此前缀为WPR)。

DynamicEtwSessions注册表键

当ETW会话跟踪启动时,将在%UserProfile%\AppData\local\Temp\下创建一个带有随机GUID的文件夹,以及一个与上述注册表键匹配的文件名,在我的情况下完整路径是:%UserProfile%\AppData\local\Temp\{GUID}\WPR_initiated_DiagTrackMiniLogger_OneTrace User Logger 20200113 1 Event Collector_0.buf

随后,将调用CEtwSession::FlushBuffered来刷新临时GUID文件夹中的跟踪文件。相关的伪代码如下:

1
2
3
4
5
6
7
LPCWSTR fileName = sprintf("%s\\%s.buf.etl", path, lpFileName);
LPCWSTR newFileName = sprintf("%s\\%s.etl", path, lpNewFileName);
hFile = CreateFileW(fileName, ...)
...
if(!MoveFileW(fileName, newFileName)) {
    DeleteFileW(fileName);
}

换句话说,服务将尝试将文件从filename.buf.etl重命名为filename.etl,如果失败则删除该文件。

现在我们有一个以SYSTEM完整性运行的服务,正在删除当前登录用户完全可控的文件夹中的文件。这听起来一点也不危险,对吧?

如何利用此漏洞?

至此,我们掌握了以下关于漏洞的信息:

  • 易受攻击的代码路径可以通过崩溃应用程序来触发
  • %UserProfile%\AppData\Local\Temp\{GUID}下创建随机文件夹
  • 文件WPR_initiated_DiagTrackMiniLogger_OneTrace User Logger 20200113 1 Event Collector_0.buf.etl在此文件夹下创建
  • 然后文件被重命名为扩展名.etl,如果失败,.buf.etl文件将被删除
  • WerSvc不模拟调用用户,因此文件操作以SYSTEM完整性执行

此时,任何了解符号链接重定向漏洞工作原理的人都应该能够想到利用路径。对于那些没有这方面知识的人,了解以下约束条件很重要:

为了重定向文件操作,可以完成两件事(可以完成更多事情,但让我们保持简单)。要么将父文件夹转换为挂载点/连接点,要么将文件转换为硬链接。在20H1版本中实施了硬链接的缓解措施,因此它们不再有效。此外,这是一个任意删除漏洞,硬链接将不起作用。

因为我们需要将父文件夹转换为挂载点,我们需要在WPR_initiated_DiagTrackMiniLogger_OneTrace User Logger 20200113 1 Event Collector_0.buf.etl文件被移动之前知道文件夹的名称。

我们可以通过在调用MoveFileW之前确保目录是挂载点来强制MoveFileW调用失败。

有了这些信息,我们可以继续进行实际利用。以下是PoC的工作流程:

  1. 创建一个文件监视器,监视%UserProfile%\AppData\Local\Temp下的文件夹创建
  2. 崩溃一个进程(Powershell.exe -Command “[Environment]::FailFast(‘Error’)")
  3. 持续尝试删除文件%UserProfile%\AppData\Local\Temp\{GUID}\WPR_initiated_DiagTrackMiniLogger_OneTrace User Logger 20200113 1 Event Collector_0.buf.etl。一旦成功,转到下一步
  4. 创建一个从%UserProfile%\AppData\Local\Temp\{GUID}\RPC Control的挂载点
  5. 创建一个从\RPC Control\WPR_initiated_DiagTrackMiniLogger_OneTrace User Logger 20200113 1 Event Collector_0.buf.etl\??\C:\Windows\System32\license.rtf的符号链接

第3步很可能可以通过OpLock更好地解决,但对于此漏洞,这并不重要,因为PoC每次都能成功。可以在以下Process Monitor截图中看到成功的利用,其中C:\Windows\System32\license.rtf被删除。

漏洞成功利用

完整的PoC可以在这里找到。

如何修复?

正如我在本文开头提到的,WER在过去一年(或几年)中出现了许多类似的漏洞。因此,在WER代码库中添加了一个方法来检查文件句柄是否指向预期的路径。该方法UtilVerifyFilePath随后在删除文件的包装方法UtilDeleteFilePath中使用。

如果我们回顾CEtwSession::FlushBuffered的代码片段,对DeleteFileW的调用现在被替换为对UtilDeleteFilePath的调用。因此,相关代码现在看起来像这样:

1
2
3
4
5
6
7
LPCWSTR fileName = sprintf("%s\\%s.buf.etl", path, lpFileName);
LPCWSTR newFileName = sprintf("%s\\%s.etl", path, lpNewFileName);
hFile = CreateFileW(fileName, ...)
...
if(!MoveFileW(fileName, newFileName)) {
    UtilDeleteFilePath(fileName);
}

因此,我们可以得出结论,已经实施了缓解措施。在深入探讨之前,我想透露一个我迄今为止未公开的小细节。

给(不太)细心读者的额外奖励

CEtwSession::FlushBuffered的原始代码片段中,我跳过了一个小细节,训练有素的眼睛可能已经注意到了。该方法在调用DeleteFileW之前调用了MoveFileW。显然,这也可以被利用来将你选择的文件移动到任意文件夹。

假设我们有一个从GUID文件夹到\RPC Control的挂载点。从这里我们可以创建两个符号链接。一个从filename.etf.buf到我们选择的有效载荷,例如%UserProfile%\payload.dll,另一个从filename.etfC:\Windows\System32\windowscoredeviceinfo.dll。这允许我们使用Clément Labro的UsoDllLoader来获取系统shell。

查看新代码,这个调用仍然存在,意味着我们可以滥用MoveFileW调用来植入我们的有效载荷,对吧?嗯,不完全是这样。在2020年5月代号为2004的Windows 10版本中,向WER库添加了一个新方法UtilVerifyAndLockDirectory(LPCWSTR path, HANDLE handle)。以下片段是该方法的简化版本,省略了一些错误处理。

本质上,该方法尝试在给定路径中创建一个随机文件,然后返回该文件的句柄。这应该(理论上)锁定文件夹并防止用户篡改文件夹。然后调用方负责在所有"危险"文件操作后关闭此句柄。

正如你可能听说的,微软改变了Windows预览版错误赏金计划的范围,因此涉及通过连接点或挂载点进行文件路径重定向的漏洞不再有效。显然,他们正在研究更广泛的缓解措施来减轻整个漏洞类别。

我希望你喜欢这篇文章。如果你有任何问题,请随时通过Twitter @fritzboger联系我。

恭喜你读到这里。你的礼物是一个小小的额外漏洞,因为这个漏洞不是5月补丁中唯一修复的漏洞。查找Wersvc.dll中UtilVerifyAndLockDirectory的使用,你可能会找到另一个。

披露时间线

  • 2020-01-21 — 向MSRC报告漏洞
  • 2020-01-24 — MSRC跟进要求提供更多关于如何重现的信息
  • 2020-02-03 — 漏洞确认
  • 2020-04-02 — 授予赏金
  • 2020-05-12 — 在5月补丁星期二修复漏洞并分配CVE-2020-1088
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计