Vmware vcenter未授权任意文件/RCE漏洞的复现与分析

  • A+
所属分类:安全文章

0x01 背景

vSphereVMware推出的虚拟化平台套件,包含ESXivCenter Server等一系列的软件。其中vCenter Server ESXi的控制中心,可从单一控制点统一管理数据中心的所有vSphere主机和虚拟机,使得IT管理员能够提高控制能力,简化入场任务,并降低IT环境的管理复杂性与成本。

vSphere Client(HTML5)vCenter Server插件中存在一个远程执行代码漏洞。未授权的攻击者可以通过开放443端口的服务器向vCenter Server发送精心构造的请求,从而在服务器上写入webshell,最终造成远程任意代码执行。

受影响的版本:

7.0 U1c 之前的 7.0 版本6.7 U3l 之前的 6.7 版本6.5 U3n 之前的 6.5 版本

0x02 代码分析

vCenter ServervROPS插件的API未经过鉴权,存在一些敏感接口。其中 uploadova 接口存在一个上传 OVA 文件的功能:

   @RequestMapping(      value = {"/uploadova"},      method = {RequestMethod.POST}   )   public void uploadOvaFile(@RequestParam(value = "uploadFile",required = true) CommonsMultipartFile uploadFile, HttpServletResponse response) throws Exception {      logger.info("Entering uploadOvaFile api");      int code = uploadFile.isEmpty() ? 400 : 200;      PrintWriter wr = null;      try {         if (code != 200) {            response.sendError(code, "Arguments Missing");            return;         }         wr = response.getWriter();      } catch (IOException var14) {         var14.printStackTrace();         logger.info("upload Ova Controller Ended With Error");      }      response.setStatus(code);      String returnStatus = "SUCCESS";      if (!uploadFile.isEmpty()) {         try {            logger.info("Downloading OVA file has been started");            logger.info("Size of the file received  : " + uploadFile.getSize());            InputStream inputStream = uploadFile.getInputStream();            File dir = new File("/tmp/unicorn_ova_dir");            if (!dir.exists()) {               dir.mkdirs();            } else {               String[] entries = dir.list();               String[] var9 = entries;               int var10 = entries.length;               for(int var11 = 0; var11 < var10; ++var11) {                  String entry = var9[var11];                  File currentFile = new File(dir.getPath(), entry);                  currentFile.delete();               }               logger.info("Successfully cleaned : /tmp/unicorn_ova_dir");            }            TarArchiveInputStream in = new TarArchiveInputStream(inputStream);            TarArchiveEntry entry = in.getNextTarEntry();            ArrayList result = new ArrayList();            while(entry != null) {               if (entry.isDirectory()) {                  entry = in.getNextTarEntry();               } else {                  File curfile = new File("/tmp/unicorn_ova_dir", entry.getName());                  File parent = curfile.getParentFile();                  if (!parent.exists()) {                     parent.mkdirs();                  }                  OutputStream out = new FileOutputStream(curfile);                  IOUtils.copy(in, out);                  out.close();                  result.add(entry.getName());                  entry = in.getNextTarEntry();               }            }            in.close();            logger.info("Successfully deployed File at Location :/tmp/unicorn_ova_dir");         } catch (Exception var15) {            logger.error("Unable to upload OVA file :" + var15);            returnStatus = "FAILED";         }      }      wr.write(returnStatus);      wr.flush();      wr.close();   }

代码逻辑是将TAR文件解压后上传到 /tmp/unicorn_ova_dir 目录。注意到如下代码:

                while(entry != null) {                    if (entry.isDirectory()) {                        entry = in.getNextTarEntry();                    } else {                        File curfile = new File("/tmp/unicorn_ova_dir", entry.getName());                        File parent = curfile.getParentFile();                        if (!parent.exists()) {                            parent.mkdirs();

直接将TAR的文件名与 /tmp/unicorn_ova_dir 拼接并写入文件。如果文件名内存在 ../ 即可实现目录遍历。

0x03 影响版本

vcenter_server 7.0 U1c 之前的 7.0 版本vcenter_server 6.7 U3l 之前的 6.7 版本vcenter_server 6.5 U3n 之前的 6.5 版本

0x04 复现

VMware-VCSA-all-6.7.0-8217866为例,web的资源目录为/usr/lib/vmware-vsphere-ui/server/work/deployer/s/global/{REPLACE_RANDOM_ID_HERE}/0/h5ngc.war/resources/

https://VCIP/ui/vropspluginui/rest/services/uploadova发送POST请求,tar包内容为带有目录穿越的shell

Vmware vcenter未授权任意文件/RCE漏洞的复现与分析

上传成功会返回SUCCESS

访问上传的shell

Vmware vcenter未授权任意文件/RCE漏洞的复现与分析

0x05 VMware的骚操作

vSphere vCenter6.7 U2的某个分支里,VM官方搞了个骚操作导致6.7U2+无法通过上传webshell的形式去获取vCenter权限,以下为启动前端UI的命令

/usr/java/jre-vmware/bin/vsphere-ui.launcher-Xmx597m-XX:CompressedClassSpaceSize=256m-Xss320k-XX:ParallelGCThreads=1-Djava.io.tmpdir=/usr/lib/vmware-vsphere-ui/server/work/tmp-Dorg.eclipse.virgo.kernel.home=/usr/lib/vmware-vsphere-ui/server-DPS_BASEDIR=/storage/vsphere-ui/-Declipse.ignoreApp=true-Dcatalina.base=/usr/lib/vmware-vsphere-ui/server-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/var/log/vmware/vsphere-ui/-XX:ErrorFile=/var/log/vmware/vsphere-ui/java_error%p.log-XX:+PrintGCDetails-XX:+PrintGCDateStamps-XX:+PrintReferenceGC-XX:+UseGCLogFileRotation-XX:NumberOfGCLogFiles=10-XX:GCLogFileSize=1024K-XX:-OmitStackTraceInFastThrow-Xloggc:/var/log/vmware/vsphere-ui/vsphere-ui-gc.log-Djava.security.properties=/etc/vmware/java/vmware-override-java.security-Djava.ext.dirs=/usr/java/jre-vmware/lib/ext:/usr/java/packages/lib/ext:/opt/vmware/jre_ext/-Dorg.osgi.framework.system.packages.extra=sun.misc-Dsun.zip.disableMemoryMapping=true-Dui.component.name=vsphere-ui-Dvlsi.client.vecs.certstore=false-DisFling=false-Dorg.apache.tomcat.websocket.DISABLE_BUILTIN_EXTENSIONS=true-Dlogback.configurationFile=/usr/lib/vmware-vsphere-ui/server/conf/serviceability.xml-Dlogs.dir=/var/log/vmware/vsphere-ui/logs/-Dhttps.port=5443-Dhttp.port=5090-Dshutdown.port=-1-Dcom.sun.org.apache.xml.internal.security.ignoreLineBreaks=true-Dorg.apache.xml.security.ignoreLineBreaks=true-classpath/usr/lib/vmware-vsphere-ui/server/bootstrap/server-launcher.jar:/usr/lib/vmware-vsphere-ui/server/bin/bootstrap.jar:/usr/lib/vmware-vsphere-ui/server/bin/tomcat-juli.jarcom.vmware.vise.launcher.tomcat.TomcatLauncherstart

注意server-launcher.jar这个包调用了com.vmware.vise.launcher.tomcat.TomcatLauncher类,反编译后部分代码如下

public final class TomcatLauncher{    private static final String VECS_KEYSTORE_TYPE = "VKS";    private static final String MACHINE_SSL_CERT = "MACHINE_SSL_CERT";    private static final String VECS_LOAD_STORE_PARAM_TYPE = "com.vmware.provider.VecsLoadStoreParameter";    private static final String FILE_SEPARATOR;    private static final String SYSPROP_COMPONENT_NAME = "ui.component.name";    private static final String DEFAULT_COMPONENT_NAME = "vsphere-ui";    private static final String CLIENT_APP_DATA_FOLDER;    private static final String DEST_KEYSTORE_NAME = "keystore.jks";    private static final String PASSWORD;    private static final String TOMCAT_DIR = "catalina.base";    private static final String CONFIG_DIR;        public static void main(final String[] args) {        loadKeystore();        deleteWorkDirectory();        createJavaTempDir();        Bootstrap.main(args);    }

其中有个函数deleteWorkDirectory

    private static void deleteWorkDirectory() {        final File workDir = new File(System.getProperty("catalina.base") + "/work");        if (!workDir.exists()) {            return;        }        try {            deleteDirectoryRecur(workDir);        }        catch (IOException e) {            throw new RuntimeException("Cannot clean work dir", e);        }    }

这个函数主要作用就是删除web目录,先从命令行中的catalina.base获取设置的Tomcat工作目录/usr/lib/vmware-vsphere-ui/server,然后拼接/work路径并判断是否存在,不存在则返回,存在的调用deleteDirectoryRecur函数进行删除

    private static void deleteDirectoryRecur(final File directory) throws IOException {        final File[] contents = directory.listFiles();        if (contents != null) {            for (final File f : contents) {                if (isSymlink(f)) {                    f.delete();                }                else {                    deleteDirectoryRecur(f);                }            }        }        directory.delete();    }        private static boolean isSymlink(final File file) throws IOException {        if (file == null) {            throw new NullPointerException("File must not be null");        }        File canon;        if (file.getParent() == null) {            canon = file;        }        else {            final File canonDir = file.getParentFile().getCanonicalFile();            canon = new File(canonDir, file.getName());        }        return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());    }

这也是为什么6.7U2+、7.0+的版本无法进行常规写shell的操作原因。

但是问题来了,实际发现tomcat并没有启动

Vmware vcenter未授权任意文件/RCE漏洞的复现与分析

0x06 柳暗花明

经过分析启动进程rhttpproxy,发现该进程将443请求转发到5090端口

Vmware vcenter未授权任意文件/RCE漏洞的复现与分析

这和启动进程的参数吻合

经过后续的分析,发现了一种有条件写shell的操作,vCenter在重启时会启动服务,但是在启动服务的过程中会调用war包重新生成web目录,这就可以给我们一个可乘之机

查看war包权限

Vmware vcenter未授权任意文件/RCE漏洞的复现与分析

770权限,那么我们可以先把该文件下载回本地进行加料,再利用CVE-2021-21792漏洞回传回vCener服务器进行复写操作,等待vCenter重启时就会在内存中驻留我们的webshell

成功如图

Vmware vcenter未授权任意文件/RCE漏洞的复现与分析

0x07 EXP下载地址

https://github.com/NS-Sp4ce/CVE-2021-21972

Vmware vcenter未授权任意文件/RCE漏洞的复现与分析



Vmware vcenter未授权任意文件/RCE漏洞的复现与分析


点赞,转发,在看


原创投稿作者:sp4ce

Vmware vcenter未授权任意文件/RCE漏洞的复现与分析

本文始发于微信公众号(HACK学习呀):Vmware vcenter未授权任意文件/RCE漏洞的复现与分析

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: