Monday, March 26, 2012

Understand MS12-020

I saw many misunderstanding about MS12-020 bug. Here is my quick explanation (hope it is clear). There are 2 bugs for this bulletin. One is RCE (CVE-2012-0002). Another one is DoS (CVE-2012-0152). I use the diff result from work of people in IRC (freenode#MS12-020) http://pastie.org/private/4egcqt9nucxnsiksudy5dw.

Understand User and Channel in RDP

The User and Channel words explain themselves. A client can create a user by sending "MCS Attach User Request" (see the sequence) to server. When creating a user, a server also create a channel for user. This channel is called "User Channel". The assigned user id is always the same as channel id. There is special user that created by sending "MCS Connect Initial" request with "Client Network Data". It is "Server User" that created along with "Server Channel".

Channels can be created by sending "MCS Connect Initial" request with "Client Network Data" or "MCS Channel Join Request" with channel id 0.

Now let see how a server keeps track of Users and Channels. There are global Channel list and global User list (SList) for each connection. For each channel, there is a list to keep joined users. Similar to user. For each user, there is a list to keep joined channels.

CVE-2012-0002

There are 2 specific advisories for this CVE, Luigi and ZDI. This bug occurs while adding channels (in NM_Connect()) specified in "Client Network Data". When a server cannot create more channel (by checking a number of channel in Channel list with MaximumChannelIds), the NMAbortConnect() is called. When look inside SM_OnConnected(), you will see NM_Disconnect() is called. Then NMDetachUserReq() is called twice. So this is use-after-free bug.

You can see Kostya's work of this bug from his blog (MS12-020 round up). Additional, the bug can be triggered even MaximumChannelIds > 32 by sending "Connect Initial" request and "Attach User" requests at once. Because userData in "Connect Initial" is dispatched to another thread for processing (my guess). The "Attach User" requests are processed first. So a number of channel is Channel list is not 0 before processing the "Client Network Data".

Now the idea to controlling EIP is doing remote memory spray on svchost process with RDP requests. The difficulty is all RDP request is handled directly in driver (kernel mode). Only some data is copied to user mode memory space. I still cannot do it. Need more free time.

CVE-2012-0152

There is only 1 advisory from Microsoft, this is a DoS bug. Many people guess the bug is in HandleAttachUserReq(). But I think it is in MCSChannelJoinRequest(). Here is my reason.

User Channel is supposed to be joined only by user owner. But the bug in MCSChannelJoinRequest() allow it. So the change is comparing request channel id against request user id instead of request channel id. This bug seems to have no problem at first. But when removing user (DetachUser()), the User Channel is destroyed too. If User does not join its own channel, the channel is destroyed without removing joined users.

To trigger the bug is simple. First we send 2 "Attach User" requests. So we have userA and userB with channelA and channelB. Then we send a "Channel Join" request for userA with channelB. If we manage to removing userB before userA, channelB is destroyed while joined channel list in userA still have channelB. Then removing userB will try to remove itself from destroyed channelB. Boom!!

This is also user-after-free bug. But I cannot find any interesting operation on freed channel. So I guess this is a DoS bug. Some useful for this bug is safe remote detecting the vulnerabilities on a target. Here is my code for checking.