EnglishmansDentist Exploit Analysis


Introduction

We are continuing our series of blog posts dissecting the exploits released by ShadowBrokers in April 2017. After the first two posts about the SMB exploits known as EternalChampion and EternalSynergy, we’ll move this time to analyze a different tool and we’ll focus on the exploit named EnglishmansDentist designed to target Exchange Server 2003.

EnglishmansDentist targets Exchange 2003 mail server through a rendering vulnerability present in a shared library provided by the underlying (out-of-support) operating system Windows Server 2003, which is used by Exchange 2003 in its default configuration.

Newer operating systems (Windows Server 2008 and above) and more recent versions of Exchange Server (2007 and above) are not impacted by this exploit and so no action is needed for customers using these newer platforms.

As previously announced on MSRC blog, after considering the availability of ready-to-use weaponized code and the assessment of the threat landscape, Microsoft decided to release in June an extraordinary update for out-of-support platforms (Windows XP and Server 2003) to protect customers who were not able to update to newer products.

This blog post will deep-dive into the root cause of the vulnerability, the impact on Microsoft products, the exploitation methods and how modern mitigations can break such exploits in newer operating systems and products.

Overview

The root cause of this vulnerability is a memory corruption bug in the code of a shared library (OLECNV32.DLL), used to render images encoded with the old file format known as QuickDraw PICT. This graphic library is present by default on Windows XP and Windows Server 2003. Exchange Server 2003 uses this graphic library to render PICT content delivered in form of email attachments. So, while the underlying bug exists in the operating system, the attack vector used to reach the vulnerable code is an Exchange rendering routine called through OLE invocation and triggered with a specially crafted email attachment.

When Microsoft security engineers analyze a vulnerability in a shared component such as a graphic library, multiple investigation workstreams are initiated to answers two very important questions:

  • what products still in support may use or distribute the vulnerable shared library?
  • is the source code of the vulnerable library copied or re-used in other components?

For the first question, we determined that the vulnerable version of OLECNV32.DLL library is shipped and present on disk only on out-of-support platforms like Windows Server 2003 and Windows XP, with the first one being of interest as default platform for an Exchange Server 2003 installation. After research on affected platforms and possible installation combinations of Exchange Server, we came up with the following matrix that can help to understand which combination of products are mostly exposed at risk of exploitation by EnglishmansDentist.

Exchange Server 2007 product is not affected by this attack because the graphic rendering engine no longer uses OLECNV32.DLL library to render PICT images, even if the library may be present on disk (uncommon case with Windows Server 2003 + Exchange 2007). Newer versions of Exchange Server such as 2010 and 2013 are not impacted by this bug and so they won’t be considered.

Regarding the source code investigation, we tracked how the PICT vulnerable function was integrated and re-used in certain older versions of Office no longer in support. During this investigation, we were happy to see that while this bug was initially copied by developers into a graphic filter for Office, the same bug was later identified by Microsoft security reviews and fuzzing and it was internally fixed back in 2006 as part of the increased effort in finding vulnerability initiated by Microsoft during that time. This example represents a good story of bug collisions, where a weaponized exploit used silently by an attacker may be killed by internal pentesting and fuzzing efforts of the vendor.

It is probable that EnglishmansDentist was initially written before 2005 because the exploit seems to not work properly (ends with a crash) when tested against an Exchange Server 2003 SP2 and it has only 32-bit operating system targets, probably because 64-bit architecture was not popular enough a decade ago.

Exploit requirements and delivery mechanism

EnglishmansDentist requires the attacker to have at least one valid mail account on the target Exchange 2003 mail server (username and password). In fact, the exploit will run first a series of validation and checks to make sure that the valid account can login and check mails successfully. The exploit requires also a secondary email account (spoofed or real) used as source which will send the malformed PICT attachment to the valid account.

After the delivery of the malicious PICT attachment to the target mail server, the tool will login with the valid account credentials and force Exchange Server to parse and render the malicious attachment using one of the many protocols available (OWA, IMAP, POP3). Because the rendering code is executed on the

server-side, successful exploitation will result in execution of arbitrary code in the context of an Exchange Server process running with SYSTEM privileges.

After exploitation, EnglishmansDentist remains in listening mode waiting for the shellcode to connect back. When this happens, the tool instructs the Exchange server to delete the malicious email which delivered the exploit, removing forensic evidences of the attack.

The vulnerability: CVE-2017-8487

In order to understand the vulnerability, readers must be familiar with PICT graphic specifications and with the opcodes defined by this file format. Some references to parse this old file format are still available online here, here and here. Another good reference with details of the internal PICT opcode parsing code is also available here.

When testing the exploit against Exchange Server 2003 SP2, we observed the following crash in our test environment; we included in this blog only information and modules relevant for the analysis of this vulnerability, marking in red attacker’s controlled frames and in yellow interesting function names

Application exception occurred:
App: C:\Program Files\Exchsrvr\bin\store.exe (pid=2288)
When: 4/15/2017 @ 00:27:11.078
Exception number: c0000005 (access violation)

*----> System Information <----*
Computer Name: XXX
User Name: SYSTEM
Terminal Session Id: 0
Number of Processors: 1
Processor Type: x86 Family 6 Model 62 Stepping 4
Windows Version: 5.2
Current Build: 3790
Service Pack: 2

*----> Module List <----*
0000000000400000 - 000000000091c000: C:\Program Files\Exchsrvr\bin\store.exe
[...]
000000006d580000 - 000000006d628000: C:\WINDOWS\system32\dbghelp.dll
0000000071db0000 - 0000000071dbc000: C:\WINDOWS\system32\OLECNV32.DLL

eax=4a85c948 ebx=00094850 ecx=00000000 edx=00000020 esi=000949c0 edi=4a85ca0c
eip=6d8b1cfd esp=4a85c738 ebp=4a85ca50 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
6d8b1cfd ?? ???

-> ROP gadget targeting DBGHELP.DLL + 0x00081cfd

0:057> kp
# ChildEBP RetAddr
WARNING: Frame IP not in any known module. Following frames may be wrong.
00 4a85c734 77c0f329 0x6d8b1cfd
01 4a85ca50 77c0f282 gdi32!iAnsiCallback+0x9d
02 4a85ca84 77c0f480 gdi32!EnumFontsInternalW+0x111
03 4a85cab4 77c265dc gdi32!EnumFontsInternalA+0x68
04 4a85cad4 71db2a0b gdi32!EnumFontsA+0x1a
05 4a85caf8 71db31c7 olecnv32!EnumFontFunc+0x3d1
06 4a85cb08 71db38d9 olecnv32!GdiOpenMetafile+0x335
07 4a85cb14 71db6290 olecnv32!GdiTextOut+0x22
08 4a85cc98 71db71c4 olecnv32!QDCopyBytes+0xd40
09 4a85ccb0 71db1375 olecnv32!QDConvertPicture+0xb4
0a 4a85ccc0 77760418 olecnv32!QD2GDI+0x3d
0b 4a85cd28 776fd79a ole32!QD2GDI+0xac
0c 4a85cd58 776cccf3 ole32!UtGetHMFFromMFStm+0x71
0d 4a85cd80 776ccb21 ole32!CMfObject::Load+0x4d
0e 4a85cdb4 776cc96a ole32!CCacheNode::Load+0xc5
0f 4a85ce60 007628f9 ole32!COleCache::Load+0x1b2
10 4a85ce80 00762e9b store!IMAGESTM::HrGetViewObject+0x87
11 4a85ce8c 0076304a store!IMAGESTM::HrAttachToImage+0x16
12 4a85ce98 0076320c store!IMAGESTM::HrEnsureImage+0x10
13 4a85cea8 6225dce2 store!IMAGESTM::Stat+0xf
14 4a85ced4 62258840 exmime!CStreamLockBytes::Stat+0x4a
15 4a85d0ac 6225d911 exmime!CBodyStream::HrInitialize+0x107
16 4a85d0f0 6225e4ca exmime!CMessageBody::GetDataHere+0xd4
[...]
 

As immediately visible from this callstack trace, the vulnerability exists inside the routine QD2GDI() exported by OLECNV32.DLL. This function is responsible for converting and rendering QuickDraw images and it’s used by Exchange Server 2003 “store.exe” process. The routine is called when an attachment for example is automatically parsed through OWA while reading new incoming emails; the attack surface of this parser is reachable through OLE32.

The internal code of QD2GDI() has a memory corruption bug while parsing a LongComment record, normally identified by opcode 0xA1. An attacker can exploit this bug by creating a malformed PICT file with a LongComment record containing a PP_FONTNAME sub-record with a fontName string greater than 32 bytes which triggers a memory corruption with an out-of-bound overwrite of a fixed size variable.

A malformed PICT image produced by EnglishmansDentist will have a similar layout as follow.

The image will always start with two hardcoded headers. One is used to integrate the PICT image into the TNEF OLE container (mail attachment format used by Exchange), and the second one represents a proper PICT header. The two static headers are immediately followed by a dummy tag TxFont record and by the vulnerable LongComment record which will trigger the memory corruption overwrite.

The preparation of the malicious PICT file is done programmatically in EnglishmansDentist in two routines at offset 0x404621 and 0x404650. It’s done by assembling the static headers followed by multiple PICT records, including the malformed 0xA1 opcode and other records used to deliver a ROP chain and the encrypted shellcode payload.

The decoding of the header and the records performed by QD2GDI() will immediately hit the malformed 0xA1 opcode and trigger the vulnerability.

//inner parsing done by OLECNV32!QD2GDI()
private void TranslateOpcode( opcodeEntry far * currOpcodeLPtr )
{
    Word  function = currOpcodeLPtr->function;   
    /* perform appropriate action based on function code */
    switch (function)                                                                                                     
        {
            [...]
            case LongComment:         // opcode 0xA1       
            {   
                [...]           
                /* determine what should be done with the comment */       
                switch (comment)          
                {  
                    [...]               
                    case picAppComment:         //comment 0064              
                    { 
                        [...]                  
                        
                        /* determine what to do with the function specified */
                        switch (realFunc)                
                        {                   
                            case PP_FONTNAME:             //function 0011                  
                            {                      
                                Byte     fontFamily;                      
                                Byte     charSet;                      
                                Byte     fontName[32];     //fixed-szie string buffer (32 bytes)                        
                                
                                /* font name from GDI2QD - read the LOGFONT info */                      
                                GetByte( &fontFamily );                      
                                GetByte( &charSet );  
                                
                                //”fontName” parameter is attacker’s controlled (malformed size) 
                                //GetString()does not validate max size (32) and will blindly use it to copy 
                                //resulting in an out-of-bound overwrite                       
                                
                                GetString( fontName );                           
                                
                                length = 0;                        
                                
                                // call Gdi module to override font selection                     
                                GdiFontName( fontFamily, charSet, fontName );

As mentioned earlier, this bug was found internally by Microsoft when this code was ported and integrated in some older versions of Office. Therefore the function GetString() was modified many years ago to require the caller to pass the length of the buffer and enforce checks to avoid overwriting data out-of-bound, neutralizing this vulnerability in every possible place. 

Exploitation: easy job without mitigations

Unfortunately, it’s trivial to exploit a good out-of-bound overwrite bug inside an environment like Windows Server 2003 which lacks fundamental mitigations like ASLR and CFG. On Windows Server 2003, DEP is easily bypassed by the attacker because of lack of ASLR. Without the randomization of ASLR in memory, the attacker can use a pre-calculated ROP chain to call VirtualAlloc and next transfer the shellcode into the newly allocated executable buffer to run without problems.

The exploit first triggers the memory corruption vulnerability using a malformed 0xA1 record and it uses the out-of-bound overwrite to corrupt internal OLECNV32 structures hosting other objects. Specifically, the exploit targets a font entry in the global fontTable[] array which later is copied to gdiEnv structure and can be used to overwrite a function pointer and take control of execution.

The following memory dump captured during exploitation shows an example of the fontTable[] array where some entries were corrupted by the memory overwrite caused by the vulnerable GetString() function. It is possible to spot in the fontTable[] the malformed data coming from the PICT file and the offset used as initial ROP gadget (0x6D8B1CFD) marked in red.

After the corruption of fontTable[], the exploit leverages parsing of other PICT opcodes to trigger further interactions with the recently malformed font entry. This will lead OLECNV32 to do one more string copy operation to copy the malformed font into OLECNV32!gdiEnv data structure as shown in the following code snippet (fontTable[newFont] was malformed and is now controlled by the attacker controlled).

   if (GdiAttribHasChanged( GdiTxFont ))
    {       
        Integer  newFont;         
        
        /* call the routine to find a matching GDI font face name */       
        newFont = FindGdiFont();         
        
        /* fill in information from the font lookup table */       
        gdiEnv.newLogFont.lfPitchAndFamily = fontTable[newFont].family | (Byte)DEFAULT_PITCH;         
        
        /* copy the correct font character set */       
        gdiEnv.newLogFont.lfCharSet = fontTable[newFont].charset; 
        
        /* copy over the new font face name */       
        lstrcpy( gdiEnv.newLogFont.lfFaceName, fontTable[newFont].gdiName );   
        
    [...] 

This final string copy operation will result in overwriting a function pointer that can be leveraged by the attacker as callback to take control later when the EnumFonts function is called to enumerate fonts.

0:000> dt olecnv32!gdiEnv     
    +0x000 metafile         : 0xffffffff`b8662029 Void    
    +0x004 newLogBrush      : tagLOGBRUSH    
    +0x010 newLogFont       : tagLOGFONTA    
    +0x04c newLogPen        : tagLOGPEN    
    +0x05c clipRect         : tagRECT    
    +0x06c drawingEnabled   : 0n1    
    +0x070 sameObject       : 0n0    
    +0x074 useGdiFont       : 0n0    
    +0x078 hatchIndex       : 0n-1    
    +0x07c lastPattern      : [8]  ""    
    +0x084 lastPatType      : 0n0    
    +0x088 lastFgColor      : 0    
    +0x08c lastBkColor      : 0    
    +0x090 infoContext      : 0x00000000`7c0133d1 HDC__    
    +0x094 fontFunction     : 0x00000000`71db263a     <---overwritten with 0x6D8B1CFD    
    +0x098 state            : [24]  "" 

Exploitation: ROP chains for English, German, Korean and Chinese OS

The exploit uses ROP gadgets built on top of DBGHELP.DLL library, which is normally loaded into the memory space of Exchange Server store.exe process. It is possible that the first version of the exploit was instead developed using OLECNV32.DLL gadgets. Even with the lack of ASLR randomization, obtaining reliable and universal exploitation of this vulnerability is not immediate, because DBGHELP.DLL is a language-dependent library (multiple versions exist for different OS languages). This introduces certain variance across different versions of Windows Server 2003. 

The attacker solved this problem by pre-calculating the correct offsets for each OS version they were interested in targeting. In fact, the configuration XML file included in EnglishmansDentist contains ROP gadgets developed for Windows Server 2003 in English but also for German, Korean, Simplified Chinese, and Traditional Chinese, disclosing all the potential targeted platforms of attacker’s interest.

The decoding of the ROP gadgets configured in EnglishmansDentist will map to these code blocks of DBGHELP.DLL module.

The first gadget executed by the function pointer overwrite (0x6d8b1cfd) will do some stack alignment and re-balancing EBP (add 0x1A0) and then transfer control to the full ROP chain using a combination of LEAVE/RET instructions. The full ROP chain (as seen in memory) is shown below with the equivalent gadgets on the right. It’s a short ROP chain which allocates executable memory to bypass DEP (0x8888 bytes) and copies into this region additional shellcode (egghunter) which is responsible for running the final backdoor payload with SYSTEM privilege (as granted by the Exchange Server process under attack). 

0:057> r 
eax=4a85c948 ebx=00094850 ecx=00000000 edx=00000020 esi=000949c0 edi=4a85ca0c 
eip=6d8b1cfd esp=4a85c738 ebp=4a85ca50 iopl=0         nv up ei pl nz na po nc 
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202 
6d8b1cfd ??              ???  

0:057> dps ebp+1a0+4
4a85cbf4  6d849568 ;pop ecx/retn 
4a85cbf8  6d831104  ;ptr kernel32!VirtualAlloc 
4a85cbfc  6d88c464  ;mov eax,dword[ecx]/retn 
4a85cc00  6d85f71d  ;jmp eax 
4a85cc04  6d849568  ;pop ecx/retn 
4a85cc08  00000000  ;VirtuaAlloc_arg1(lpAddress) 
4a85cc0c  00008888  ;VirtuaAlloc_arg2(dwSize) 
4a85cc10  00001000  ;VirtuaAlloc_arg3(MEM_COMMIT) 
4a85cc14  00000040  ;VirtuaAlloc_arg4(PAGE_RWX) 
4a85cc18  a4f3f88b  ;code "mov edi,eax/rep movs byte [edi],[esi]" 
4a85cc1c  6d893f8b  ;mov dword ptr [eax],ecx/ret8 
4a85cc20  6d849568  ;pop ecx/retn 
4a85cc24  72b8130f   
4a85cc28  534c1b8a 
4a85cc2c  00000031  ;size of movs byte (egghunter) 
4a85cc30  6d843b71  ;pop esi/retn 
4a85cc34  71d096fc 
4a85cc38  6d85f71d  ;jmp eax 

Detection and Mitigations

As we mentioned earlier, Windows Server 2003 lacks fundamental mitigations developed in the last decade of security enhancements of Microsoft products. Because of ASLR, CFG and other mitigations, a similar bug in a modern operating system like Windows 10 Creators Update or Windows Server 2016 will be much more difficult to remotely exploit. Also, the introduction of integrity levels and containers (sandbox), allowed Microsoft to constrain certain graphic rendering components to minimize the damage in case of a parsing vulnerability like the one discussed today (e.g. Office Protected View, AppContainer for browsers, Font sandbox for fonts rendering).

Finally, these days the evolution of security checks in Microsoft compilers and the extensive use of fuzzing can find and eliminate similar bugs in the source code before they ship in the products, reducing the entire class of bugs at the source.

We are providing a YARA signature which can be used to detect the PICT images delivered in emails by EnglishmansDentist for customers still running Windows Server 2003. 

rule PICT_ENGLISHMANEDENTIST 
{    
    strings:     
        $hdr  = {0B B0 00 00 00 00 00 64 00 64 11 01}    
        $tag  = {03 15 00 A1 00 64 01 00 50 50 4E 54 00 11 00 4D}     
        $rop1 = {FF FF 01 01 FD 1C}     
        $rop2 = {68 95 ?? ?? 04 11 ?? ?? 64 C4 ?? ?? 1D F7 ?? ?? 68 95}     
        
        condition:  
            $hdr and #tag>5 and $rop1 and $rop2 and filesize<100KB 
}

As always, we recommend that customers use the latest and newest OS and Microsoft products, so as to benefit from the security enhancements and mitigations against exploits added at each iteration.

Final Words

I’d like to extend a thank you to Matt Miller (MSRC), Ben Faull (Office Security) and Brent Alinger (Office 365) for their notes and help provided in analyzing this exploit.

Elia Florio,
Windows Defender ATP Research Team


Comments (0)

Skip to main content