CVE-2020-0863:Windows诊断跟踪服务中的任意文件读取漏洞

iso60001  1496天前

尽管此漏洞不会直接导致权限提升,但其中涉及到的利用“技巧”仍然非常有趣。诊断跟踪服务(又称联网用户体验和遥测服务,Diagnostic Tracking Service)可能是Windows最具争议的功能之一,因为它会收集用户和操作系统的数据。因此,该服务的信息泄露漏洞,多少有些讽刺意味。总而言之,该漏洞允许本地用户以NT AUTHORITY\SYSTEM权限读取任意文件。

22.png

DiagTrack RPC接口

本文将不讨论COM,而是纯粹的老式RPC。因此,让我们检查Diagtrack公开的接口,感谢RpcView工具。

33.png

我们可以看到它有相当多的接口,但让我们将重点放在ID为4c9dbf19-d39e-4bb9-90ee-8f7179b20283的接口上。其中有37个方法,这是一个相当大的攻击面!

44.png

我发现的漏洞就是和UtcApi_DownloadLatestSettings有关:

UtcApi_DownloadLatestSettings

RpcView可以生成与RPC接口对应的接口定义语言(Interface Definition Language)文件。编译完成后,我们将得到用于UtcApi_DownloadLatestSettings流程的C函数原型。

long DownloadLatestSettings( 
    /* [in] */ handle_t IDL_handle,
    /* [in] */ long arg_1,
    /* [in] */ long arg_2
)

不出所料,第一个参数是RPC绑定句柄,另外两个参数还未知。

注意:如果你不熟悉RPC接口的工作方式,以下有一个非常简短的解释。在处理远程过程调用时,首先要做的是使用唯一标识符(例如4c9dbf19-d39e-4bb9-90ee-8f7179b20283)获取远程接口的句柄。只有这样,你才能使用这个句柄来调用过程。这就是为什么你经常会发现`handle_t`参数在最开头。当然并不是所有的接口都是如此,但大多数情况都是这样。

在获得远程接口的绑定句柄之后,我首先尝试使用以下参数来调用这个函数。

RPC_BINDING_HANDLE g_hBinding;
/* ... initialization of the binding handle skipped ... */
HRESULT hRes;
hRes = DownloadLatestSettings(g_hBinding, 1, 1);

和往常一样,我使用Process Monitor分析在后台进行的文件操作。

55.png

虽然该服务以NT AUTHORITY\SYSTEM权限运行,但我注意到它会试图枚举位于以下文件夹中的xml文件,而该文件夹属于当前登录的用户。

C:\Users\lab-user\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Tips\

用户lab-user是我在测试中使用的一个用户。这是一个拥有标准权限的普通用户,无管理权限。该操作源于对diagtrack.dll中的FindFirstFileW()的调用。

66.png

该文件夹在默认情况下似乎是空的,所以我在其中创建了一些xml文件。

77.png

再次运行测试程序并观察结果。

88.png

这一次,QueryDirectory操作成功,服务读取了file1.xml的内容。它是目录中第一个xml文件,其内容会被复制到C:\ProgramData\Microsoft\Diagnosis\SoftLandingStage\文件夹的新文件中。

同样的操作也发生在另外两个文件:file2.xmlfile3.xml

99.png

100.png

最后,所有在C:\ProgramData\[…]\SoftLandingStage中被创建的xml文件在过程结束时都会被删除。

110.png

注意:我在Procmon中创建了一个特定的规则来突出显示在DeleteFileAPI调用中发生的CreateFile操作。

CreateFile操作源于对diagtrack.dll中的DeleteFileW()的调用。

120.png

任意文件读取漏洞

这些文件不是通过调用MoveFileW()来移动的,也不是通过调用CopyFileW()来进行复制的,我们无法控制目标文件夹,因此本地攻击者无法利用这个操作来移动/复制任意文件到任意位置。相反,读取每个文件,然后将内容写入C:\ProgramData\[…]\SoftLandingStage\中的一个新文件。在某种程度上,这更像是一种手动复制文件的操作。

首先,我们可以完全控制的是源文件夹,因为它属于当前登录的用户。其次,目标文件夹对每个人都是可读的。这意味着,在默认情况下,每个人都可以读取这个文件夹中所创建的新文件,所以这其中涉及的高权限操作仍然可能被滥用。

130.png

例如,我们可以用指向object Directory的挂载点取代C:\Users\lab-user\AppData\Local\Packages\[…]\Tips文件夹,并创建伪符号链接指向我们想要的任何文件。

如果系统存在SAM文件的备份,我们就可以创建如下符号链接以获得该文件的副本。

C:\Users\lab-user\AppData\Local\Packages\[…]\Tips -> \RPC Control
\RPC\Control\file1.xm l -> \??\C:\Windows\Repair\SAM

此时,当服务试图打开file1.xml,它将被重定向到C:\Windows\Repair\SAM。然后,它将读取其内容并将其复制到C:\ProgramData\[…]\SoftLandingStage\file1.xml,而这个文件任何本地用户都可读!

不过这还有两个问题:

1.对Tips文件夹的FindFirstFileW()调用将失败,因为挂载点的目标不是“真正的”文件夹。

2.在C:\ProgramData\[…]\SoftLandingStage中创建的新file1.xml文件在进程结束时被删除。

事实证明,我们可以使用一个额外的挂载点、几个bait 文件和机会锁的组合来解决这两个问题。

解决“FindFirstFileW()”的问题

为了利用前一部分中描述的想法,我们必须找到一种可靠地将文件读操作重定向到我们想要读取的文件的方法。但是,对于调用FindFirstFileW(),我们不能直接使用伪符号链接。

注意:Win32的FindFirstFileW()函数首先列出与目标目录中的指定过滤器所匹配的文件,但这对于object Directory没有任何意义。简单来说,你可以dir C:\Windows,但不能dir "\RPC Control"。

第一个问题很容易解决,我们不需要直接创建一个指向object Directory的挂载点,而是创建一个指向实际目录的挂载点,其中包含一些bait文件。

首先,我们必须创建一个临时工作目录,如下所示:

C:\workspace
|__ file1.xml 
|__ file2.xml

然后,我们可以创建挂载点:

C:\Users\lab-user\AppData\Local\Packages\[…]\Tips -> C:\workspace

此时,FindFirstFileW()将成功并返回file1.xml。另外,如果我们在这个文件上设置一个机会锁,就可以控制服务的部分执行流,因为远程过程在试图访问它时就会被暂停。

当机会锁被触发时,我们就可以将挂载点切换到一个object Directory。此时QueryDirectory操作已经执行过,而且它只会在FindFirstFileW()调用开始时执行一次。

C:\Users\lab-user\AppData\Local\Packages\[…]\Tips -> \RPC Control
\RPC Control\file2.xml -> \??\C:\users\lab-admin\desktop\secret.txt

注意:此时我们不需要为file1.xml创建符号链接,因为服务已经有了该文件的句柄。

因此,当服务打开C:\Users\lab-user\AppData\[…]\Tips\file2.xml时。实际上它打开的是secret.txt,并会将其内容复制到C:\ProgramData\[…]\SoftLandingStage\file2.xml

结论:我们可以欺骗服务读取我们不能读取的文件,但是还存在第二个问题。在这个过程的最后,C:\ProgramData\[…]\SoftLandingStage\file2.xml被删除,我们还是无法读取它。

解决文件删除问题

由于目标文件会在过程结束时被删除,因此我们存在与服务的竞争,希望能抢在过程结束前获得文件副本。为此,我们有两种选择,第一个是暴力攻击。我们可以通过脚本循环监视目标目录C:\ProgramData\[…]\SoftLandingStage,以便第一时间读取文件。

但是,暴力攻击总是无可奈何的选择。我们还有第二个方法,也是更可靠的方法。

在一开始,我们将创建三个文件,而不是两个文件。

C:\workspace
|__ file1.xml
|__ file2.xml  
|__ file3.xml

接下来的步骤是相同的,但是,当触发file1.xml上的机会锁时,我们将执行两个额外的操作。

我们首先切换挂载点并创建两个伪符号链接,确保file3.xml链接指向实际的file3.xml文件。

C:\Users\lab-user\AppData\Local\Packages\[…]\Tips -> \RPC Control
\RPC Control\file2.xml -> \??\C:\users\lab-admin\desktop\secret.txt
\RPC Control\file3.xml -> \??\C:\workspace\file3.xml

在释放第一个锁之前,我们就在file3.xml上设置了一个新的机会锁。

而这些操作产生如下影响:

1.DiagTrack试图读取file1.xml时会碰到第一个机会锁。

2.现在,我们切换挂载点,创建两个符号链接,并在file3.xml上设置一个机会锁。

3.我们释放第一个机会锁(file1.xml)。

4.DiagTrack会复制file1.xmlfile2.xml,file2指向了secret.txt

5.DiagTrack会试图读取file3.xml,碰到第二个机会锁。

6.现在是关键的部分。此时,远程过程被暂停,以便我们可以获得C:\ProgramData\[…]\SoftLandingStage\file2的副本,也就是secret.txt的副本。

7.我们释放第二个机会锁(file3.xml)。

8.远程过程终止,三个xml文件被删除。

请注意:因为DiagTrack执行的过程是按顺序执行的,所以每个文件被一个接一个地复制,所有新创建的文件都在最后被删除。

以上操作就产生了一个漏洞,它可让普通用户获得只有NT AUTHORITY\SYSTEM权限才能读取的文件的副本。

140.png

相关链接和工具

1.CVE-2020-0863 - Connected User Experiences and Telemetry Service Information Disclosure Vulnerability

https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/CVE-2020-0863

2.My PoC for CVE-2020-0863

https://github.com/itm4n/DiagTrackAribtraryFileRead

3.RpcView

https://www.rpcview.org/

4.Symbolic Link Testing Tools - James Forshaw

https://github.com/googleprojectzero/symboliclink-testing-tools

本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场
来源:https://itm4n.github.io/cve-2020-0863-windows-diagtrack-info-disclo/

最新评论

昵称
邮箱
提交评论