返回
顶部

参考链接

漏洞描述

CVE-2021-21972:未经认证的文件上传导致的RCE

影响范围

VMware vCenter Server 7.0系列 < 7.0.U1c

VMware vCenter Server 6.7系列 < 6.7.U3l

VMware vCenter Server 6.5系列 < 6.5 U3n

分析

其实成因很简单,就是其中一个接口没有进行认证即可被访问到,而该接口中的其中一个方法又存在目录穿越漏洞,最终导致了任意文件上传到服务器任意路径的漏洞

存在漏洞的jar包为vropsplugin-service.jar,物理路径:

C:\ProgramData\VMware\vCenterServer\cfg\vsphere-client\vc-packages\vsphere-client-serenity\com.vmware.vrops.install-6.7.0.10000\plugins\vropsplugin-service.jar

直接解压缩并反编译其中的下面这个class文件:

vropsplugin-service\com\vmware\vropspluginui\mvc\ServicesController.class

漏洞代码片段:

@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 e) {
      e.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();
          for (String str : entries) {
            File currentFile = new File(dir.getPath(), str);
            currentFile.delete();
          } 
          logger.info("Successfully cleaned : /tmp/unicorn_ova_dir");
        } 
        TarArchiveInputStream in = new TarArchiveInputStream(inputStream);
        TarArchiveEntry entry = in.getNextTarEntry();
        List<String> result = new ArrayList<String>();
        while (entry != null) {
          if (entry.isDirectory()) {
            entry = in.getNextTarEntry();
            continue;
          } 
          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((InputStream)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 e) {
        logger.error("Unable to upload OVA file :" + e);
        returnStatus = "FAILED";
      }  
    wr.write(returnStatus);
    wr.flush();
    wr.close();
  }

在遍历tar文件并逐个释放到/tmp/unicorn_ova_dir目录的过程中,有这么一行代码:

File curfile = new File("/tmp/unicorn_ova_dir", entry.getName());

这个操作没有任何对entry.getName()的检查与过滤,直接将/tmp/unicorn_ova_direntry.getName()拼接了起来,如果我们构造出包含..\的tar文件,那么就能达到目录穿越的目的

使用evilarc.py制作目录层级为2的tar文件,就会在目录结构中包含两个目录穿越符号,正好够我们达到服务器文件系统的根路径

1615115959034

结语

漏洞很简单,难的是找到无需认证即可访问的接口以及存在漏洞的方法!!!