CVE-2024-37079:VMware vCenter Server 整数下溢代码执行漏洞





















2024年6月,天工实验室发现并协助VMware修复CVE-2024-37079和CVE-2024-37080两个严重漏洞,攻击者可构造恶意请求,远程触发vCenter Server任意代码执行。8月28日,趋势科技研究团队对CVE-2024-37079漏洞进行了详细分析,以下是文章翻译内容。



VMware vCenter Server 发现并公布存在一个整数溢出漏洞,该漏洞源于在执行减法操作时,未对计算得出的响应头大小进行充分验证。


远程且未经身份验证的攻击者可以通过向目标服务器发送精心设计的 DCERPC 数据包来利用此漏洞。成功利用该漏洞可能引发堆缓冲区溢出,从而导致在受影响的服务中执行任意代码。



漏 洞   


VMware vCenter Server 是 VMware Inc. 开发的一款数据中心管理服务器应用程序,主要用于管理 vSphere 平台,这是 VMware 用于构建虚拟化云基础架构的核心系统。vCenter Server 通过依赖 VMware 的 Likewise Open 项目分支来支持 DCERPC,特别是支持与 Microsoft 服务和产品(如 Active Directory)交互所需的 MSRPC 协议。具体而言,vCenter Server 在 VMware 证书管理服务 (vmcad)、VMware 目录服务 (vmdird) 和 VMware 身份验证框架 (vmafdd) 中使用了 Likewise Open 的 libdcerpc.so 库,这些服务分别通过外部网络的 TCP 端口 2014、2012 和 2020 进行访问。



DCERPC     


带有 Microsoft 扩展 ( MSRPC ) 的DCERPC(分布式计算环境/远程过程调用),用于透明地执行远程服务器上的功能。为了促进这一过程,使用接口定义语言 (IDL) 定义接口。IDL 代码在服务器和客户端之间共享并定义用于网络通信的数据结构。每个接口都由 UUID 标识,并包含抽象数据类型和函数声明。要通过 DCERPC 调用远程服务器上的函数,客户端需要通过发送包含函数所属接口的接口 UUID 的绑定请求 ( RPC C CN PKT BIND, 0x0b ), 来建立上下文。一旦建立上下文,客户端将发送所需的 RPC 调用,或通过发送更改上下文 ( RPC C CN PKT ALTER CONTEXT, 0x0e ) 请求来修改上下文。本文感兴趣的其他 RPC 请求和响应类型包括:

  • Bind Acknowledgement ( RPC C CN PKT BIND ACK , 0x0c ) – 对绑定请求成功完成的确认

  • Bind Negative Acknowledgement ( RPC C CN PKT BIND NAK , 0x0d ) – 对绑定请求拒绝的通知

  • Alter Context Respons ( RPC C CN PKT ALTER CONTEXT RESP , 0x0f ) – 对更改上下文请求的响应


DCERPC 消息公共头具有以下结构:

Offset  Length    Description        (bytes)------  ------    -----------0x00    1         Version (major)0x01    1         Version (minor)0x02    1         Packet type
0x03 1 Packet flags0x04 4 Data Representation0x08 2 Fragment length (frag_len)0x0A 2 Authentication length (auth_len)0x0C 4 Call ID0x10 Variable Type Specific Data (dependent on packet type)

Data Representation字段的四个最高有效位(即通过与 0xF0000000 进行 AND 运算获得的位)包含有关字节顺序的信息。如果这些位全为零,则 DCERPC 消息采用大端编码;否则,它是小端编码。


对于本报告来说,重要的是“Packet flags”字段中的“lastfrag”标志 (0x02)。如果设置,则给定片段是多片段传输的最后一个片段。



DCERPC 请求数据包    


在请求数据包中,公共头后面跟着数据包类型特定的字段。对于Bind 和 Alter Context,类型特定数据字段将设置为以下结构:

Offset  Length    Description        (bytes)------  ------    -----------0x00    2         Max transmit fragment size0x02    2         Max receive fragment size0x04    4         Associated group ID0x08    Variable  Presentation Context List

本文中最重要的是Presentation Context List,其结构如下:

Offset  Length    Description        (bytes)------  ------    -----------0x00    1         Number of context elements (n_context_elem)0x01    1         Reserved (alignment pad, must be zero)0x02    2         Reserved (alignment pad, must be zero)0x04    Variable  Presentation context elements

其中每个 Presentation Context Element 定义为:

Offset  Length    Description        (bytes)------  ------    -----------0x00    2         Presentation context ID (pres_context_id)0x02    1         Number of transfer syntaxes (n_transfer_syn, N)0x03    1         Reserved (alignment pad, must be zero)0x04    20        Abstract syntax (UUID + version)0x18    20 * N    Transfer syntaxes (each transfer syntax is 20 bytes for UUID + version)

语法如下:

Offset  Length    Description        (bytes)------  ------    -----------0x00    16 UUID   (id)0x10    4         Version

DCERPC 数据包可以包括可选的身份验证 trailer(也称为身份验证验证器),其中包含身份验证或授权数据。当且仅当 auth len 字段非零并设置为 trailer 的长度(以字节为单位)时,trailer 才会存在。常见的身份验证 trailer 具有以下格式:

Offset  Length    Description        (bytes)------  ------    -----------0x00    1         Type (auth_type)0x01    1         Level (auth_level)0x02    1         Padding length (auth_pad_length)0x03    1         Reserved (auth_reserved)0x04    4         Context ID (auth_context_id), aka Key ID (key_id)0x08    Variable  Credentials (auth_value)

值得注意的是,标头中的 auth len 仅指示 auth value 的长度,而不是整个 trailer 的长度,其中有 8 个额外字节用于静态字段。 


libdcerpc.so 支持以下身份验证类型及其相应的 ID: 

  • 具有 SPNEGO 机制的 GSS-API (0x09)

  • NTLMSSP (0x0a)

  • 具有 Kerberos 机制的 GSS-API (0x10)

  • Netlogon 安全通道 (0x44)


本文选取第一个类型(0x09)用于解释和漏洞演示。注意,所选类型不是漏洞本身的一部分,仅用于演示其影响。



GSS-API、SPNEGO 和 SRP    


当身份验证 trailer 的 auth type 字段设置为具有 SPNEGO 机制的 GSS-API (0x09) 时,auth value 字段保存具有以下结构的 ASN.1 编码的 GSS-API 数据负载:

GSSAPI         ::=   [APPLICATION 0] IMPLICIT SEQUENCE {  mech                MechType,  negTokenInit        NegotiationToken}
NegotiationToken ::= CHOICE { negTokenInit [0] NegTokenInit, negTokenTarg [1] NegTokenTarg}
NegTokenInit ::= SEQUENCE { mechTypes [0] MechTypeList OPTIONAL, reqFlags [1] ContextFlags OPTIONAL, mechToken [2] OCTET STRING OPTIONAL, mechListMIC [3] OCTET STRING OPTIONAL}
MechTypeList ::= SEQUENCE of MechType
MechType ::= OBJECT IDENTIFIER

当 mech 字段的值为对象标识符 (OID)“1.3.6.1.5.5.2”时,GSS-API 数据代表一个简单且受保护的 GSS-API 协商 (SPNEGO) 消息,该消息允许客户端协商与服务器的特定身份验证机制。mechTypes 保存客户端支持的身份验证机制的 OID 列表(例如 Kerberos、NTLM 等),mechToken 是列表中第一个机制的初始 token。 


安全远程密码 (SRP)是可以与 vCenter 服务协商的机制之一。这种机制与 GSS-API 的使用尚未明确定义,但可以在 VMware 的 Project Lightwave 中找到对其的引用。该机制使用“made up”(即未正式注册)OID“1.2.840.113554.1.2.10”,其 mechToken 具有以下伪 ASN.1 定义,从 Lightwave 源代码重构:

SRPMechToken   ::= [APPLICATION 0] SEQUENCE {    mechType          OBJECT IDENTIFIER,    authData          [APPLICATION 1] SEQUENCE {        ver_maj       INTEGER,        ver_min       INTEGER,        userName      OCTET STRING,        publicValue   OCTET STRING    }}

其中 mechType 设置为 OID“1.2.840.113554.1.2.10”,ver maj 和 ver min 分别设置为 1 和 0,userName 是有效的用户主体名称 (UPN),例如“[email protected]”,并且publicValue是大型客户端的公共数据(在RFC 2945中称为A)。 


SPNEGO SRP 响应 token 可以定义如下:

SPNEGOToken   ::= SEQUENCE {    negTokenResp  NegTokenResp}

NegTokenResp ::= SEQUENCE { negResult [0] ENUMERATED { accept-completed (0), accept-incomplete (1), reject (2), request-mic (3) } OPTIONAL, supportedMech [1] MechType OPTIONAL, responseToken [2] OCTET STRING OPTIONAL, // encoded SRPResponse mechListMIC [3] OCTET STRING OPTIONAL}
MechType ::= OBJECT IDENTIFIER
SRPResponse ::= [APPLICATION 2] SEQUENCE { MDA OCTET STRING, // Message Digest Algorithm salt OCTET STRING, publicValue OCTET STRING}

这里,publicValue是大型服务器的公开数据(在RFC 2945中称为B)。



DCERPC 响应数据包    


DCERPC 响应数据包(即从服务器发送回客户端的数据包)具有与请求数据包类似的结构。它们以公共标头开始,后跟数据包类型特定的数据字段。Bind和Alter Context请求报文对应的响应报文类型为Bind Acknowledgement、Bind Negative Acknowledgement、Alter Context Response。在这三者中,本报告仅涉及Bind Acknowledgement 和 Alter Context Response:Bind Negative Acknowledgement仅在发生错误时生成,应避免这种情况。 


Bind Acknowledgement 和 Alter Context Response都具有相同的结构:

Offset      Length    Description            (bytes)----------  ------    -----------0x00        16        Common header0x10        2         Max transmit fragment size0x12        2         Max receive fragment size0x14        4         Association group ID0x18        Variable  Secondary address (sec_addr,                      N, with alignment) [if present]                      0x18+N      Variable  Presentation result list (pres_result_list,                      M, with alignment) [if present]0x18+N+M    Variable  Authentication trailer (auth_tlr)                      [if present and auth_len != 0]

这里重要的字段是Secondary Address, Presentation Result List, 和 Authentication Trailer。在这种情况下,Secondary Address是目标服务的端口,例如 vmdird 的“2012”,包括空终止符并以 2 字节长度整数作为前缀。对于请求的Presentation Result List 中的每个元素,表示结果列表包含一个 24 字节的结果,加上 4 个字节的静态字段。Authentication Trailer 的结构与请求中的结构相同。注意,对于上述 SPNEGO SRP 机制,trailer 包含较大的认证数据。



漏洞的更多详细细节    


VMware vCenter Server 发现并公布存在一个整数溢出漏洞,该漏洞源于在执行减法操作时,未对计算得出的响应头大小进行充分验证。


有两种类型的请求数据包会导致该漏洞被触发:Bind Acknowledgement 和 Alter Context Response。与其他数据包(以及片段缓冲区)相反,这些数据包没有大小限制:虽然所有其他类型最多可以包含 4096 字节的数据(这使得片段缓冲区最多为 4158 字节),但这些数据包可以在 receive packet() 函数中发现没有这样的限制。


libdcerpc.so 的操作基于协议状态机。当接收到数据包时,对于给定客户端对应的状态机,会生成事件。该事件指示接下来必须采取什么操作才能继续协议流程。根据事件,接收到的数据包将传递到其中一个处理程序。在正常操作中,对于Bind packets,处理程序是 do assoc action rtn(),对于 Alter Contextincr 是 do alter action rtn(),这两个函数最终都会调用负责构建响应的实际数据包处理器:分别是 do assoc req action rtn() 和 do alter cont req action rtn()。要达到前者,有一个限制:要么必须设置lastfrag标志,要么次要RPC版本必须为0。 


从这一点来看,我们将重点关注 do assoc req action rtn() 和 do alter cont req action rtn() 的流程几乎相同,但有一些细微的变化。

sizeof(static fieds) + sizeof(Result Element) * N <= sizeof(Remainder of the Response Buffer)
    4 + 24 * N <= 4096 - 32
    24 * N <= 4060
     N <= 169.16

这就限制了Presentation Context List 元素的数量。如果设置为最大值 169,则返回的 Presentation Result List 大小为 4060 字节,加上先前响应缓冲区的内容,需要 4092 字节。 


假设没有返回错误,接下来会调用易受攻击的 rpc cn assoc process auth tlr() 函数,该函数负责处理请求的身份验证 trailer 并为响应填充一个回复,其 header size 参数设置为 4092,auth len参数设置为 4096 – 4092 = 4 。


要实现这部分函数的攻击,必须满足以下条件:

首先,请求的 auth len 不得为零,并且 authentication trailer 不得超出数据包的长度限制。


其次,RPC CN AUTH CVT ID WIRE TO API() 不得返回错误。该函数将从数据包中获取的身份类型转换为内部表示;因此,使用有效类型(例如 SPNEGO 的 0x9)足以通过此检查。


接着,RPC CN AUTH INQ SUPPORTED() 必须对选择的协议返回肯定结果。此函数确保运行时支持所选的身份验证类型。同样,允许使用 SPNEGO。


之后,调用 RPC CN AUTH VFY CLIENT REQ() 函数,负责验证请求的authentication trailer。该函数是动态的:实际调用的函数取决于所选的身份验证类型。例如,对于 SPNEGO,它是 rpc gssauth cn vfy client req()。虽然这个函数确实验证authentication trailer,但凭据不一定需要是有效的,因为authentication rejection也必须放在响应中。此外,对于某些协议,例如SPNEGO,在完成凭证验证之前需要多次交换。


最后,填充response authentication trailer。为此,将 8 个字节(不带 auth value 的trailer)添加到 header size,将其设置为 4092 + 8 = 4100,并且不为 auth value 留下任何空间。然而,在计算剩余空间时,会从最大响应大小 (4096) 中执行无符号减法 4100,从而得到一个较大的正值 0xfffffffc,该值稍后会传递到 RPC CN AUTH FMT SRVR RESP() 函数中,与 RPC CN AUTH VFY CLIENT REQ() 相同,该函数是动态的,实际调用的函数取决于所选的身份验证类型。


注意,导致堆溢出的Presentation Context List元素的数量严格为169:上面已经建立了上限,下限可以根据结果 header size 低于最大响应数据包大小的事实来确定仅 4 个字节。即使减少 1 个 Presentation Context Lis 元素的数量也会导致 Presentation Result List 的长度减少 24 个字节,因此 header size 减少 24 个字节,从而不会导致下溢。


未经身份验证的远程攻击者可以通过向目标服务器发送精心设计的 DCERPC 数据包来利用此漏洞。成功利用此漏洞可能会导致堆缓冲区溢出,从而导致在存在漏洞的服务中执行任意代码。 


下面以 SPNEGO SRP 认证协议为例,解释该漏洞如何导致堆溢出。


对于SPNEGO,RPC CN AUTH VFY CLIENT REQ() 函数调用会导致控制权传递给 rpc gssauth cn vfy client req() 函数。该函数又调用 gss accept sec context() 库函数,该函数返回包含响应 auth value 的 output token。如果发生任何错误,output token 的长度将设置为零。然后将该 token 保存到与客户端关联的安全上下文中的 krb message 字段中。 


虽然对于其他协议,token 可能很小,但对于 SPNEGO SRP,如上所述,它包含大型服务器的公开数据。


最终,当调用 RPC CN AUTH FMT SRVR RESP() 函数时,控制权将传递给 rpc gssauth cn fmt srvr resp() 函数,其中 auth value len 指向较大的正值 0xffffffffc,auth value 指向响应缓冲区的末尾。该函数负责将 krb message 字段的内容复制到 auth value,但前提是有足够的空间。为了确保这一点,该函数首先将 krb message 的长度与 auth value len 处的值进行比较。鉴于 auth value len 指向整数下溢产生的值,并且比较是无符号的,因此该检查始终通过。接下来,krb message 的内容被复制到 auth value,该值同样没有任何可用空间。对于 SPNEGO SRP,它在 krb message 中具有较大的响应 token,这会导致堆缓冲区溢出和堆损坏。



通用攻击检测    


为了检测利用该漏洞的攻击,检测设备必须监控并解析端口2012/TCP、2014/TCP和2020/TCP(DCE/RPC)上的流量。 


检测设备必须监视 DCE/RPC 流量,查找数据包类型设置为Bind(RPC C CN PKT BIND,0x0b)或 Alter Context (RPC C CN PKT ALTER CONTEXT,0x0e)的消息。如果找到,检测设备应检查 auth len 字段是否大于零。如果是,则必须检查上下文元素数量 (n context elem) 字节。如果大于或等于169,则应将流量视为可疑,可能正在利用这个漏洞进行攻击中。



总  结    


该漏洞已于 6 月份由厂商修复。在发布补丁时,该漏洞引起了相当多的关注。然而,迄今为止,还没有发现在野利用。如上所述,利用不会是直截了当的。尽管如此,这是一个严重的漏洞,应该下载厂商提供的补丁来修复。如果您无法更新应用,您还可以使用本文“攻击检测”部分提供的信息过滤恶意流量。


特别感谢趋势科技研究团队的 Grigory Dorodnov 和 Guy Lederfein 对此漏洞提供了全面的分析。


原文链接:https://www.zerodayinitiative.com/blog/2024/8/27/cve-2024-37079-vmware-vcenter-server-integer-underflow-code-execution-vulnerability



END



原文始发于微信公众号(奇安信天工实验室):CVE-2024-37079:VMware vCenter Server 整数下溢代码执行漏洞

版权声明:admin 发表于 2024年8月29日 下午5:06。
转载请注明:CVE-2024-37079:VMware vCenter Server 整数下溢代码执行漏洞 | CTF导航

相关文章