CVE-2020-0863:Windows诊断跟踪服务中的任意文件读取漏洞
尽管此漏洞不会直接导致权限提升,但其中涉及到的利用“技巧”仍然非常有趣。诊断跟踪服务(又称联网用户体验和遥测服务,Diagnostic Tracking Service)可能是Windows最具争议的功能之一,因为它会收集用户和操作系统的数据。因此,该服务的信息泄露漏洞,多少有些讽刺意味。总而言之,该漏洞允许本地用户以NT AUTHORITY\SYSTEM
权限读取任意文件。
DiagTrack RPC接口
本文将不讨论COM,而是纯粹的老式RPC。因此,让我们检查Diagtrack公开的接口,感谢RpcView工具。
我们可以看到它有相当多的接口,但让我们将重点放在ID为4c9dbf19-d39e-4bb9-90ee-8f7179b20283
的接口上。其中有37个方法,这是一个相当大的攻击面!
我发现的漏洞就是和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
分析在后台进行的文件操作。
虽然该服务以NT AUTHORITY\SYSTEM
权限运行,但我注意到它会试图枚举位于以下文件夹中的xml文件,而该文件夹属于当前登录的用户。
C:\Users\lab-user\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Tips\
用户lab-user
是我在测试中使用的一个用户。这是一个拥有标准权限的普通用户,无管理权限。该操作源于对diagtrack.dll
中的FindFirstFileW()
的调用。
该文件夹在默认情况下似乎是空的,所以我在其中创建了一些xml文件。
再次运行测试程序并观察结果。
这一次,QueryDirectory
操作成功,服务读取了file1.xml
的内容。它是目录中第一个xml文件,其内容会被复制到C:\ProgramData\Microsoft\Diagnosis\SoftLandingStage\
文件夹的新文件中。
同样的操作也发生在另外两个文件:file2.xml
,file3.xml
。
最后,所有在C:\ProgramData\[…]\SoftLandingStage
中被创建的xml文件在过程结束时都会被删除。
注意:我在Procmon中创建了一个特定的规则来突出显示在DeleteFile
API调用中发生的CreateFile
操作。
CreateFile
操作源于对diagtrack.dll
中的DeleteFileW()
的调用。
任意文件读取漏洞
这些文件不是通过调用MoveFileW()
来移动的,也不是通过调用CopyFileW()
来进行复制的,我们无法控制目标文件夹,因此本地攻击者无法利用这个操作来移动/复制任意文件到任意位置。相反,读取每个文件,然后将内容写入C:\ProgramData\[…]\SoftLandingStage\
中的一个新文件。在某种程度上,这更像是一种手动复制文件的操作。
首先,我们可以完全控制的是源文件夹,因为它属于当前登录的用户。其次,目标文件夹对每个人都是可读的。这意味着,在默认情况下,每个人都可以读取这个文件夹中所创建的新文件,所以这其中涉及的高权限操作仍然可能被滥用。
例如,我们可以用指向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.xml
和file2.xml
,file2指向了secret.txt
。
5.DiagTrack会试图读取file3.xml
,碰到第二个机会锁。
6.现在是关键的部分。此时,远程过程被暂停,以便我们可以获得C:\ProgramData\[…]\SoftLandingStage\file2
的副本,也就是secret.txt
的副本。
7.我们释放第二个机会锁(file3.xml
)。
8.远程过程终止,三个xml文件被删除。
请注意:因为DiagTrack执行的过程是按顺序执行的,所以每个文件被一个接一个地复制,所有新创建的文件都在最后被删除。
以上操作就产生了一个漏洞,它可让普通用户获得只有NT AUTHORITY\SYSTEM
权限才能读取的文件的副本。
相关链接和工具
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
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/
最新评论