LDAPNightmare:SafeBreach Labs 发布了 CVE-2024-49113 的第一个概念验证漏洞

科技   2025-01-03 14:49   广东  

作者:Or Yair,安全研究团队负责人 | Shahak Morag,研究负责人

Active Directory 域控制器 (DC) 被视为组织计算机网络中的珍宝之一。在 DC 中发现的漏洞通常比在普通工作站中发现的漏洞更为严重。在 DC 上运行代码或使 Windows 服务器崩溃的能力会严重影响网络安全态势。

2024 年 12 月 10 日,Yuki Chen (@guhe120) 发现了两个 LDAP 漏洞:远程代码执行 (RCE) 和拒绝服务/信息泄露,这两个漏洞均会影响任何 DC,并作为最新补丁星期二更新的一部分发布在 Microsoft 安全响应中心 (MSRC) 网站上。RCE 漏洞被指定为 CVE-2024-49112,CVSS 严重性评分为 9.8(满分 10 分);DOS 漏洞被指定为 CVE-2024-49113。但是,这两个漏洞都没有在任何地方发布公开的漏洞利用或博客文章来解释漏洞或利用路径。

SafeBreach Labs 团队定期开展一些项目,我们认为这些项目既可以帮助我们的客户(他们代表着世界上一些最大的品牌),也可以帮助整个安全社区。鉴于此漏洞后果的严重性以及自修复以来受到的关注,我们作为一个团队决定将其列为优先事项,并为我们所发现的有助于企业解决任何潜在风险的发现感到自豪。

高级摘要

SafeBreach Labs 针对 CVE-2024-49113 开发了一个概念验证漏洞,该漏洞可导致任何未修补的 Windows Server(不仅仅是 DC)崩溃,无需任何先决条件,只要受害 DC 的 DNS 服务器具有 Internet 连接即可。

攻击流程:

  1. 攻击者向受害者服务器发送 DCE/RPC 请求

  2. 受害者被触发发送有关 SafeBreachLabs.pro 的 DNS SRV 查询

  3. 攻击者的 DNS 服务器使用攻击者的主机名和 LDAP 端口进行响应 

  4. 受害者发送广播 NBNS 请求来查找收到的主机名(攻击者的)的 IP 地址

  5. 攻击者发送一个 NBNS 响应,其中包含其 IP 地址

  6. 受害者成为 LDAP 客户端并向攻击者的机器发送 CLDAP 请求

  7. 攻击者发送带有特定值的 CLDAP 引用响应数据包,导致 LSASS 崩溃并强制受害者服务器重新启动

我们相信可以利用相同的攻击媒介来实现 RCE;上面提到的整个链,包括前六个步骤,应该是类似的,但最后发送的 CLDAP 数据包应该被修改。  

我们认为我们的发现具有重要意义,原因如下。首先,我们通过证明此漏洞可用于使多个未打补丁的 Windows 服务器崩溃,证明了此漏洞的严重性。根据 Microsoft 的分类,可进一步利用此漏洞导致远程代码执行。其次,我们确实验证了 Microsoft 的补丁修复了越界漏洞,并且该漏洞无法使已打补丁的服务器崩溃。最后,我们提供了一个公共 PoC,组织可以使用它来测试和验证其服务器是否受到保护。有关更多详细信息,请参阅本博客末尾注明的 GitHub 存储库。SafeBreach

Labs PoC 利用的漏洞影响了企业网络中广泛使用的技术,此漏洞可能有助于攻击者更轻松、更有效地传播。SafeBreach 可帮助大型企业识别和解决潜在风险,包括 CVE-2024-49113 等漏洞,SafeBreach 客户很快将能够使用新功能来测试其内部网络是否受到此漏洞和其他漏洞的攻击。请关注www.safebreach.com以获取最新消息。

技术深度探究

下面,我们将解释 SafeBreach Labs 研究团队如何识别触发漏洞并使 DC(或任何 Windows Server)崩溃的利用路径的确切技术细节,提供分步利用摘要,并分享执行这些步骤的概念验证(PoC)工具。

CVE-2024-49113 

CVE-2024-49113 的标题是“Windows 轻量级目录访问协议 (LDAP) 拒绝服务漏洞”。LDAP 是 Microsoft Active Directory 中的工作站和服务器用于访问和维护目录服务信息的协议。漏洞的标题意味着该漏洞可能与 LDAP 相关代码有关。在 MSRC 的 CVE 页面上,Microsoft 提供了一些详细信息,但关于 RCE 漏洞还有其他有趣的数据:

“攻击者如何利用此漏洞?

成功利用此漏洞的远程未经身份验证的攻击者将能够在 LDAP 服务上下文中执行任意代码。但是,成功利用取决于目标组件。

在利用 LDAP 服务器的域控制器的情况下,为了成功攻击,攻击者必须向目标发送特制的 RPC 调用以触发对攻击者的域的查找才能成功。

在利用 LDAP 客户端应用程序的情况下,要想成功,攻击者必须说服或诱骗受害者执行攻击者域的域控制器查找或连接到恶意 LDAP 服务器。但是,未经身份验证的 RPC 调用不会成功。“

根据这些信息(并假设 Microsoft 文档的准确性),我们做出了以下假设:

  1. 攻击者无需进行身份验证

  2. 该漏洞是一种整数溢出漏洞,来源于实现 LDAP 客户端逻辑的可执行文件或动态链接库 (DLL)

  3. 我们可以利用 RPC 调用来影响 DC 查询攻击者控制的 LDAP 服务器

  4. 在 DC 上下文中,漏洞可能存在于lsass.exe或其加载的某个 DLL 中,因为lsass.exe在 DC 上实现 LDAP 服务

  5. 因此,具有易受攻击的 LDAP 客户端代码的 RPC 调用的 RPC 接口位于 lsass.exe 中或其加载的某个 DLL 中

此外,我们还在 X 上发现了 Artur Marzano(@MacmodSec)的有趣见解,其中暗示了微软针对该漏洞的补丁可能位于 wldap32.dll 中:

这个见解与 MSRC 网站上的文档完全吻合,因为 wldap32.dll 实现了 LDAP 客户端的逻辑。

触发远程 LDAP 请求

我们首先证明针对 DC 的第一步利用方法 — 影响它以查询我们控制的 LDAP 服务器。我们需要找到源自 lsass.exe 本身的 RPC 调用,或找到加载到 lsass.exe 中的 DLL 中的 RPC 调用,该调用从 wldap32.dll 导入函数。使用 RpcView,我们列出了加载到 lsass.exe 中的可用 RPC 接口:

在这些 RPC 接口中,我们仅列出了依赖于 wldap32.dll 并使用其导出函数的 DLL 中的接口。我们正在寻找不需要身份验证的 RPC 接口,因为我们假设攻击者不需要进行身份验证。我们发现两个有趣的接口提供了几个有趣的 RPC 调用,这些调用似乎与 LDAP 查询有关,并且可能触发一个查询,它们位于 lsasrv.dll 和 netlogon.dll 中:

使用 IDA,我们从底层开始搜索主动使用从 wldap32.dll 导入的函数之一的 RPC 调用。经过长时间的搜索,我们发现了 DsrGetDcNameEx2。根据微软的文档:

“DsrGetDcNameEx2 方法应返回有关指定域和站点中的域控制器 (DC) 的信息。如果 AccountName 参数不为 NULL,并且与请求的功能相匹配的 DC(如 Flags 参数中所定义)在此方法调用期间做出响应,则该 DC 将验证 DC 帐户数据库是否包含指定 AccountName 的帐户。

NET_API_STATUS DsrGetDcNameEx2(
   [in, unique, string] LOGONSRV_HANDLE ComputerName,
   [in, unique, string] wchar_t* AccountName,
   [in] ULONG AllowableAccountControlBits,
   [in, unique, string] wchar_t* DomainName,
   [in, unique] GUID* DomainGuid,
   [in, unique, string] wchar_t* SiteName,
   [in] ULONG Flags,
   [out] PDOMAIN_CONTROLLER_INFOW* DomainControllerInfo
 
)
;

这个函数看起来非常有前途。除了验证特定帐户是否存在之外,它还会主动检索域控制器的主机名。域名和帐户均由调用者指定。这意味着,如果该函数使用 LDAP 来实现其目的,我们就得到了所需的东西。

接下来,我们需要了解 DsrGetDcNameEx2 的每个参数以及我们为它们设置的值:

  • ComputerName:目标 DC 的主机名 - 这将设置为受害者的主机名(进一步的研究表明,这个值对于该功能来说根本不重要)

  • AccountName:将在查询的攻击者域中搜索的帐户名 - 可以是任何名称 - 我们不关心它是否存在

  • AllowableAccountControlBits:控制查询“AccountName”的内容 - 可以为 0 - 我们并不真正关心查询的帐户

  • DomainName:将被查询的域 - 我们将其设置为攻击者的域名

  • SiteName:DC 必须位于的站点 - 可以设置为 NULL

  • Flags——调用的额外配置——我们首先想要默认行为,因此我们将其设置为 0

  • DomainControllerInfo – 输出参数,返回的信息将放在此处

为了测试目的,我们在同一个子网中安装了两个新的 DC,并在每个 DC 中创建了两个新的根域。一个叫做 SBRESEARCH.LAB,另一个叫做 TESTDOMAIN.LAB。目标是在 SBRESEARCH.LAB 的 DC(攻击者)上运行,并让 TESTDOMAIN.LAB 的 DC(受害者)查询 SBRESEARCH.LAB 的 DC 上的 LDAP 服务器。

因此,在攻击者 DC 上运行时,我们在受害者 DC 上调用了 DsrGetDcNameEx2 函数。调用的参数是:

  • 计算机名称 – WIN-ELD41******

  • 帐户名称 – 用户1

  • AllowableAccountControlBits – 0

  • 域名 – SBRESEARCH.LAB

  • 站点名称 – NULL

  • 旗帜 — 0

不幸的是,这还不够。在 Wireshark 中查看受害者发送和接收的数据包,我们没有看到受害者发起的任何 LDAP 请求。但是,Wireshark 确实向我们展示了一些非常有趣的东西。我们看到受害者向其 DNS 服务器发送了有关 SBRESEARCH.LAB 子域的 DNS 查询。DNS 查询以错误代码回复,指出 DNS 服务器未找到有关该域的任何记录。那么调用失败的原因就完全说得通了。受害者 DC 获得有关此查询的成功答案的唯一方法是攻击者 DC 是其 DNS 服务器。但我们不能只更改 DC 的 DNS 服务器;仅此一点就可能被视为漏洞:

发送的特定 DNS 查询是 SRV 类型。DNS SRV 查询指定一个域名,响应中会将另一个域名和端口映射到该域名。受害 DC 发送的两个查询的具体完整域名为:

  • _ldap._tcp.默认第一个站点名称._sites.dc._msdcs.SBRESEARCH.LAB

  • _ldap._tcp.dc._msdcs.SBRESEARCH.LAB

太棒了!看起来受害者 DC 确实在攻击者域中寻找 LDAP 服务器。如果我们能够成功解决此 DNS 查询,那么受害者的 LDAP 查询就有可能发生。但如果我们无法更改受害者的 DNS 服务器,我们还能做什么?

我们必须控制受害者的 DNS 服务器才能成功解决查询吗?受害者的 DNS 服务器不知道 SBRESEARCH.LAB,但它知道其他域名。受害者 DNS 服务器所知道的域名并非全部都是手动配置的。当然,该 DNS 服务器知道“google.com”。Google 做了什么才能让该 DNS 服务器知道?他们在互联网上购买了一个域名,所以这正是我们所做的。

我们购买了域名“safebreachlabs.pro”,并为其创建了两个 SRV 记录:

  • _ldap._tcp.默认第一个站点名称._sites.dc._msdcs.safebreachlabs.pro

  • _ldap._tcp.dc._msdcs.safebreachlabs.pro

这些 SRV 记录需要返回一个域名(不支持 IP)和一个端口,受害者可能会将其作为 LDAP 服务器进行联系。乍一看,这似乎意味着受害者必须联系在 Internet 上具有公共 IP 的 LDAP 服务器,而我们不希望出现这种要求,因为防火墙可能会阻止此类通信。但是,如果我们已经可以访问 DC 的子网,我们也许可以将 SRV 记录返回的域名设置为我们在子网中控制的计算机的主机名。因此,我们将两个 SRV 记录都映射到攻击者 DC 的主机名和端口 389(其 LDAP 服务器)。
随后,我们进行了另一项测试。在攻击者 DC 上运行时,我们再次在受害者 DC 上调用 DsrGetDcNameEx2 函数,但这次将 DomainName 参数更改为“safebreachlabs.pro”,而不是“SBRESEARCH.LAB”,并且成功了。受害者 DC 向我们的攻击者 DC 发出了 LDAP 查询。

如上图所示,查询是在无连接 LDAP (CLDAP) 中发送的,并使用 UDP 而不是 TCP。使用 Windbg,我们能够验证,即使此请求是在 CLDAP 中发出的,它仍然由 wldap32.dll 执行。

发送恶意 LDAP 响应

一旦我们设法让受害者 DC 查询我们的攻击者 LDAP 服务器,我们就可以继续了解该查询的响应中需要包含哪些内容。这是为了让受害者执行 Artur Marzano 发现的假定易受攻击的函数 - LdapChaseReferral。

引用允许将 Active Directory 树划分到多个 LDAP 服务器之间。

当 LDAP 服务器无法回答请求时,它可以回复对其他可能提供查询答案的服务器的引用。然后,客户端可以“追踪”这些引用并查询被引用的服务器。需要注意的是,客户端没有义务“追踪”这些引用。但是,在我们的例子中,它确实会追踪它们。

为了让服务器表明它没有查询的答案并将客户端引导到不同的服务器,它需要使用“引导”LDAP 结果代码(等于 10)进行回复。响应还必须包含有效的 LDAP URL(以“ldap://”或“ldaps://”开头)。

回到我们的利用场景,为了触发 LdapChaseReferral 函数,我们创建了自己的定制 LDAP UDP 服务器,允许我们发送这样的引荐响应包。

从补丁的逻辑上看,微软添加了一个条件,用于验证某个值是否不大于另一个值。根据此逻辑旁边打印的日志,这些比较的值被命名为“lm_referral”和“referral table size”。“lm_referral”取自“ldap_message”结构(可能是我们的响应消息),“referral table size”取自“ldap_connection”结构。条件检查“lm_referral”值是否在“referral table”的范围内。这个范围就是“referral table size”。

在没有补丁的漏洞版本中,这个“lm_referral”值确实用于访问引用表内的某个偏移量:

在使用 Windbg 的测试中,我们发现“lm_referral”中的值始终等于 0,而指向引用表的指针也等于 0。但是,确定代码是否访问“引用表”的条件仅验证“lm_referral”值是否不为零。这意味着,为了触发漏洞,我们必须控制“lm_referral”变量并使其非零。如果我们成功了,那么代码将取消引用我们可以使用 lm_referral 的值控制的指针。

在搜索“ldap_message”结构中的“lm_referral”变量的填充位置时,我们在 wldap32.dll 中查找了“ldap_message”结构中“lm_referral”偏移量被使用的其他情况(+0x3C)。这导致了两个函数:LdapInitialDecodeMessage 和 LdapChaseReferral:

然后我们找到了在LdapInitialDecodeMessage中设置“lm_referral”的代码:

我们看到的是“msgid”和“lm_referral”取自数据包的同一部分。

在上面的截图中,“value_from_response_packet”必须是 4 字节 DWORD,才能使“lm_referral”成为非零 WORD,因为移位了 25。

在我们使用自定义 UDP LDAP 服务器发送的默认响应数据包中,我们可以完全控制“value_from_response_packet”的值(如上图所示),它的长度为 1 个字节。我们了解到,这个值以其长度为前缀。

然后我们明白了为了给“lm_referral”设置非零值我们需要做什么:

  • 将表示“value_from_response_packet”(“lm_referral”和“lm_msgid”的组合)长度的字节从 1 更改为 4。

  • 现在“value_from_response_packet”的长度为 4 个字节,我们可以从中设置最高有效字节,这将影响“lm_referral”。请记住,我们只能将此字节设置为可以被 2 整除的值,否则会影响“lm_msgid”的值

这两个操作会将代码流指向易受攻击的代码范围,并在发生取消引用时创建访问冲突:

由于“ref_table”等于NULL,而此时的“lm_referral”为非零值,上图中的最后一行代码将触发对不存在地址的取消引用,从而导致越界读取并破坏 LSASS 和整个操作系统。

下一步:实现 RCE

基于此处概述的初步研究,我们继续致力于实现完整的 RCE 链 (CVE-2024-49112)。我们尚未实现这一目标,但已取得了一些进展。在本节中,我们将描述这一进展。

为了不崩溃并继续利用漏洞,我们计划找到一种方法来触发解析 CLDAP 响应的代码中的整数溢出,因为 MSRC 记录 CVE-2024-49112 是由整数溢出触发的。

我们分析了修补版本和未修补版本的 DLL 之间的差异,并找到了整数溢出修复。修复是通过添加对函数 ULongMult、ULongAdd 和 ULongSub 的调用来实现的。这些函数执行加法/乘法/替换并检查是否发生溢出。此外,它们将结果存储在输出参数中。

这些函数是微软针对以前的整数溢出漏洞(例如 MS16-098)的常用缓解措施。请参阅我们之前对此修补方法的分析。

以下是修补后的 DLL 中这三个新添加函数的交叉引用:

我们开始研究修复程序,至少目前我们得出结论,我们检查的修复程序可能不会导致 RCE。我们从 LdapParseResult 开始。在左侧,我们可以看到函数 LdapParseResult 的未修补版本,在右侧我们可以看到修补版本,该版本在调用 ldapMalloc 之前添加了对 ULongMult 的调用。

我们验证了如果我们返回常规 CLDAP 响应而不是崩溃的 LSASS 响应,我们的漏洞代码就会触发此函数,但这还不够。仅当第六个参数不为零时,此函数才会获取此修补代码。此第六个参数是一个表示引用的 unicode 字符串。根据我们的检查,我们调用的 RPC 方法导致该参数始终为零。还有其他对 LdapParseResult 的交叉引用,但我们没有成功找到调用它并使用我们使用的 RPC 调用将第六个参数设置为非零值的流程。它可能可以通过与我们使用的 RPC 调用不同的 RPC 调用触发 - DsrGetDcNameEx2。现在,我们将尝试使用 DsrGetDcNameEx2。

我们决定转向不同的攻击流程。我们分析了对 ULongMult 的其他调用,并专注于函数 SendLdapSearch。

就在对 ULongMult 的调用下方,我们发现了一个错误打印,它验证了整数溢出缓解:

这是未修补的代码:

我们能够访问此函数,甚至可以访问对 ldapMalloc 的调用:

在相关代码中,我们了解到传递给 strlenW 的变量是作为 RPC 调用结果的搜索的一部分发送的 LDAP 过滤器。如果 filterLength 乘以 2,并且 filterLength 足够长,则会发生溢出,并且分配的内存与过滤器长度相比会非常小。需要注意的一件重要事情是,我们控制此过滤器中的某些元素,例如用户名和 DnsDomain:

我们尝试发送一个非常长的用户名,但似乎触发此溢出的用户名值所需的长度太大,无法传递给 DsrGetDcNameEx2 RPC 调用。 

我们仍在调查对三个整数溢出缓解函数的其他引用,一旦我们有新的发现,我们将在此提供更多更新。

漏洞 PoC

我们创建了一个研究存储库,其中包含 LDAP Nightmare 漏洞的 PoC,组织可以使用它来测试和验证他们的服务器是否受到此漏洞的保护。

https://github.com/SafeBreach-Labs/CVE-2024-49113

受影响的 Windows 服务器

虽然我们的研究重点是 Windows Server 2022(DC)和 Windows Server 2019(非 DC)的测试,但我们相信此漏洞利用路径和 PoC 适用于修补点之前的任何 Windows Server 版本。

减轻

为了减轻此漏洞的风险,组织应实施 Microsoft 发布的补丁程序(详情请见此处)。如上所述,SafeBreach Labs 已验证该补丁程序足以防止被测试服务器被利用和崩溃。我们认为修补此漏洞是时间紧迫的,但也明白修补 DC 和 Windows 服务器必须小心谨慎。

因此,我们建议组织实施检测以监控可疑的 CLDAP 引荐响应(具有特定的恶意值设置)、可疑的 DsrGetDcNameEx2 调用和可疑的 DNS SRV 查询,直到可以应用补丁。

结论  

这项研究旨在探索 LDAP CVE-2024-49113 漏洞是否可被利用。我们的研究证明,该漏洞不仅可针对域控制器进行利用,还可影响任何未打补丁的 Windows Server。

此外,我们还提供了一个漏洞 PoC 用于测试,如上文所述。

我们还认为,这将使 CVE-2024-49112 在不久的将来更有可能被利用,因此我们建议修补这两个漏洞。


感谢您抽出

.

.

来阅读本文

点它,分享点赞在看都在这里

Ots安全
持续发展共享方向:威胁情报、漏洞情报、恶意分析、渗透技术(工具)等,不会回复任何私信,感谢关注。
 最新文章