完成静音:将漏洞串连起来,在 Outlook 上实施 RCE 攻击: 第 1 部分
执行摘要
Akamai 研究人员 Ben Barnea 在 Microsoft Windows 中发现了两个漏洞,这些漏洞被指定为 CVE-2023-35384 和 CVE-2023-36710。
网络攻击者可以将这些漏洞串连起来,构建一个以 Outlook 客户端为目标的完全自动化、无需任何用户交互的远程代码执行 (RCE) 漏洞。
第一个漏洞出现在 MapUrlToZone 函数解析路径的过程中。在利用此漏洞时,攻击者需要向 Outlook 客户端发送经过特殊设计的电子邮件,诱使用户从攻击者操控的服务器下载特殊的声音文件。
第二个漏洞出现在音频压缩管理器 (ACM) 中。当下载的声音文件被自动播放时,攻击者就会利用这个漏洞,在受害者的计算机上执行恶意代码。本博客文章的 第 2 部分 将详细说明此漏洞。
这些漏洞已披露给 Microsoft,并在 2023 年 8 月 和 2023 年 10 月 的 Patch Tuesday 中得到了解决。
安装了 2023 年 10 月软件更新的 Windows 计算机可以防范这些漏洞。此外,如果 Outlook 客户端使用的是已经用 2023 年 3 月软件更新进行修补的 Exchange 服务器,那么这些 Outlook 客户端也可以防范这个被滥用的功能。
概述
在 2023 年 3 月的 Patch Tuesday 中,修复的漏洞包括一个 严重 Outlook 漏洞 ,编号为 CVE-2023-23397。该漏洞被 Forest Blizzard 广泛利用,Microsoft 将其认定为受到俄罗斯国家资助的攻击者。2023 年 12 月,Microsoft 与波兰网络司令部 (DKWOC) 联合 发布 消息称,他们近期发现同一攻击者试图利用该漏洞进行攻击。攻击者利用该漏洞强制 Outlook 客户端连接到他们操控的服务器。在连接过程中,客户端会将 NTLM 凭据发送给攻击者。攻击者随后可以离线破解这些凭据,或者利用它们执行中继攻击。此漏洞可以通过互联网进行远程利用,无需任何用户交互(零点击)。
在针对此漏洞发布修补程序后,我们发现了一种绕过方法,并已在 上一篇博文中已对此作出了解释。这种绕过方法已在 2023 年 5 月的 Patch Tuesday 中得到了修复。在该博文中,我们建议 Microsoft 移除这个被滥用的功能,因为它会造成庞大且复杂的攻击面。考虑到该功能目前仍然存在于 Outlook 中,我们决定对其进行深入研究。
经过一番努力,我们最终在 Outlook 上构建了一条完整的 RCE 漏洞链。我们发现原始 Outlook 漏洞有另一种绕过方法,同样允许我们强制客户端连接到攻击者操控的服务器,并下载恶意声音文件。随后,我们在 Windows 媒体解析库中找到了一个漏洞,该库通常用于处理和播放各种音频文件,其中就包括 Outlook 的通知声音。攻击者通过将这些漏洞串连在一起,可以在易受攻击的 Outlook 客户端上实施零点击 RCE 攻击。
本系列博文分为两个部分,其中将详细介绍我们为发现这两个漏洞所进行的研究。第一部分将重点介绍以前的绕过方法以及新发现的绕过方法。在 第 2 部分,我们将描述我们所发现的媒体解析漏洞。
原始漏洞
当攻击者发送带自定义通知音的提醒电子邮件时,会触发该 Outlook 漏洞(已在 3 月得到修补)。此自定义声音由攻击者指定为路径,在此过程中使用的是扩展的 MAPI 属性 PidLidReminderFileParameter。攻击者可以指定一个 UNC 路径,该路径会导致客户端从任意 SMB 服务器检索声音文件。在与远程 SMB 服务器的连接中,会在协商消息中发送 Net-NTLMv2 哈希值(图 1)。
为了解决这个问题,代码现在会调用 MapUrlToZone ,以便将路径分类为内网路径、本地路径或互联网路径。如果 URL 指向互联网上的资源,则会使用默认的提醒声音,而不是自定义声音。
寻找绕过方法
在防御措施部署到位之后,我们开始思考是否有可能绕过这些措施。
在这种情况下,绕过是指既可以通过本地环境测试,也可以被 Outlook 用于从远程位置下载声音文件的路径。换句话说, 我们需要找到一个符合以下条件的路径: MapUrlToZone 认为该路径是非互联网路径,但 CreateFile 会将其视为互联网域。
要找到这样的绕过方法,我们需要深入理解函数的内部工作原理,以及路径解析过程中所执行的操作。
Windows 路径和 URL
在 Windows 系统中存在多种类型的 DOS 路径 ,人们对这些路径以及它们与 NT 路径之间的转换进行了广泛的研究。我们不会在此详细讨论 Windows 的不同路径类型;因为 James Forshaw 的博文 已经全面讨论了这一主题。
让我们回到本文讨论的函数。 CreateFile 用于接收 Windows 路径; MapUrlToZone (如其名称所示)可以传递 URL 或路径。为了找到绕过方法,我们首先需要了解每个函数(或这两个函数)支持哪些路径类型。
备注: CreateFile 和 MapUrlToZone 不会对路径本身进行处理,而是使用其他 WinAPI 函数来实现这一目的。为了简洁起见,我们将使用 CreateFile 和 MapUrlToZone 来指代它们的底层路径解析函数。
CreateFile |
MapUrlToZone |
|
---|---|---|
RtlPathTypeUncAbsolute |
✔ |
✔ |
RtlPathTypeDriveAbsolute |
✔ |
✔ |
RtlPathTypeDriveRelative |
✔ |
✔ |
RtlPathTypeRooted |
✔ |
✘ |
RtlPathTypeRelative |
✔ |
✘ |
RtlPathTypeLocalDevice |
✔ |
✔ |
RtlPathTypeRootLocalDevice |
✔ |
✘ |
Schemes (file://, http://) |
✘ |
✔ |
表 1: CreateFile 和 MapUrlToZone 路径功能对比图
如表 1 所示,这两个函数只支持四种路径类型: RtlPathTypeUncAbsolute、RtlPathTypeDriveAbsolute、RtlPathTypeDriveRelative 和 RtlPathTypeLocalDevice。
第一次尝试
在第一次尝试寻找绕过方法时,我们使用的是绝对 UNC 路径 (RtlPathTypeUncAbsolute)。图 2 详细呈现了该路径的结构。
Windows 如何知道路径组件从哪里开始?表 2 展示了相关代码 (RtlGetFullPathName_Ustr)。
case RtlPathTypeUncAbsolute:
SeperatorsFound = 0;
for ( CurrentIndex = 2; CurrentIndex < InputPathLength; ++CurrentIndex )
{
CurrentChar = InputPathString->Buffer[CurrentIndex];
if ( CurrentChar == '\\' || CurrentChar == '/' )
{
SeperatorsFound++;
if ( SeperatorsFound == 2 )
break;
}
}
表 2:处理 UNC 路径的 RtlGetFullPathName_Ustr 代码片段
我们可以观察到代码跳过了绝对 UNC 前缀(“\\”),并假设路径组件从第二个路径分隔符(“\”或“/”)后的第一个字符开始。
然而,如果我们提供一个路径,如“\\\\localhost\..\Akamai.com\dir\file.txt”,将会发生什么呢?
该路径将按照以下方式进行处理:
“\\\\”被解释为 UNC 前缀 和 根路径组件
路径组件是“localhost\..\Akamai.com\dir\file.txt”
在正常情况下,“..”的引用不应该超过根目录。例如,“\\localhost\directory\..\file.txt”将被解析为“\\localhost\directory\file.txt”。但在我们的例子中,“..”不是根路径的一部分,因此该路径将被转换为“\\\Akamai.com\dir\file.txt”。
这意味着我们发现了一种方法,可以通过删除部分路径来对其进行修改。
这就是 CreateFile 处理此路径的方式;那么 MapUrlToZone 是如何处理的呢(表 3)?首先,它会删除额外的反斜杠,因而以不同的方式解析该路径:
\\localhost 是服务器名称
\..\ 被忽略(因为我们不能超出服务器名称)
Akamai.com\dir\file.txt 包含路径组件
输入路径:\\\\localhost\..\Akamai.com\dir\file.txt |
|
---|---|
CreateFile |
MapUrlToZone |
\\\Akamai.com\dir\file.txt |
\\localhost\Akamai.com\dir\file.txt |
表 3: CreateFile 和 MapUrlToZone 的输入路径及其解析结果
MapUrlToZone 为上述输出路径返回 0(本地)。
虽然我们似乎找到了绕过方法,但遗憾的是,该路径无法用于触发 UNC 请求。请注意,在处理路径时, CreateFile 会在路径开头添加额外的斜杠,这将导致服务器名称被标记为空。当多 UNC 提供程序 (MUP) 查询不同的网络提供程序是否可以处理这个空服务器名称时,它们全部会返回 false,因此不会触发任何请求。
MapUrlToZone和 CreateFile 对此路径的处理方式存在差异。为了解决滥用这种差异的行为,需要一个更加细致的解决方案,也许要找到一种方法来省略额外的反斜杠,或者在 MUP 代码中找到解析不匹配的地方。这是对未来研究工作的一个建议。
第二次尝试:绕过方法 1 (CVE-2023-29324)
由于使用绝对 UNC 路径未能达到预期效果,我们决定采用另一种支持 UNC 的路径类型—— RtlPathTypeLocalDevice。“\\.\UNC\Akamai.com\test.wav”是本地设备路径的一个示例。具体来说,它指向 UNC 设备名称,而该名将被重定向到 MUP 驱动程序。
正如之前所述,为了寻找绕过方法,我们需要详细研究路径解析过程中的不同操作。表 4 展示了不同的操作。
CreateFile |
MapUrlToZone |
---|---|
如果是 RtlPathTypeLocalDevice → 向前移动 4 个字符 |
如果是 RtlPathTypeLocalDevice → 向前移动 4 个字符 |
跳过尾随空格 |
|
将“/”转换为“\” |
|
折叠重复的“\” |
|
删除“.”和“..”组件 |
删除“.”和“..”组件 |
表 4:在路径解析过程中完成的不同操作
我们可以看到 CreateFile 执行了额外的操作,例如将正斜杠转换为反斜杠,以及折叠重复的反斜杠。
让我们看一下利用这些差异之一(亦即使用额外路径分隔符)的路径。表 5 展示了代码跳过“UNC\”前缀后生成的路径。
输入路径:\\.\UNC\\Akamai.com\test.wav |
|
---|---|
CreateFile |
MapUrlToZone |
Akamai.com\test.wav |
\Akamai.com\test.wav |
表 5:跳过 UNC/ 前缀后生成的路径
请注意右列中的路径。以路径分隔符开头,后跟非路径分隔符字符的路径称为 根路径。MapUrlToZone 使用 IsRootedPath 或 IsDrivePath 函数来判断根路径组件是否指向本地。在我们的示例中,由于路径是根路径,因此 MapUrlToZone 返回 local。
CreateFile 不会在 UNC 前缀之后包含额外的路径分隔符,因此它能够正确地提取域名。现在,它会访问 Akamai.com SMB 服务器以检索 test.wav 文件。 我们找到一个 MapUrlToZone 认为指向本地的路径,但 CreateFile 并不认为它指向本地。这种绕过方法使得 Outlook 漏洞 CVE-2023-23397再次有了可乘之机。
为了解决这个问题,Microsoft 尝试过使这两个流程变得更为相似;将正斜杠转换为反斜杠,以及折叠重复的路径分隔符,这些操作被添加到 MapUrlToZone 路径解析流程中。
一个想法……
在上一节中,我们提到 MapUrlToZone 会检查“\\.\UNC\”之后的路径组件是否指向驱动器或根路径。在进行修复之后,我们无法让这个路径组件指向根路径,因为重复的路径分隔符会被折叠。然而,我们仍然可以提供一个驱动器路径,例如“\\.\UNC\C:Akamai.com/test.wav”。
这样做确实会导致 MapUrlToZone 返回 0。遗憾的是,没有网络服务提供商能够处理带有冒号的路径,因此这种混淆对我们没有帮助。与我们第一次失败的尝试相同,我们发现混淆 MUP 解析代码可能会导致新的漏洞。
第三次尝试:绕过方法 2 (CVE-2023-35384)
经过修复后,两个函数执行的操作几乎相同(表 6)。
CreateFile |
MapUrlToZone |
---|---|
如果是 RtlPathTypeLocalDevice → 向前移动 4 个字符 |
如果是 RtlPathTypeLocalDevice → 向前移动 4 个字符 |
跳过尾随空格 |
|
将“/”转换为“\” |
将“/”转换为“\” |
折叠重复的“\” |
折叠重复的“\” |
删除“.”和“..”组件 |
删除“.”和“..”组件 |
表 6: CreateFile 和 MapUrlToZone 后缀执行的操作
然而,随着对细节的深入探究,我们可以问问自己:每个函数是如何判断路径是本地设备路径的呢?表 7 展示了每个函数中帮助于判断路径类型的代码片段。
CreateFile
if (IS_PATH_SEPARATOR(Path[0]) &&
IS_PATH_SEPARATOR(Path[1]) &&
(Path[2] == '.' || Path[2] == '?') &&
IS_PATH_SEPERATOR(Path[3])
return RtlPathTypeLocalDevice;
MapUrlToZone
!strncmp(path, "\\.\", 4) || !strncmp(path, "\\?\", 4)
表 7:用于判断路径类型的代码片段
对于 CreateFile,路径分隔符可以是正斜杠或反斜杠;例如,“\\./”被认为是本地设备路径。对于 MapUrlToZone,只有精确的“\\.\”或者“\\?\”路径才被认为是本地设备路径。 这就是路径类型混淆。我们可以让 CreateFile 将“\\./”组件识别为本地设备路径,但 MapUrlToZone 却不会这样。这种混淆决定了两个函数会按不同的方法来处理路径。
清楚这一点后,我们可以使用一个包含“造成混淆的”组件的路径: \\./UNC/Akamai.com/file.wav。
在分析如何判断路径类型的过程中, MapUrlToZone使用的流程是:
该路径是本地驱动器还是根路径?否
IsLocalDeviceUNC? 否
PathIsUNCW?是
PathIsUNCW 返回 true,因此该函数将路径标记为 绝对 UNC 路径 ,并向前移动两个字符以跳过 UNC 前缀“\\”。表 8 展示了每个函数的输出。
输入路径:\\./UNC/Akamai.com/file.wav |
|
---|---|
CreateFile |
MapUrlToZone |
UNC\Akamai.com\file.wav |
./UNC/Akamai.com/file.wav |
表 8: CreateFile 和 MapUrlToZone 函数的路径输出
此时, CreateFile 得出结论,其输出为 UNC 路径,而 Akamai.com 是主机名。
相比之下, MapUrlToZone 总结了以下信息:
方案:file://
主机:. (点)
路径:/UNC/Akamai.com/file.wav
绝对 URI:file://./UNC/Akamai.com/file.wav
实际上,当绝对 URI 以“file://./”(其中“.”是主机)开头时,代码将 sharename 解释为 DOS 设备命名空间的一部分(图 3)。因此,“file://./UNC/”指的是 UNC 命名空间。
澄清一下,这两个函数都将我们的输入路径视为 UNC 路径,但类型不同: CreateFile 将其视为 Windows 本地设备路径,而 MapUrlToZone 则将其视为 URL。
此时,我们可以在这两个函数之间制造混淆。遗憾的是,如果我们不做任何小动作, MapUrlToZone 仍然会将 Akamai.com 解释为主机名。由于该主机名是一个互联网域名,该函数将返回 3,因此这并不算是绕过。 我们需要寻找另一种方法来滥用解析过程。
接下来, MapUrlToZone 使用一个名为 SetPath 的内部函数来处理路径组件(表 9)。
CreateFile |
SetPath |
---|---|
如果是 RtlPathTypeLocalDevice → 向前移动 4 个字符 |
|
跳过尾随空格 |
|
将“/”转换为“\” |
|
折叠重复的“\” |
|
删除“.”和“..”组件 |
删除“.”和“..”组件 |
表 9: CreateFile 和 SetPath 完成的操作比较
同样,我们可以利用这两个函数执行的操作之间的差异。我们从之前的漏洞得知,添加额外的斜杠可能导致绕过,所以不妨再试一次。CreateFile 只会删除多余的斜杠。
对于 MapUrlToZone,CreateUri 将返回绝对 URI“file://./UNC//Akamai.com/file.wav”。此 URI 被传递到 GetZoneFromUriInternal,然后在其内部引发另一个 CreateUri 调用。
为什么这是个问题?由于 CreateUri 接收到一个 URL,因此会使用 PathCreateFromUrlW将其转换回 Windows 路径。返回的 Windows 路径是“\\.\UNC\\Akamai.com\test.wav”。经过修复的版本现在能够识别并删除多余的斜杠,因而可以将 Akamai.com 正确地理解为主机名。
这意味着我们需要以更复杂的手段来滥用 CreateFile 和 SetPath之间的差异。这次,我们将滥用两个差异:
CreateFile 折叠重复的路径分隔符。
CreateFile 在折叠重复的路径分隔符后删除“.”和“..”组件
滥用这两个差异的路径是 \\./UNC/C://../Akamai.com/file.wav。图 4 中的流程图详细说明了其处理过程。
图 4:两个函数分析该路径的流程图
我们已经知道 CreateFile的最终路径将被视为 UNC 路径。至于 SetPath的输出, MapUrlToZone 将调用 GetZoneFromUriInternal ,使用的是绝对 URI file://./UNC/C:/Akamai.com/file.wav。这次 PathCreateFromUrlW 将此 URL 转换为 Windows 路径“\\.\UNC\C:\Akamai.com\file.wav”。 这是一个本地路径,因此 MapUrlToZone 返回 0(本地)。我们再次找到了一种简洁的绕过方法!
为了解决这个问题,代码现在会调用 NormalizeDosDevicePrefix 将斜杆转换为反斜杆,以防止在检测本地设备路径时出现混淆。
检测和抵御
Microsoft 发布了关于检测和抵御原始 Outlook 漏洞的 全面指南 。根据我们的观察,所有指定的方法都适用于这个新漏洞,因为它们不依赖于 PidLidReminderFileParameter 属性中指定的 URL。
我们建议企业使用 微分段 来阻止出站 SMB 连接至远程公共 IP 地址。此外,我们建议您在自己的环境中禁用 NTLM,或者将用户添加到 受保护用户组,以防止使用 NTLM 作为身份验证机制。
阻止出站 SMB 连接并禁用 NTLM 之后,有助于防止凭据被盗。但是,如果 SMB 请求失败,并且启用了 WebDAV,Windows 会切换到 WebDAV。虽然凭据盗用不能通过 WebDAV 滥用,但下载声音文件的可能性仍然存在,而这正是我们 RCE 攻击链的第二步。
为什么需要立即予以阻止?
在这篇文章中,我们详细介绍了发现这两种绕过方法的研究流程,包括其根本原因分析。正如我们所展示的那样,Windows 路径解析代码异常复杂,很容易引发漏洞。我们鼓励安全研究人员在遇到路径处理代码时,要认真考虑其造成的攻击面。
除了在 Outlook 上下文中利用 MapUrlToZone 绕过方法之外,我们不能排除这些漏洞也会被用于绕过 Web 标记 (MotW) 安全限制的可能性。
除了泄漏 NTLM 凭据外,我们还可以下载和播放任意声音文件。现在,请阅读 本博客系列的第 2 部分,详细了解声音解析漏洞。