In this blog post, I’ll discuss my analysis of CVE-2023-36563, a Microsoft WordPad Information Disclosure Vulnerability, from initial patch diff to working exploit. Then, I’ll discuss detection and mitigation strategies for preventing exploitation of this vulnerability.

CVE-2023-36563 Overview

Summary

CVE-2023-36563’s flaw lies within legacy functionality to convert an OLE 1 storage object (OLESTREAM) to the new IStorage format. By crafting a file with a malicious OLE 1 LinkedObject, an attacker could coerce authentication to an untrusted server to steal NTLM hashes.

Inspiration

There were a few things that made this vulnerability stick out to me and inspired me to figure out how it worked:

  1. The vulnerability was added to CISA’s Known Exploited Vulnerabilities Catalog, meaning someone was able to exploit this vulnerability in the wild.
  2. The “information disclosure” referred to a victim’s NTLM hashes, which can be very practically abused using NTLM relay attacks.
  3. The vulnerability is triggered by opening a malicious file with WordPad, which is very applicable for phishing and red team operations.
  4. It’s WordPad, and it’s hilarious that this vulnerability was announced right as WordPad is being deprecated

Technical Analysis

When trying to understand how recently released (or N-day) vulnerabilities work, performing a binary patch diff is an enormous help. In essence, we compare the binary instructions of a program using software like Bindiff before and after an update is applied. This gives us vital hints regarding fixes that occurred during a patch.

During my analysis, I reminded myself that this vulnerability resulted in NTLM hash disclosures. This heavily suggested that the vulnerability had something to do with making a web request or accessing a resource, since such operations can trigger an NTLM challenge-response.

Additionally, the CVE mentioned that the vulnerability was triggered by opening a malicious file in WordPad, so I would likely need to get familiar with the RTF file type.

WordPad.exe

Before Patch MD5: bd05d1b9fba2f5f1db6fbb59d3a78d84

After Patch MD5: e46d2a1e4836b78d00eeccc0e1db0f52

Modified Functions

I figured the wordpad.exe binary was a great place to start patch diffing. Bindiff identified several interesting functions that were modified by the patch. The one that interested me most was the LoadImageResource function, which sounded like it might handle retrieving an image within a document.

WordPad.exe modified functions

WordPad.exe Modified Functions

This ended up being a red herring. I set a breakpoint on the function in windbg and triggered it when hovering over an icon within WordPad that loaded several preview images of bullet points. Thus, it seemed to me like the function handled loading a resource from within the WordPad executable itself–not something we’d be able to easily exploit.

shell\shell32\netfldrp_ui.h(83)\SHELL32.dll!00007FFE78FA87DF: (caller: 00007FFE7614F490) ReturnHr(5) tid(1184) 80004001 Not implemented
(1498.11d4): Unknown exception - code 000006ba (first chance)
(1498.11d4): Unknown exception - code 000006ba (first chance)
ModLoad: 00007ffe`6c550000 00007ffe`6c567000   C:\Windows\system32\OnDemandConnRouteHelper.dll
ModLoad: 00007ffe`404f0000 00007ffe`4053b000   C:\Windows\system32\ndfapi.dll
ModLoad: 00007ffe`6f970000 00007ffe`6f98f000   C:\Windows\system32\wdi.dll
Breakpoint 1 hit
wordpad!LoadImageResource:
Load Image Resource Triggered

LoadImageResource function triggered from application resources

New Functions

I also noticed that a new function was added called QueryConvertOLELinkCallback, a wrapper that would call a provided callback function. This wrapper was called within one of WordPad’s main editing functions, as shown below. I wasn’t sure what this was used for quite yet, but I took note of it.

QueryConvertOLELinkCallback

New QueryConvertOLELinkCallback function

An OLE Primer

The QueryConvertOLELinkCallback got me thinking that the vulnerability might have something to do with Microsoft’s Object Linking and Embedding (OLE) format. In essence, OLE allows for objects and files to be embedded within other files on Windows.

As a brief example of how OLE objects work, let’s examine a paint object embedded within an RTF file. To do this, we can pop open WordPad, select Insert Object and Paintbrush Picture. Then, we’ll be able to create a paint image in MsPaint and have it show up in the RTF file.

Embedded Paint Brush Picture

Embedding a paintbrush picture within an RTF document

If we opened the RTF file in Notepad, we would notice an \objdata tag containing hexadecimal data for the embedded object. More on this in just a bit.

Embedded Object Hexadecimal Data

The embedded object’s hexadecimal data

OLE functionality has been extensively abused by attackers, especially within Rich Text Format (RTF) files, which happens to be the default file type for WordPad. OLE was even the culprit of the infamous Follina RCE vulnerability (CVE-2022-30190).

Much of OLE’s functionality is implemented by the ole32.dll Windows library, so that seemed like a logical next place to explore. This is where things started to get interesting.

Ole32.dll

Before Patch MD5: 5151f3912370086a405a9a7070768f4b

After Patch MD5: 72907f2a113ebf319838f6276fbd0460

Modified Functions

The following functions were modified from the patch. The naming convention implies they perform some sort of OLE object conversion.

  • wConvertOLESTREAMToIStorage
  • OLESTREAMToGenericObject
  • OleConvertOLESTREAMToIStorage
  • OleConvertOLESTREAMToIStorageEx

New Functions

The patch added these new functions:

  • CheckOLELinkConversionRegistrySetting
  • FindStringInMultiString
  • IsAppExcludedFromOLELinkConversionRegistrySetting
  • OleConvertOLESTREAMToIStorage2
  • OleConvertOLESTREAMToIStorageEx2

The IsAppExcludedFromOLELinkConversionRegistrySetting function instantly stuck out to me as an added check to determine whether some sort of OLE link should be processed.

Additionally, the addition of OleConvertOLESTREAMToIStorage2 and OleConvertOLESTREAMToIStorageEx2 was intriguing. Although it took a couple days after the patch, Microsoft added them to their official documentation. The function prototype looks like this:

HRESULT OleConvertOLESTREAMToIStorage2(
  [in]  LPOLESTREAM          lpolestream,
  [out] LPSTORAGE            pstg,
  [in]  const DVTARGETDEVICE *ptd,
  [in]  DWORD                opt,
  [in]  PVOID                pvCallbackContext,
  [in]  OLESTREAMQUERYCONVERTOLELINKCALLBACK pQueryConvertOLELinkCallback
);

The last 3 arguments are new from the patch, and Microsoft’s description of them is shown below. An opt flag could now be provided to “disable a linked object during conversion.” Additionally, a pQueryConvertOLELinkCallback function pointer could be specified to determine whether a linked object should be converted or not. And remember, we noticed the QueryConvertOLELinkCallback function specified in the patched version of WordPad. Coincidence? I think not!

OleConvertOLESTREAMToIStorage2 New Arguments

New arguments for the OleConvertOLESTREAMToIStorage2 function

Creating an Exploit

Things were now starting to make sense. Clearly, there was an unsafe conversion happening to an OLE LinkedObject that coerced NTLM authentication to occur. It was time to craft a payload to trigger this.

Crafting the Payload

Remember that embedded paint object we created earlier? Let’s take a look at the hex bytes within the \objdata tag. I created an 010 template based on Microsoft’s documentation of the OLE 1 format, so we could see what’s going on.

Viewing Embedded Object Bytes

Viewing the bytes of the embedded paintbrush object

We have the OLE magic followed by a FormatID field, which can have either the value 0x2 (as shown here) for an EmbeddedObject, or 0x1 for a LinkedObject. A LinkedObject! We know from our previous analysis that this is the type of object that triggers this vulnerability.

Microsoft Object Header Details

Microsoft documentation specifying the object header format

Looking further at the documentation for a LinkedObject, I found that if the OLE object was of type LinkedObject, the TopicName field should point to a UNC path for the linked file:

LinkedObject TopicName Documentation

Microsoft documentation detailing the TopicName field

Now that sounded juicy. I went ahead and set the TopicName to be a file on a remote SMB share that I controlled. I also had to modify the payload a bit to remove the NativeDataSize and NativeData fields, since the LinkedObject structure did not contain them.

Crafted Malicious File

Crafted file with a remote UNC path inside of a LinkedObject

It was almost time to reap the benefits of my work.

The Mark of the Web

It is important to briefly discuss a concept on Windows known as the Mark of the Web (MOTW). Whenever a file is downloaded from a remote resource, Windows sets a specific flag on that file. The purpose is to indicate to applications that it should be treated with caution, since it is from an untrusted source. You can view this special flag by selecting a file’s Properties in Windows Explorer. Below shows the properties of my exploit file after I downloaded it from my remote server:

The Mark of the Web

MOTW flag set on downloaded exploit file

Applications such as Word, Excel, and yes, WordPad, are designed to open files with the MOTW flag set in safe mode, prompting a user before loading any external resources. This is because, on Windows, fetching remote resources can lead to authentication challenges which can disclose NTLM credentials. If this bit is not set, security is much more lax.

The point is, a document that does not have the MOTW bit set and causes a remote resource to be fetched is likely not exploiting a vulnerability. Therefore, it was important to test the RTF file I crafted with the MOTW set.

Exploitation

I downloaded my crafted RTF file from my web server and ensured the MOTW flag was set. Then, I spun up Responder on my remote server to listen for SMB resource requests. Next, I opened the crafted file in WordPad:

Opening Exploit in WordPad With Security Warning

Opening the crafted RTF file in WordPad, receiving a security warning

Note that WordPad showed an alert which might lead one to believe that external resource fetches were blocked. However, this was not the case, as WordPad happily attempted to authenticate to my rogue server:

Exploit Success NTLM Hashes

Successful exploitation resulting in NTLM hashes

As shown in the windbg stack trace below, the file access resulted from the vulnerable OleConvertOLESTREAMToIStorage function.

WinDbg Stack Trace

Stack trace showing vulnerable function leading to file operations

Success :)

Mitigation

Microsoft released a support article a few days after Patch Tuesday which provided mitigations for CVE-2023-36563.

Users can add the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Ole\AppCompat\ OLELinkConversionFromOLESTREAMToIStorage and set the DWORD value Disabled to 0x00000001, according to the document. Additionally, users can add applications they wish to allowlist for OLE link conversion to the ExclusionList key value.

Additionally, users should be sure to apply the patch provided by Microsoft. I confirmed that my exploit did not function after patching my system.

Detection

Exploitation of this vulnerability requires opening an RTF file with a legacy OLE 1 LinkedObject structure. You probably shouldn’t receive such a file for a legitimate reason unless you are communicating with a time traveler from the 1990’s. Additionally, a malicious LinkedObject would need to contain a remote UNC path to exploit this vulnerability.

With this in mind, I created the following YARA rule. I am currently retro hunting with it on Virus Total as well as looking for threat actors currently using this vulnerability.

rule RTF_LinkedObject_UNC_Path {
    meta:
        description = "CVE-2023-36563: Detects and RTF with a LinkedObject containing a remote UNC path in TopicName"
        author = "Dillon Franke"
        reference = "CVE-2023-36563"

    strings:
        // Match the \objdata tag
        $rtf_objdata = "\\objdata"

        $rtf_header = { 7B 5C 72 74 } // "{\rt"

        // // Match OLE version and FormatID for LinkedObject
        $ole_header = "0105000001000000"

        // // Match UNC path prefix
        $unc_path_upper = { 35 43 35 43 } // "\\..." UNC path 5C5C
        $unc_path_lower = { 35 63 35 63 } // "\\..." UNC path 5c5c

    condition:
        // File format should be RTF
        $rtf_header at 0 and

        // // Check for \objdata tag
        $rtf_objdata and

        // // // Check for header and UNC path after the \objdata tag
        $ole_header in (@rtf_objdata..@rtf_objdata+0x50) and 
        $unc_path_lower in (@rtf_objdata..@rtf_objdata+0x400) or
        $unc_path_upper in (@rtf_objdata..@rtf_objdata+0x400)
}

Thank You

Thanks for reading. I welcome any feedback and am always willing to discuss/collaborate on vulnerability research. Please reach out me @dillon_franke on Twitter, or via my contact page.