Talos Vulnerability Report

TALOS-2019-0901

Microsoft Remote Desktop Services (RDP8) license negotiation denial-of-service vulnerability

December 10, 2019
CVE Number

CVE-2019-1453

Summary

An exploitable denial-of-service vulnerability exists in the RDP8 implementation of Microsoft’s Remote Desktop Services. A certain component of license negotiation can allow a remote client to read an amount of memory that is controlled by the client. Due to this, a client can coerce the component to read from memory that is unmapped, resulting in a denial-of-service condition. An attacker can negotiate capabilities and then send a particular packet type in order to trigger this vulnerability.

Tested Versions

Microsoft’s Remote Desktop Services – Windows 7: RdpCoreTS.dll 6.2.9200.22828

Product URLs

https://docs.microsoft.com/en-us/windows/win32/termserv/terminal-services-portal

CVSSv3 Score

7.5 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

CWE

CWE-126: Buffer Over-read

Details

Remote Desktop Services allow a user or administrator to take control of a remote computer over a network connection. This allows the user to utilize a familiar graphical user interface to interact with said remote machine which provides a thin-client architecture on the Windows platform. These capabilities are accomplished using the Remote Desktop Protocol which is built on top of the X.224, T.124, T.125, T.128 protocols. Remote Desktop Services is a common service within the enterprise and is commonly used as a work-around on a network with otherwise minimalistic remote administration capabilities.

When a client initializes a connection via the RDP protocol, the client must first go through a number of stages in order to setup each of the individual layers that are used by the RDS platform. During setup of the T.125 layer, a client may announce a number of channels by name that the server is expected to connect to an endpoint. After establishing this and performing the rest of the required negotiations, the client will then perform a security exchange which is required to complete the initialization of the T.128 protocol which will provide the Multipoint Application Sharing component as mentioned in the T.128 specification. After performing this security exchange, the client will then need to negotiate capabilities with the remote server. This is done by first receiving a packet from the server containing the supported capabilities, followed by a response from the client with the capabilities that it will use. After this has been accomplished, the server will then connect the channel names requested by the client to their endpoints and then perform the license exchange. Due to the server using the same channel protocol for things such as the license exchange, and a number of other capabilities, a remote client can establish a connection to these internal channels and interact with the logic of their endpoint. One of the packet types parsed by its endpoint allows a user to specify a length that will be used to make an allocation, and use it as a length when copying data from the packet into the buffer. Due to the client controlling the length, this can enable the client to specify a length that is larger than the packet resulting in potentially reading an unmapped memory resulting in a denial of service condition.

When establishing a connection, the server will instantiate a CUMRDPConnection object. This object appears to be an abbreviation of “User-mode RDP Connection”. Once this object has been constructed to manage the connection from the client, the CUMRDPConnection::CreateVirtualChannel method will be called for each channel. This method will eventually check its parameter using stricmp() to see if the channel name that was passed to it is one of the strings listed. At [1], if the channel name is “rdplic” the application will go down a branch where a failure should be returned. Nonetheless, this list contains a number of channel endpoints that the remote client is able to communicate with by writing to the channel via the T.125 protocol. It is assumed by the author that these endpoints are not intended to be reachable by a remote client as the implementation in RdpCoreTS.dll seems to write undocumented structures to these different channel endpoints.

rdpcorets!CUMRDPConnection::CreateVirtualChannel:
000007fe`f9ae191c 48895c2410      mov     qword ptr [rsp+10h],rbx
000007fe`f9ae1921 4489442418      mov     dword ptr [rsp+18h],r8d
000007fe`f9ae1926 55              push    rbp
000007fe`f9ae1927 56              push    rsi
000007fe`f9ae1928 57              push    rdi
000007fe`f9ae1929 4154            push    r12
000007fe`f9ae192b 4155            push    r13
000007fe`f9ae192d 4156            push    r14
000007fe`f9ae192f 4157            push    r15
000007fe`f9ae1931 4883ec40        sub     rsp,40h
...
rdpcorets!CUMRDPConnection::CreateVirtualChannel+0x212:
000007fe`f9ae1b2e 488d0d932df7ff  lea     rcx,[rdpcorets!`string' (000007fe`f9a548c8)]      ; "DRDYNVC"
000007fe`f9ae1b35 498bd7          mov     rdx,r15
000007fe`f9ae1b38 ff15ca822700    call    qword ptr [rdpcorets!_imp__stricmp (000007fe`f9d59e08)]
000007fe`f9ae1b3e 85c0            test    eax,eax
000007fe`f9ae1b40 0f840c010000    je      rdpcorets!CUMRDPConnection::CreateVirtualChannel+0x336 (000007fe`f9ae1c52)
...
000007fe`f9ae1b46 488d0d832df7ff  lea     rcx,[rdpcorets!`string' (000007fe`f9a548d0)]      ; "rdpgrfx"
000007fe`f9ae1b4d 498bd7          mov     rdx,r15
000007fe`f9ae1b50 ff15b2822700    call    qword ptr [rdpcorets!_imp__stricmp (000007fe`f9d59e08)]
000007fe`f9ae1b56 85c0            test    eax,eax
000007fe`f9ae1b58 0f84f4000000    je      rdpcorets!CUMRDPConnection::CreateVirtualChannel+0x336 (000007fe`f9ae1c52)
...
000007fe`f9ae1b5e 488d0d732df7ff  lea     rcx,[rdpcorets!`string' (000007fe`f9a548d8)]      ; "rdpinpt"
000007fe`f9ae1b65 498bd7          mov     rdx,r15
000007fe`f9ae1b68 ff159a822700    call    qword ptr [rdpcorets!_imp__stricmp (000007fe`f9d59e08)]
000007fe`f9ae1b6e 85c0            test    eax,eax
000007fe`f9ae1b70 0f84dc000000    je      rdpcorets!CUMRDPConnection::CreateVirtualChannel+0x336 (000007fe`f9ae1c52)
...
000007fe`f9ae1b76 488d0d632df7ff  lea     rcx,[rdpcorets!`string' (000007fe`f9a548e0)]      ; "rdpcmd"
000007fe`f9ae1b7d 498bd7          mov     rdx,r15
000007fe`f9ae1b80 ff1582822700    call    qword ptr [rdpcorets!_imp__stricmp (000007fe`f9d59e08)]
000007fe`f9ae1b86 85c0            test    eax,eax
000007fe`f9ae1b88 0f84c4000000    je      rdpcorets!CUMRDPConnection::CreateVirtualChannel+0x336 (000007fe`f9ae1c52)
...
000007fe`f9ae1b8e 488d0d532df7ff  lea     rcx,[rdpcorets!`string' (000007fe`f9a548e8)]      ; [1] "rdplic"
000007fe`f9ae1b95 498bd7          mov     rdx,r15
000007fe`f9ae1b98 ff156a822700    call    qword ptr [rdpcorets!_imp__stricmp (000007fe`f9d59e08)]
000007fe`f9ae1b9e 85c0            test    eax,eax
000007fe`f9ae1ba0 0f84ac000000    je      rdpcorets!CUMRDPConnection::CreateVirtualChannel+0x336 (000007fe`f9ae1c52)
...
000007fe`f9ae1ba6 488d0d432df7ff  lea     rcx,[rdpcorets!`string' (000007fe`f9a548f0)]      ; "Microsoft::Windows::RDS::Graphics"
000007fe`f9ae1bad 498bd7          mov     rdx,r15
000007fe`f9ae1bb0 ff1552822700    call    qword ptr [rdpcorets!_imp__stricmp (000007fe`f9d59e08)]
000007fe`f9ae1bb6 85c0            test    eax,eax
000007fe`f9ae1bb8 0f8494000000    je      rdpcorets!CUMRDPConnection::CreateVirtualChannel+0x336 (000007fe`f9ae1c52)
...
000007fe`f9ae1bbe 488d0d4f2df7ff  lea     rcx,[rdpcorets!`string' (000007fe`f9a54914)]      ; "RDPSND"
000007fe`f9ae1bc5 498bd7          mov     rdx,r15
000007fe`f9ae1bc8 ff153a822700    call    qword ptr [rdpcorets!_imp__stricmp (000007fe`f9d59e08)]
000007fe`f9ae1bce 85c0            test    eax,eax
000007fe`f9ae1bd0 7504            jne     rdpcorets!CUMRDPConnection::CreateVirtualChannel+0x2ba (000007fe`f9ae1bd6)

When creating the endpoint for the “rdplic” channel, the service will first call the CUMRDPLicPluginFactory_CreateInstance function. This object is responsible for creating instances of the CUMRDPLicPlugin object as needed. This is done with the IRDPCOREChannelPluginFactory interface. One of the methods within this interface is the CUMRDPLicPluginFactory::CreateConnectionChannel method and is shown in the following disassembly. When creating an instance for the channel, this method will create a COM interface by calling the __RDPAPIDLL__CreateInstance function with the CLSID and IID (Interface ID) specified at [2]. Once finally calling __RDPAPIDLL__CreateInstance at [3], the CUMRDPLicPlugin_CreateInstance function will then be called. This is the function that’s actually responsible for creating an instance of a CUMRDLicPlugin. First at [4], the function will allocate 0xd8 bytes for the object. Afterwards, the object’s virtual method tables will be populated by the function. One of the method tables at [5], IRDPCoreVirtualChannelEvents, is responsible for actually receiving events as a channel endpoint and is implemented by a number of other objects for the channel names that were prior mentioned.

rdpcorets!CUMRDPLicPluginFactory::CreateConnectionChannels:
000007fe`f9ae8930 4055            push    rbp
000007fe`f9ae8932 53              push    rbx
000007fe`f9ae8933 56              push    rsi
000007fe`f9ae8934 57              push    rdi
000007fe`f9ae8935 4156            push    r14
000007fe`f9ae8937 488bec          mov     rbp,rsp
000007fe`f9ae893a 4883ec40        sub     rsp,40h
...
rdpcorets!CUMRDPLicPluginFactory::CreateConnectionChannels+0x197:
000007fe`f9ae8ac7 488b4e40        mov     rcx,qword ptr [rsi+40h]
000007fe`f9ae8acb 4c8d4d30        lea     r9,[rbp+30h]
000007fe`f9ae8acf 4c8d0592b1f6ff  lea     r8,[rdpcorets!IID_IUMTSLicensePlugin (000007fe`f9a53c68)]             ; [2] IID_IUMTSLicensePlugin
000007fe`f9ae8ad6 488d158b98f6ff  lea     rdx,[rdpcorets!CLSID_UMRDPLICPlugin (000007fe`f9a52368)]              ; [2] CLSID_UMRDPLICPlugin
000007fe`f9ae8add e8e2c80000      call    rdpcorets!__RDPAPIDLL__CreateInstance (000007fe`f9af53c4)             ; [3] \\
000007fe`f9ae8ae2 8bd8            mov     ebx,eax
000007fe`f9ae8ae4 85c0            test    eax,eax
000007fe`f9ae8ae6 7944            jns     rdpcorets!CUMRDPLicPluginFactory::CreateConnectionChannels+0x1fc (000007fe`f9ae8b2c)
\\
rdpcorets!CUMRDPLicPlugin_CreateInstance:
000007fe`f9ae8ed8 488bc4          mov     rax,rsp
000007fe`f9ae8edb 48895808        mov     qword ptr [rax+8],rbx
000007fe`f9ae8edf 48896810        mov     qword ptr [rax+10h],rbp
000007fe`f9ae8ee3 48897018        mov     qword ptr [rax+18h],rsi
000007fe`f9ae8ee7 48897820        mov     qword ptr [rax+20h],rdi
000007fe`f9ae8eeb 4156            push    r14
000007fe`f9ae8eed 4883ec30        sub     rsp,30h
...
000007fe`f9ae8ef1 488bf9          mov     rdi,rcx
000007fe`f9ae8ef4 b9d8000000      mov     ecx,0D8h
000007fe`f9ae8ef9 498bf0          mov     rsi,r8
000007fe`f9ae8efc 488bea          mov     rbp,rdx
000007fe`f9ae8eff ff158b0f2700    call    qword ptr [rdpcorets!_imp_??2YAPEAX_KZ (000007fe`f9d59e90)]           ; [4] allocate 0xd8 bytes
000007fe`f9ae8f05 4533f6          xor     r14d,r14d
000007fe`f9ae8f08 488bd8          mov     rbx,rax
000007fe`f9ae8f0b 4885c0          test    rax,rax
000007fe`f9ae8f0e 0f84b4000000    je      rdpcorets!CUMRDPLicPlugin_CreateInstance+0xf0 (000007fe`f9ae8fc8)
...
000007fe`f9ae8f14 c74030cdabcadb  mov     dword ptr [rax+30h],0DBCAABCDh
000007fe`f9ae8f1b c7403401000000  mov     dword ptr [rax+34h],1
000007fe`f9ae8f22 4883c020        add     rax,20h
000007fe`f9ae8f26 48894018        mov     qword ptr [rax+18h],rax
000007fe`f9ae8f2a 488d0d3740fcff  lea     rcx,[rdpcorets!CCaRdpGfxEncoderRaw::`vftable' (000007fe`f9aacf68)]    ; Default INonDelegatingUnknown
000007fe`f9ae8f31 458d4640        lea     r8d,[r14+40h]
000007fe`f9ae8f35 488908          mov     qword ptr [rax],rcx
000007fe`f9ae8f38 488d0dc9aff6ff  lea     rcx,[rdpcorets!CTSUnknown::`vftable' (000007fe`f9a53f08)]             ; Default CTSObject
000007fe`f9ae8f3f 33d2            xor     edx,edx
000007fe`f9ae8f41 48894808        mov     qword ptr [rax+8],rcx
000007fe`f9ae8f45 44897020        mov     dword ptr [rax+20h],r14d
000007fe`f9ae8f49 488d0da0cbfbff  lea     rcx,[rdpcorets!CUMRDPLicPlugin::`vftable' (000007fe`f9aa5af0)]        ; [5] Implementation of IRDPCoreVirtualChannelEvents
000007fe`f9ae8f50 48890b          mov     qword ptr [rbx],rcx
000007fe`f9ae8f53 488d0d66cbfbff  lea     rcx,[rdpcorets!CUMRDPLicPlugin::`vftable' (000007fe`f9aa5ac0)]        ; Implementation of IRDPCOREChannelPlugin
000007fe`f9ae8f5a 48894b08        mov     qword ptr [rbx+8],rcx
000007fe`f9ae8f5e 488d0d3bcbfbff  lea     rcx,[rdpcorets!CUMRDPLicPlugin::`vftable' (000007fe`f9aa5aa0)]        ; Implementation of IUMTSLicensePlugin
000007fe`f9ae8f65 48894b10        mov     qword ptr [rbx+10h],rcx
000007fe`f9ae8f69 488d0df8cafbff  lea     rcx,[rdpcorets!CUMRDPLicPlugin::`vftable' (000007fe`f9aa5a68)]        ; Implementation of IWRdsProtocolLicenseConnection
000007fe`f9ae8f70 48894b18        mov     qword ptr [rbx+18h],rcx
000007fe`f9ae8f74 488d0dd5cafbff  lea     rcx,[rdpcorets!CUMRDPLicPlugin::`vftable' (000007fe`f9aa5a50)]        ; Implementation of INonDelegatingUnknown
000007fe`f9ae8f7b 488908          mov     qword ptr [rax],rcx
000007fe`f9ae8f7e 488d05abcafbff  lea     rax,[rdpcorets!CUMRDPLicPlugin::`vftable' (000007fe`f9aa5a30)]        ; Implementation of CTSObject
000007fe`f9ae8f85 488d8b88000000  lea     rcx,[rbx+88h]
000007fe`f9ae8f8c 48894328        mov     qword ptr [rbx+28h],rax

The implementation of the IRDPCoreVirtualChannelEvents method table is as follows. When receiving data on the “rdplic” channel, the CUMRDPLicPlugin::OnDataReceived method at [6] will be called with the channel data and its length as its parameters.

000007fe`f9aa5af0  000007fe`f9c1126c rdpcorets!CUMRDPLicPlugin::QueryInterface
000007fe`f9aa5af8  000007fe`f9ae84b0 rdpcorets!CRDPGfxPlugin::AddRef
000007fe`f9aa5b00  000007fe`f9ae84c4 rdpcorets!CUMTSCommandPlugin::Release
000007fe`f9aa5b08  000007fe`f9ae95f0 rdpcorets!CUMRDPLicPlugin::OnDataReceived      ; [6]
000007fe`f9aa5b10  000007fe`f9ae9570 rdpcorets!CUMRDPLicPlugin::OnClose
000007fe`f9aa5b18  000007fe`f9ae9560 rdpcorets!CUMRDPLicPlugin::OnChannelOpened
000007fe`f9aa5b20  000007fe`f9ae95d0 rdpcorets!CUMRDPLicPlugin::OnDataSent
000007fe`f9aa5b28  000007fe`f9aea544 rdpcorets!CFakeGfxProvider::HandleSHMUpdate
000007fe`f9aa5b30  000007fe`f9ae924c rdpcorets!CUMRDPLicPlugin::Initialize

As was prior mentioned, data written to the “rdplic” channel will result in the server executing the following method to handle its endpoint. This method takes two parameters at [7] representing the channel data and its length. This data is taken directly from the client and is intended to be processed by this method. Once these values are loaded into the %r8 and %r15d registers, the method will continue and then check the first 16-bits of the channel data at [8] to see if they’re one of 3 possible values. Depending on the value, one of the cases listed will be entered. At [9] when the first 16-bits are set to 0x1630, the handler for its case will be entered. This handler will simply hand-off the channel data and its length to the CUMRDPLicPlugin::HandleClientLicensePdu method at [10]. As this method is called anytime data is written to the channel, these cases can be called repeatedly and at anytime the remote client chooses.

rdpcorets!CUMRDPLicPlugin::OnDataReceived:
000007fe`f9ae95f0 48895c2408      mov     qword ptr [rsp+8],rbx
000007fe`f9ae95f5 48896c2410      mov     qword ptr [rsp+10h],rbp
000007fe`f9ae95fa 4889742418      mov     qword ptr [rsp+18h],rsi
000007fe`f9ae95ff 57              push    rdi
000007fe`f9ae9600 4156            push    r14
000007fe`f9ae9602 4157            push    r15
000007fe`f9ae9604 4883ec20        sub     rsp,20h
000007fe`f9ae9608 33f6            xor     esi,esi
000007fe`f9ae960a 4d8bf0          mov     r14,r8        ; [7] Channel Data
000007fe`f9ae960d 448bfa          mov     r15d,edx      ; [7] Channel Data Length
000007fe`f9ae9610 488be9          mov     rbp,rcx       ; CUMRDPLicPlugin*
000007fe`f9ae9613 4d85c0          test    r8,r8
000007fe`f9ae9616 7543            jne     rdpcorets!CUMRDPLicPlugin::OnDataReceived+0x6b (000007fe`f9ae965b)
...
rdpcorets!CUMRDPLicPlugin::OnDataReceived+0x6b:
000007fe`f9ae965b b301            mov     bl,1
000007fe`f9ae965d 488d3dbc0a2100  lea     rdi,[rdpcorets!WPP_GLOBAL_Control (000007fe`f9cfa120)]
000007fe`f9ae9664 83fa04          cmp     edx,4
000007fe`f9ae9667 732b            jae     rdpcorets!CUMRDPLicPlugin::OnDataReceived+0xa4 (000007fe`f9ae9694)
...
rdpcorets!CUMRDPLicPlugin::OnDataReceived+0xa4:
000007fe`f9ae9694 488b0d850a2100  mov     rcx,qword ptr [rdpcorets!WPP_GLOBAL_Control (000007fe`f9cfa120)]
000007fe`f9ae969b 410fb706        movzx   eax,word ptr [r14]        ; [8] Read 16-bits from beginning of ChannelData packet
000007fe`f9ae969f 3d30130000      cmp     eax,1330h
000007fe`f9ae96a4 0f8493000000    je      rdpcorets!CUMRDPLicPlugin::OnDataReceived+0x14d (000007fe`f9ae973d)
...
000007fe`f9ae96aa 3d30160000      cmp     eax,1630h                 ; [9] Check if 16-bits are 0x1630
000007fe`f9ae96af 747a            je      rdpcorets!CUMRDPLicPlugin::OnDataReceived+0x13b (000007fe`f9ae972b)
...
000007fe`f9ae96b1 3d30190000      cmp     eax,1930h
000007fe`f9ae96b6 7425            je      rdpcorets!CUMRDPLicPlugin::OnDataReceived+0xed (000007fe`f9ae96dd)
...
rdpcorets!CUMRDPLicPlugin::OnDataReceived+0x13b:
000007fe`f9ae972b 4d8bc6          mov     r8,r14        ; [10] Channel Data
000007fe`f9ae972e 418bd7          mov     edx,r15d      ; Channel Data Length
000007fe`f9ae9731 488bcd          mov     rcx,rbp       ; CUMRDPLicPlugin*
000007fe`f9ae9734 e8fb0a0000      call    rdpcorets!CUMRDPLicPlugin::HandleClientLicensePdu (000007fe`f39ca234)
000007fe`f9ae9739 8bf0            mov     esi,eax
000007fe`f9ae973b eb45            jmp     rdpcorets!CUMRDPLicPlugin::OnDataReceived+0x192 (000007fe`f39c9782)

After the channel data and its length are passed to the CUMRDPLicPlugin::HandleClientLicensePdu method, these values are then loaded into registers at [11] with the channel data being loaded from the %r8 register into %rbp, and the channel data’s length left in %edx. At [12], the channel data’s length will be checked to see if it’s larger than 9. If so, then the code at [13] will be executed. This will read 32-bits from the channel data at [13], and then use the 32-bits directly as a parameter to the allocation that follows (operator new). As the remote client controls the length that is being used, this allows the client to make arbitrarily sized allocations. Once the allocation has been made at [14], the result will then be written into offset 0x78 of the CUMRDPLicPlugin object. As a result of this property being overwritten, the previous value of the property is removed from the scope of the object before being properly released which can allow the remote client to repeatedly make controlled allocations to trigger memory exhaustion. Afterwards at [15], the channel data at offset +0x8 of the packet will be copied into the buffer that was allocated. As the client controls the length of this allocated buffer and the length used while copying channel data from the packet, a remote client can specify a length that is larger than the source packet data resulting in the memcpy() function reading from unmapped memory while trying to copy data. This can result in a denial of service condition.

rdpcorets!CUMRDPLicPlugin::HandleClientLicensePdu:
000007fe`f9aea234 48895c2408      mov     qword ptr [rsp+8],rbx
000007fe`f9aea239 48896c2410      mov     qword ptr [rsp+10h],rbp
000007fe`f9aea23e 4889742418      mov     qword ptr [rsp+18h],rsi
000007fe`f9aea243 57              push    rdi
000007fe`f9aea244 4883ec30        sub     rsp,30h
000007fe`f9aea248 33db            xor     ebx,ebx
000007fe`f9aea24a 498be8          mov     rbp,r8                    ; [11] Channel Data
000007fe`f9aea24d 488bf1          mov     rsi,rcx                   ; CUMRDPLicPlugin*
000007fe`f9aea250 4d85c0          test    r8,r8
000007fe`f9aea253 0f8426010000    je      rdpcorets!CUMRDPLicPlugin::HandleClientLicensePdu+0x14b (000007fe`f9aea37f)
000007fe`f9aea259 83fa09          cmp     edx,9                     ; [12] Channel Length
000007fe`f9aea25c 0f821d010000    jb      rdpcorets!CUMRDPLicPlugin::HandleClientLicensePdu+0x14b (000007fe`f9aea37f)
000007fe`f9aea262 488d3db7fe2000  lea     rdi,[rdpcorets!WPP_GLOBAL_Control (000007fe`f9aea120)]
000007fe`f9aea269 41395804        cmp     dword ptr [r8+4],ebx
000007fe`f9aea26d 7545            jne     rdpcorets!CUMRDPLicPlugin::HandleClientLicensePdu+0x80 (000007fe`f9aea2b4)
...
rdpcorets!CUMRDPLicPlugin::HandleClientLicensePdu+0x80:
000007fe`f9aea2b4 418b4804        mov     ecx,dword ptr [r8+4]      ; [13] 32-bits from offset +0x4 of Channel Data
000007fe`f9aea2b8 ff15c2fb2600    call    qword ptr [rdpcorets!_imp_??_UYAPEAX_KZ (000007fe`f9ae9e80)]
000007fe`f9aea2be 48894678        mov     qword ptr [rsi+78h],rax   ; [14] Overwrite value at offset +0x78 of Object
000007fe`f9aea2c2 4885c0          test    rax,rax
000007fe`f9aea2c5 7555            jne     rdpcorets!CUMRDPLicPlugin::HandleClientLicensePdu+0xe8 (000007fe`f9aea31c)
...
rdpcorets!CUMRDPLicPlugin::HandleClientLicensePdu+0xe8:
000007fe`f9aea31c 448b4504        mov     r8d,dword ptr [rbp+4]
000007fe`f9aea320 488d5508        lea     rdx,[rbp+8]               ; [15] Copy data from packet into allocation
000007fe`f9aea324 488bc8          mov     rcx,rax
000007fe`f9aea327 e8c4951f00      call    rdpcorets!memcpy (000007fe`f9ce38f0)

Crash Information

The base addresses of the functions described in the details are as follows:

0:032> lm vm rdpcorets
Browse full module list
start             end                 module name
000007fe`f9a50000 000007fe`f9d72000   rdpcorets   (pdb symbols)          c:\mss\RdpCoreTS.pdb\31C641C49232486FB999919FB0EBFC611\RdpCoreTS.pdb
    Loaded symbol image file: rdpcorets.dll
    Image path: C:\Windows\system32\rdpcorets.dll
    Image name: rdpcorets.dll
    Browse all global symbols  functions  data
    Timestamp:        Thu Jun  4 22:28:31 2015 (5571175F)
    CheckSum:         003110B6
    ImageSize:        00322000
    File version:     6.2.9200.21506
    Product version:  6.2.9200.21506
    File flags:       0 (Mask 3F)
    File OS:          40004 NT Win32
    File type:        1.0 App
    File date:        00000000.00000000
    Translations:     0409.04b0
    Information from resource tables:
        CompanyName:      Microsoft Corporation
        ProductName:      Microsoft® Windows® Operating System
        InternalName:     RdpCoreTS.dll
        OriginalFilename: RdpCoreTS.dll
        ProductVersion:   6.2.9200.21506
        FileVersion:      6.2.9200.21506 (win8_ldr.150604-1607)
        FileDescription:  TS RDPCore DLL
        LegalCopyright:   © Microsoft Corporation. All rights reserved.

Exploit Proof of Concept

To run the provided proof-of-concept, Python2 and the six module must be installed. To install the six module, one can simply use pip as follows:

$ pip install six

After installing the required modules, the proof-of-concept can then be run with the following command against RDS. To use the provided vulnerability to make a number of controlled allocations with the vulnerability, one may specify the size to use and the number of times to make it via the following parameters.

$ python poc.zip $host --size=$size --count=$count

In order to make the memcpy() operation read from an unmapped page at the end of the channel data, a large length will be needed as long as it is small enough to satisfy the memory allocation. Something similar to the following may be used to trigger a crash with the vulnerability.

$ python poc.zip $host --size=0x100000 --count=0x10

For further help, the --help parameter has also been implemented.

Mitigation

This denial-of-service vulnerability exist only on RDP8. RDP7, which is implemented in kernel-space, does not use the channels described within this document, and therefore is not vulnerable.

Timeline

2019-09-19 - Vendor Disclosure
2019-10-29 - 30 day follow up
2019-10-29 - Vendor assigned CVE
2019-12-10 - Public Release

Credit

Discovered by a member of Cisco Talos.