Wednesday, February 12, 2020

CVE-2019-1108 Root Cause Analysis

posted by Lanph3re

Introduction

In December 2019, MS RDP vulnerability is introduced in BlackHat Europe 2019 session. The link is here.

RDP stands for Remote Desktop Protocol, which allows users to connect to remote desktop endpoint via network. Protocol detail is below from wikipedia.

Remote Desktop Protocol (RDP) is a proprietary protocol developed by Microsoft, which provides a user with a graphical interface to connect to another computer over a network connection. The user employs RDP client software for this purpose, while the other computer must run RDP server software.
Clients exist for most versions of Microsoft Windows (including Windows Mobile), Linux, Unix, macOS, iOS, Android, and other operating systems. RDP servers are built into Windows operating systems; an RDP server for Unix and OS X also exists. By default, the server listens on TCP port 3389 and UDP port 3389.

CVE-2019-1108, which is an information disclosure vulnerability, is a bug in RDP client which is triggered in processing RDP sound virtual channel(RDPSND). RDP client can receive sounds from RDP server, for sound option is enabled by default.

Sound information is delivered by RDPSND virtual channel. Virtual channel is dedicated channel for its specific purpose, in above case, sound. There are many virtual channels between RDP server and client which allows them to communicate various types of information.

Fuzzer Implementation

As in BlackHat presenstation slides, fuzzer should be modified to fuzz the rdp client. So I needed to audit the original winafl fuzzer source code and had to a little dev. Winafl is forked version of AFL fuzzer to use in Windows.



Implementing the fuzzer took a little long time, as I wasn't familiar with Windows APIs and also had little knowledge of how the original fuzzer is implemented.

In winafl, there is a function called write_to_testcase which writes mutated data in file. I added the code that send mutated data to RDP server using socket. As vulnerability is caused by virtual channel, the data itself served to RDP client by fuzzer is meaningless. RDP server get its data from client(using socket), and relay them back to RDP client via RDPSND virtual channel.

When modifying fuzzer was done and ran for a couple of hours, I got the crash.
To get seed for fuzzing, I hooked mstscax!CChan::ChannelOnPacketReceived() using frida.



Root Cause Analysis

The patch for vulnerability is released in July in 2019.

CVE-2019-1108 | Remote Desktop Protocol Client Information Disclosure Vulnerability
Security Vulnerability
Published: 07/09/2019 | Last Updated : 11/19/2019
MITRE CVE-2019-1108
An information disclosure vulnerability exists when the Windows RDP client improperly discloses the contents of its memory. An attacker who successfully exploited this vulnerability could obtain information to further compromise the user’s system.
To exploit this vulnerability, an attacker would have to connect remotely to an affected system and run a specially crafted application.
The security update addresses the vulnerability by correcting how the Windows RDP client initializes memory. 
FAQ
What type of information could be disclosed by this vulnerability?
The type of information that could be disclosed if an attacker successfully exploited this vulnerability is uninitialized memory.

As noted in FAQ, the vulnerability is caused by uninitialized memory. The patch would be done in a way that initializes newly allocated memory(ex. memset()).

I installed the patch to figure out differences in patched version, got the patched dll. I began with comparing the vulnerable version and patched version of mstscax.dll in bindiff.


In the lists of patched function, there is CRDPSound::vcwaveChooseSoundFormat(), which sounds interesting. With control flow graph by bindiff, I saw the difference.


The patch added memset() right after the malloc() function.
Before digging into the root cause of the vulnerability, here is the format of RDPSND PDU(Protocol Data Unit) between RDP server and client.



sndFormats in RDPSND PDU is array of AUDIO_FORMAT which is information about audio formats supported by server(or client). Its definition is as follows.



Then I took a look at CRDPSound::DataArrived() which is the caller function of the patched CRDPSound::vcwaveChooseSoundFormat(). The bug is caused by PDU whose msgType value is 7.

Simple PDU verification is done, and then calls CRDPSound::vcwaveChooseSoundFormat().

client_snd_formats = (struct SNDFORMATITEM *)malloc(total_size); allocates memory. Then parsing PDU sent by server is done, checking if (snd_formats->nAvgBytesPerSec). Here I could find what vulnerability was. The bug is that uninitialized memory is returned when nAvgBytesPerSec field of all AUDIO_FORMAT in PDU is zero.

So the patch added memset(client_snd_formats, 0, total_size); to prevent uninitialize memory from being returned.

Writing exploit

I could read values in memory with triggering the vulnerability.
But it is no use reading garbage values. So I used heap spray so that I could
read meaningful values in memory, which is image base of mstscax.dll.

To spraying heap, Dynamic channel is used.
It is channel that RDP server and client can use to reliable communication.
Its internal implementation uses lots of memory allocation and free. So it can be used to manipulate heap.

A dynamic channel manager is allocated in heap when a new dynamic channel is created.
The point is that this manager has vftable which has lots of function pointers that can be
used to leak the base address of mstscax.dll.

I allocated about 1000 channels(heap spray), and free them all.
RDP server can send CLOSE_REQUEST_PDU to the client to free a dynamic channel.
Hers is structure of CLOSE_REQUEST_PDU.


cbId indicates the length of the ChannelId field.
- 0x00: The ChannelId is 1 byte wide.
- 0x01: The ChannelId is 2 bytes wide.
- 0x02: The ChannelId is 4 bytes wide.

So exploit scenario is as follows.
1. Spray dynamic channels
2. Free all the channels allocated
3. Trigger the vulnerability
4. Get the image base of mstscax.dll

Finally I leak the base address. Exploit can be found here.

I had little experience exploiting windows heap, so this exploit is unreliable :(