Microsoft recently released a patch for a critical vulnerability in Microsoft Secure Channel (aka Schannel). This vulnerability is being referred to as MS14-066. The patch addressing CVE-2014-6321 fixed many areas within schannel.dll, including at least two vulnerabilities related to the handling of the Datagram Transport Layer Security (DTLS) protocol.
DTLS is used by Microsoft Remote Desktop Protocol (RDP) to provide communications privacy for datagram protocols. The DTLS protocol is used by Microsoft Windows Remote Desktop Gateway (RDG) to establish a secure channel between the RDG client and RDG server (described in detail in [MS_TSGU].pdf).
The RDG client initiates the DTLS connection by sending a ClientHello to the RDG Server. The RDG server then responds with a DTLS Hello Verify Request that contains a cookie; this is used as a denial of service countermeasure. The RDG client responds once again with a Client Hello packet containing the received cookie, which will initiate the DTLS handshake (RFC6347 Section 4.2).
Figure 1: Initiation of the DTLS handshake between RDG client and server
Figure 2: RDG client and server handshake phase (Source: [MS-TSGU] Section 220.127.116.11.1)
Before starting analysis, we needed to set up a test environment. For the RDG server we referred to the following walkthrough: http://terrytlslau.tls1.cc/2014/01/deploying-remote-desktop-gateway-in.html.
Now let’s explore these vulnerabilities.
Server-Side DTLS Out Of Bounds (OOB) Read
When a client sends the DTLS ClientHello packet to the server, the server computes a Message Authentication Code (MAC) on it and compares it to the cookie contained in the packet. But the server only checks the cookie length field, not whether the cookie buffer can be read. In fact, a 32 byte length is always read, which could lead to a buffer out-of-bounds condition.
It should be noted that a client could send a crafted packet to the server without needing to start an RDP session. Figure 3, below, shows a packet crafted to display a “Cookie Length” of 32 (32 is equivalent to 0x20 in hexadecimal), which does not match the actual amount of data in the cookie (shown containing only two 0x41 characters).
Figure 3: A crafted packet sending mismatched size and content
Related code is found in the DTLSCookieManager::ValidateCookie function:
.text:5883C0F5 movzx ecx, byte ptr [esi+edi]
.text:5883C0F9 add esp, 0Ch
.text:5883C0FC cmp ecx, 20h ;Checking that the CookieSize field is above 32 bytes
.text:5883C0FF ja short loc_5883C16E
.text:5883C14A call ?ComputeCookie@DTLSCookieManager@@AAEJQAEK0KPAE@Z ;
.text:5883C14F test eax, eax
.text:5883C151 js short loc_5883C16E
.text:5883C153 mov eax, [ebp+mgr]
.text:5883C156 push dword ptr [eax+10h] ; the compared size
.text:5883C159 lea eax, [esi+edi]
.text:5883C15C push eax ; compared Buf2, which points cookie buffer.
.text:5883C15D lea eax, [ebp+Buf1]
.text:5883C160 push eax ; compared Buf1
.text:5883C161 call _memcmp
As shown above, although the server checks the “CookieSize” field, the compared length is always *(_DWORD *)(mgr + 16)), whose value is 0x20; however, the real cookie buffer length could be less than 0x20. A crafted packet could set the “CookieSize” field to 0x20 and have the actual cookie buffer contain less than 0x20 bytes of data.
Client-Side Heap Overflow
When a DTLS client receives a HelloVerifyRequest packet with a CookieSize larger than 32 bytes the client does not properly validate the CookieSize value against the amount of cookie data in the packet. This scenario can result in a heap overflow. It should be noted that if you want modify the “CookieSize“ value, you should modify the other length fields to keep the packet structure valid, as shown below in Figure 4.
Figure 4: An example of a properly modified DTLS packet cookie
We can see the first packet is a normal ClientHello sent by the client, and the second packet is a crafted packet sent by the server. In order to examine exploitation of this vulnerability, we used WinDBG to attach to the lsass.exe process. Below, Figure 5 shows what the call stack looks like when the process crashes.
Figure 5: WinDBG view of call stack when lsass.exe process crashes due to exploitation
Vulnerable code is found in the CSsl3TlsClientContext::DigestServerHelloVerifyRequest function:
.text:5883DAC1 mov esi, [ebp+phvrversion] ; esi points to helloverifyrequest "version" field
.text:5883DAC4 sub esi, edx ; esi now points to the helloverifyrequest head
.text:5883DAC6 push ebx
.text:5883DAC7 mov bl, [esi+0Eh] ; cookiesize
.text:5883DACA movzx eax, bl
.text:5883DACD mov [ebp+phvrversion], eax ; [ebp+phvrversion] saves cookiesize
.text:5883DAD0 lea ecx, [eax+3]
.text:5883DAD3 mov eax, [ebp+fragment_len]
.text:5883DAD6 add ecx, edx
.text:5883DAD8 add eax, edx
.text:5883DADA cmp eax, ecx
.text:5883DADC jnb short loc_5883DAF1 ; jmp when fragment_len >= cookielen +3
.text:5883DAF1 test bl, bl ; Checking if cookiesize is 0
.text:5883DAF3 jz short loc_5883DB0B
.text:5883DAF5 push [ebp+phvrversion] ; cookiesize
.text:5883DAF8 lea eax, [esi+0Fh] ; eax points to cookie buffer
.text:5883DAFB push eax ; Src
.text:5883DAFC lea eax, [edi+270h] ; edi+0x270 is the target heap
.text:5883DB02 push eax ; Dst
.text:5883DB03 call _memcpy ; heap overflow