0x01 漏洞描述
近期,VMware发布了CVE-2020-3952的安全公告,公告中称 VMware Directory Service(vmdir)存在敏感信息泄露漏洞。除了最新版本的其他vCenter Server v6.7都会受到攻击。
该漏洞的CVSS得分为10.0,这个分数就非常高了。尽管获得了许多信息,但仍未找到有关该漏洞的技术细节记录,希望更多地了解其风险,并了解攻击者如何利用它们,因此开始分析VMware下发的补丁程序vCenter Appliance 6.7 Update 3f中的更新。
通过梳理对vCenter Directory服务的更新,重建了导致此漏洞的漏洞代码流。分析表明,通过三个简单的未经身份验证的LDAP命令,仅对网络进行vCenter目录服务访问的攻击者可以向vCenter Directory添加管理员帐户。
通过此PoC可以实现整个vSphere部署的远程接管。
该漏洞是由vmdir的旧版LDAP处理代码中的两个严重问题引起的:
1. VmDirLegacyAccessCheck函数中的漏洞,导致在权限检查失败时返回“已授予访问权限”。
2. 一个安全设计缺陷,假设它是内部操作,该缺陷会授予不带令牌的LDAP会话root特权。
0x02 补丁分析
由于VMware将其新版本发布为磁盘映像而不是修补程序,因此必须在旧版本Update 3e和新版本之间进行区分。挂载磁盘映像显示,大多数情况下,这些发行版由一长串RPM组成。一旦提取了所有这些软件包的内容,就可以通过并列比较散列来查看实际更新了哪些文件。
不幸的是,事实证明,自上一个发行版以来,已更新了近1500个文件,远远超过可以手工检出的文件。猜测罪魁祸首可能在名称中的某处带有“ vmdir”。
缩减为以下列表:usr/lib/vmware-vmdir/lib64/libcsrp.a
usr/lib/vmware-vmdir/lib64/libcsrp.la
usr/lib/vmware-vmdir/lib64/libgssapi_ntlm.a
usr/lib/vmware-vmdir/lib64/libgssapi_ntlm.la
usr/lib/vmware-vmdir/lib64/libgssapi_srp.a
usr/lib/vmware-vmdir/lib64/libgssapi_srp.la
usr/lib/vmware-vmdir/lib64/libgssapi_unix.a
usr/lib/vmware-vmdir/lib64/libgssapi_unix.la
usr/lib/vmware-vmdir/lib64/libkrb5crypto.a
usr/lib/vmware-vmdir/lib64/libkrb5crypto.la
usr/lib/vmware-vmdir/lib64/libsaslvmdirdb.a
usr/lib/vmware-vmdir/lib64/libsaslvmdirdb.la
usr/lib/vmware-vmdir/lib64/libvmdirauth.a
usr/lib/vmware-vmdir/lib64/libvmdirauth.la
usr/lib/vmware-vmdir/lib64/libvmdirclient.a
usr/lib/vmware-vmdir/lib64/libvmdirclient.la
usr/lib/vmware-vmdir/lib64/libvmkdcserv.a
usr/lib/vmware-vmdir/lib64/libvmkdcserv.la
usr/lib/vmware-vmdir/sbin/vmdird
列出了内置于单个已编译二进制文件中的静态链接库:vmdird。换句话说,从3e更新开始,vmdir服务器就已经更新了。
在进行适当的文件 diff 之前,想知道是否对vmdird中的导出符号进行了明显的更新。
比较的结果令人震惊:jj@ubuntu:~/misc/vms$ diff
cut -f 2- -d " " | sort | uniq) g DF .text 00000000000000ce Base VmDirLegacyAccessCheck
1440d1440
g DF .text 000000000000038d Base VmDirSrvAccessCheck
2199d2199
漏洞函数根本不是VmDirLegacyAccessCheck函数,VMware在描述中写道:“当vmdir服务开始声明启用了旧版ACL模式时,受影响的部署将创建一个日志条目。”
在IDA中列出了这些功能的反汇编。这是未打补丁的版本,已经突出显示了可以更新函数返回值的所有内容。__int64 __fastcall VmDirLegacyAccessCheck(__int64 a1, __int64 a2, __int64 a3,
unsigned int a4)
{
unsigned int v5; // [rsp+14h] [rbp-2Ch]@1
__int64 v6; // [rsp+18h] [rbp-28h]@1
unsigned int v7; // [rsp+3Ch] [rbp-4h]@1
v6 = a3;
v5 = a4;
v7 = 0; // VMDIR_SUCCESS
if ( !(unsigned __int8)sub_4EF7B1(a1, a2, a4)
&& v5 == 2
&& ((unsigned __int8)sub_4EF510(v6) || (unsigned __int8)sub_4EF218(v6) || (unsigned __int8)VmDirIsSchemaEntry(v6)) )
{
v7 = 9114; // VMDIR_ERROR_UNWILLING_TO_PERFORM
VmDirLog1(4);
}
return v7;
}
这是已修补的:__int64 __fastcall VmDirLegacyAccessCheck(__int64 a1, __int64 a2, __int64 a3, unsigned int a4)
{
unsigned int v5; // [rsp+14h] [rbp-2Ch]@1
__int64 v6; // [rsp+18h] [rbp-28h]@1
unsigned int v7; // [rsp+3Ch] [rbp-4h]@1
v6 = a3;
v5 = a4;
v7 = 9207; // VMDIR_ERROR_INSUFFICIENT_ACCESS
if ( a4 == 2
&& ((unsigned __int8)sub_4EF5B1(a3) || (unsigned __int8)sub_4EF2B9(v6) || (unsigned __int8)VmDirIsSchemaEntry(v6)) )
{
v7 = 9114; // V