深入分析CVE-2022-30136 Windows NFS RCE漏洞
最近,安全研究人员Guy Lederfein和Quintin Crist公开了微软Windows操作系统中最近修复的一个远程代码执行漏洞(CVE-2022-30136)的详情,该漏洞最初由Yuki Chen发现并报告。该漏洞是在Windows的网络文件系统(NFS)的实现中发现的,是由于对NFSv4请求的处理不当所致。未经授权的远程攻击者可以通过向目标服务器发送恶意的RPC调用来利用该漏洞。一旦得手,攻击者就能在SYSTEM的上下文中执行任意代码;如果利用失败,则可能导致目标系统发生崩溃。
漏洞详情
Microsoft Windows提供了多种网络功能,旨在与非Windows文件共享进行通信和交互。其中一个模块名为网络文件系统(NFS)。
NFS是最初由SunMicrosystems于1984年开发的网络文件系统协议。其中第二版的详情请参见RFC1094;第三版请参见RFC1813。而第四版由IETF开发,详情见RFC3010(2000年12月发布),并在RFC3530(2003年4月发布)和RFC7530(2015年3月发布)中进行了修订。NFS允许用户以访问本地文件系统的相同方式访问远程文件共享。我们可以在共享上设置不同的访问级别和权限,如读写和只读。此外,它还支持IP/UID/GID/Kerberos等安全措施。NFS使用开放网络计算(ONC)远程过程调用(RPC)来交换控制消息。ONCRPC最初是由Sun Microsystems开发的,也称为Sun RPC。
当ONC RPC消息通过TCP传输时,前面会带有一个Fragment头部结构(如下表所示),该结构指定消息的长度。这允许接收者区分通过单个TCP会话发送的多条消息。而其他协议(如UDP)则不会使用该字段。请注意,所有多字节值都是以大端字节顺序编码的。
ONC RPC请求消息的结构,一般如下所示:
Sun-RPC消息中的Credentials结构具体如下所示:
上面结构体中的Flavor字段用作Contents数据的类型标识符。由于历史原因,Security形式被称为身份验证形式。RPC规范中定义了多种安全形式,例如AUTH_NONE(0)、AUTH_SYS(1)、AUTH_SHORT(2)、AUTH_DH(3)和RPCSEC_GSS(6)。
其中,RPCSEC_GSS形式的Contents字段具有以下结构:
GSS Procedure字段中定义了RPCSEC_GSS_DATA(0)、RPCSEC_GSS_INIT(1)、RPCSEC_GSS_CONTINUE_INIT(2)、RPCSEC_GSS_DESTROY(3)四种类型。此外,在GSSService字段中,定义了rpc_gss_svc_none(1)、rpc_gss_svc_integrity(2)和rpc_gss_svc_privacy(3)三种类型。当使用RPCSEC_GSS对RPC客户端进行身份验证时,必须使用RPCSEC_GSS_INIT和RPCSEC_GSS_CONTINUE_INITRPC消息来创建安全上下文:首先,RPC客户端发送一个RPCSEC_GSS_INIT消息开始创建上下文。然后,RPC 服务器决定是否需要另一个令牌。如果需要的话,服务器会返回GSS_S_CONTINUE_NEEDED消息,客户端需要发送RPCSEC_GSS_CONTINUE_INIT消息才能继续。
如果GSS Service字段设置为2(rpc_gss_svc_integrity),则特定于Program的数据字段将以下面的结构体为前缀:
如果GSS Service字段设置为3(rpc_gss_svc_privacy),则特定于Program的数据字段将被加密。
当Program字段设置为100003(NFS),且Procedure字段设置为1(Compound)时,特定于Program的数据字段具有以下结构:
在NFS的Windows实现中存在一个缓冲区溢出的漏洞。该漏洞是由于不正确地计算响应信息的大小所致:当服务器调用函数Nfs4SvrXdrpGetEncodeOperationResultByteCount()来计算每个操作码响应的大小时,并没有将操作码本身的大小计算进来。这导致响应缓冲区的大小实际上变小了,具体少了OP Count * 4 字节。此后,该实现将用OncRpcBufMgrpAllocate分配一个相应的缓冲区。而当响应数据被写入缓冲区时,就会发生溢出。由于该函数只用于NFS版本4,所以该漏洞只影响该版本。
实际上,当请求的大小低于0x800字节时,函数OncRpcBufMgrpAllocate()是通过OncRpcBufMgrpAllocateDesc riptorFromLLInlineBuffer()来分配数据内存的,否则的话,则用OncRpcBufMgrpAllocateDesc riptorFromLLLargePoolAllocation()函数来进行内存分配。
OncRpcBufMgrpAllocateDesc riptorFromLLInlineBuffer()将返回一个静态的缓冲区,长度为0x800字节,位于描述符内。对于该描述符结构来说,其中有0x50字节的空间,在静态缓冲区之后,似乎是未用到的。
OncRpcBufMgrpAllocateDesc riptorFromLLLargePoolAllocation()函数会返回一个用ExAllocatePoolWithTag()分配的缓冲区。其中,分配的字节数为:
这意味着,对于任何一种缓冲区类型,必须实现超过0x48字节的溢出才能越过任何一种缓冲区类型的填充。由于溢出的字节数是OP Count * 4,在一个复合信息中至少要进行19次操作,溢出才能奏效。
攻击者可以利用这个漏洞发送一个包含大量操作的精心制作的请求,产生足够大的计算错误,从而导致缓冲区溢出。成功的利用会导致在SYSTEM的上下文中执行任意代码;如果利用失败,则可能导致目标系统崩溃。
如何检测相关攻击
这些信息大部分在前面已经提过。为了读者阅读方便,这里再重复一下。
当ONC RPC消息通过TCP传输时,前面会带有一个Fragment头部结构(如下表所示),该结构指定消息的长度。这允许接收者区分通过单个TCP会话发送的多条消息。而其他协议(如UDP)则不会使用该字段。请注意,所有多字节值都是以大端字节顺序编码的。
上面显示了ONC RPC请求消息的结构,以及Sun-RPC消息中的凭据结构。如上所示,这个结构体中的Flavor字段用作Contents数据的类型标识符。由于历史原因,Security形式被称为身份验证形式。RPC信息如上所示中定义了多种安全形式,例如AUTH_NONE(0)、AUTH_SYS(1)、AUTH_SHORT(2)、AUTH_DH(3)和RPCSEC_GSS(6)。
其中,RPCSEC_GSS形式的Contents字段具有以下结构:
GSS Procedure字段中定义了RPCSEC_GSS_DATA(0)、RPCSEC_GSS_INIT(1)、RPCSEC_GSS_CONTINUE_INIT(2)、RPCSEC_GSS_DESTROY(3)四种类型。此外,在GSSService字段中,定义了rpc_gss_svc_none(1)、rpc_gss_svc_integrity(2)和rpc_gss_svc_privacy(3)三种类型。当使用RPCSEC_GSS对RPC客户端进行身份验证时,必须使用RPCSEC_GSS_INIT和RPCSEC_GSS_CONTINUE_INITRPC消息来创建安全上下文:首先,RPC客户端发送一个RPCSEC_GSS_INIT消息开始创建上下文。然后,RPC服务器决定是否需要另一个令牌。如果需要的话,服务器会返回GSS_S_CONTINUE_NEEDED消息,客户端需要发送RPCSEC_GSS_CONTINUE_INIT消息才能继续。
如果GSS Service字段设置为2(rpc_gss_svc_integrity),则特定于Program的数据字段将以下面的结构体为前缀:
如果GSS Service字段设置为3(rpc_gss_svc_privacy),则特定于Program的数据字段将被加密,并且在继续之前必须解密。
检测设备需要检查RPC请求消息中的Program字段是否包含值100003(NFS)、Procedure字段是否包含值1(COMPUND)、ProgramVersion字段是否包含值4(NFS4)。如果发现这些值,设备必须检查ONC RPC消息中特定于Program的数据。
NFS COMPOUND的数据格式具有以下结构:
只有NFS应答中现少有19个操作时,才会触发该缓冲区溢出漏洞。由于NFS应答含有对NFS请求中每个操作的响应,所以,我们应监测请求信息中的OP Count字段是否大于18。
如果检测到操作数量大于18的数据包,应该认为该流量是可疑的;利用该漏洞的攻击可能正在进行。
请注意,所有的多字节值都是以网络(big-endian)字节顺序表示的。另外,如果正常流量包含类似的NFSCOMPOUND请求,那么,这种检测方法可能会产生误报。
小结
Microsoft公司已经于2022年6月修复了该漏洞,并将分配了漏洞编号CVE-2022-30136。在他们的安全报告中,还将禁用NFSV4.1作为缓解攻击的一种方法。但是,这可能导致功能受损。此外,Microsoft公司指出,除非先安装了CVE-2022-26937的修复程序,否则不应采用解决该安全问题的更新程序。以适当的顺序应用这两个更新是完全解决这些漏洞的最佳方法。
最新评论