MS12-020 Vulnerabilities in Remote Desktop Could Allow Remote Code Execution

MS12-020 Vulnerabilities in Remote Desktop Could Allow Remote Code Execution

Update(03/19/2012) : Now I understand why MS said “we are not expecting to see the exploit in a few days”. To be honest, I don’t really understand how this vulnerability is working @.@. The actual bug trigger (known by leaked PoC) is in the last two pictures (rdpwd!nm_Disconnect), and you can trigger this routine by making this function fail in the middle after executing “or [esi+1c], 1”. Please see my comments below how to trigger this.

Update(03/16/2012) : Crash PoCs are available now by cool guys from freenode co-work. Here’s big fun. These codes were written based on the wild-PoC, but that wild-PoC seems to be the one originally reported to ZDI (!/luigi_auriemma). Do you see what this means ? πŸ™‚ (python) (by jduck, ruby)

Update : more diffing points. Well… you’re right. I’m still guessing.

NOTE : I haven’t confirmed this vulnerability yet, so basically this is my rough guess on this vulnerability. MS12-020 touched many different files and I don’t think I’ll take a look all of them. Hope we get helpful feed-backs on this issue from you. There’s also other analysis on MS12-020 –

Related CVE : Remote Desktop Protocol Vulnerability – CVE-2012-0002
Terminal Server Denial of Service Vulnerability – CVE-2012-0152
(This post would be about CVE-2012-0002, but need to be confirmed)

Diffed Binary : rdpcore.dll 6.1.7601.17514 (win7sp1_rtm.101119-1850)
rdpcore.dll 6.1.7601.17779 (win7sp1_gdr.120216-1503)

Look at CRDPWDUMXStack:OnMcsCPI(). This function decodes and saves the user data from the GCCUserData structure. When you make the first branch condition fail, you can directly call RDPWDUMXGccFreeUserData() function, which is a simple wrapper function of delete(). It is clear that [ebp+var_10] is uninitialized before the patch. How it is patched ? Just look at where a series of “stosd” instructions are.)

rdpwd!HandleAttachUserReq(). This one is easy to trigger and looks very interesting, but it could be just a memory leak patch.

rdpwd!MCSChannelJoinRequest(). There was some problems in handling channel id. Note that each channel seems to have a corresponding entry in the link list.

tdtcp.sys!DeviceCancelIo(). See different function call has been made, TdiDisconnect() and TdLocalDisconnect(). TdLocalDisconnect() is actually a wrapper function of TdiDisconnect() while doing DEREF like job. Do you remember MS11-083 ? MS11-083’s vulnerability and patch was pretty similar to this.

rdpwd!nm_Disconnect(). After invoking the destructing function, it clears LSB-bit of the variable. See? Before actually invoking the destructing function, this LSB-bit variable is checked. Yeah, it should be double free (or use-after-free).

rdpwd!NMAbortConnect() has a similar pattern patch. Note that these two routines are closely linked together. That is, if you can hit NMAbortConnect(), it is highly likely that you can also hit nm_Disconnect(). In other words, if you can invoke these two routines, at least you will see crash.


31 thoughts on “MS12-020 Vulnerabilities in Remote Desktop Could Allow Remote Code Execution

  1. suto

    Another vector maybe interesting:
    Original Version:
    void __stdcall CRDPWDUMXStack::OnReadCompleted(int a1, int a2)
    int v3; // esi@2
    int v4; // ebx@2
    struct _RTL_CRITICAL_SECTION *lpCriticalSection; // [sp+8h] [bp-Ch]@1
    int v6; // [sp+Ch] [bp-8h]@2
    int v7; // [sp+10h] [bp-4h]@2

    lpCriticalSection = (struct _RTL_CRITICAL_SECTION *)(a1 + 44);
    EnterCriticalSection((LPCRITICAL_SECTION)(a1 + 44));
    if ( *(_BYTE *)(a1 + 12) & 0x10 )
    (*(void (__stdcall **)(_DWORD, int))(**(_DWORD **)(a1 + 1144) + 16))(*(_DWORD *)(a1 + 1144), a2);

    And Patched Version:
    void __stdcall CRDPWDUMXStack::OnReadCompleted(int a1, int a2)
    int v4; // ebx@2
    int v5; // eax@3
    struct _RTL_CRITICAL_SECTION *lpCriticalSection; // [sp+8h] [bp-Ch]@1
    int v7; // [sp+Ch] [bp-8h]@2
    int v8; // [sp+10h] [bp-4h]@2

    lpCriticalSection = (struct _RTL_CRITICAL_SECTION *)(a1 + 44);
    EnterCriticalSection((LPCRITICAL_SECTION)(a1 + 44));
    if ( *(_BYTE *)(a1 + 12) & 0x10 )
    v5 = 0x80004004u;

    No call anymore? Huh????

  2. Mario Vilas

    Not sure if it’s relevant yet, but there’s another interesting change in CTSThread::StartThread(). In the unpatched version it calls PAL_System_ThreadAlloc(), but in the patched version it calls PAL_System_ThreadAllocInit() instead – a new function that wraps PAL_System_ThreadAlloc() and does some more things before and after it.

  3. Pingback: MS12-020 – Mycket allvarlig brist i Remote Desktop Protocol « SAFESIDE-bloggen

  4. Pingback: CVE-2012-0002 «

  5. gossi (@ActualGossi)

    Snort rules:

    alert tcp any any -> any 3389 (flow:to_server,established; content:”|03 00|”; depth:2; content:”|7f 65 82|”; distance:5; within:3; content:”|30 19|”; distance:11; within:2; byte_test:1, any 3389 (flow:to_server,established; content:”|03 00|”; depth:2; content:”|7f 65 82|”; distance:5; within:3; content:”|30 1c|”; distance:65; within:2; byte_test:2,<,6,2,relative;)

  6. The Moorish

    Luigi Auriemma ‏ @luigi_auriemma confirmed:

    ms12-020 mistery: the packet stored in the “chinese” rdpclient.exe PoC is the EXACT ONE I gave to ZDI!!! @thezdi? @microsoft? who leaked?

    anyone has the Chinese PoC?

  7. Pingback: Exploit pΓΊblico para MS12-020 (Parchea tu windows!) - TalSoft TS S.R.L.

  8. Sn00ok

    The poc rdpclient.exe is valid. I’ve tested on Vista SP1 and Vista SP2. bluescreens after remote execution.

      1. The Moorish

        yes i have posted a warning but the comment comment is awaiting moderation.

        Thanks Jeremy Richards!


    Looks like ruby code triggers a bug check. Does it mean that memory corruption occurs within ring 0,that is, a .sys module?

  10. Anonymous

    Is this related to a race condition?!

    Server-side Crash Scenario
    1. Connect initial Packet
    – Make a new channel object
    2. During the connect initial, server recv a Attach User Request packet
    – call HandleAttachUserReq
    – and SListRemove
    3. Connect initial which is not finished
    – use removed channel object (use after free)

    1. If a server get only connect initial packet, no crash occurred. But, when I added Attach User Request packet, crash occurred
    2. When I set a breakpoint in connect initial procedure, no crash occurred.
    3. Maybe HandleAttachUserReq function is exported. (Called by termdd module)

    4. My scenario does make sense…

    How do you think?!

    1. lifeasageek Post author

      You’re right. There’s seems to be a timing issue by depending on when you disconnect the connection, but I don’t truly understand how it’s working. Here’s my guess.
      – You can set maxChannelIds using domain parameters.
      – Each calling of HandleAttachUserReq() increases the number of channel id by 1.
      – if(maxChannelIds == the number of channel id) ==> then it goes to the error handling routine, which triggers the use-after-free bug.
      – thus, if you disconnect the connection (or disconnected by the server) before the number of channel id reaches to the maxChannelIds, then there’s no crash ?
      You better go to freenode #MS12-020 channel, and ask there πŸ™‚

  11. Dave

    Very good posts πŸ˜€
    I would just like to know why there are so many null bytes in the above PoC’s you have posted?

    I thought nulls in shellcode meant it wouldn’t be executed, can you please explain?
    Keep the updates coming though.

    1. lifeasageek Post author

      Shellcodes? πŸ™‚ As far as I know, there’s no working code execution exploits so far. Perhaps null bytes you’ve seen would be RDP protocol packets.

      1. Mario Vilas

        In any case, the null byte problem only occurs when exploiting bugs related to the C language string manipulation functions (like strcpy for example).

        That’s only because C strings use the null byte to indicate where strings end, as opposed to other languages in which string objects have an explicit size attribute.

        In general, restrictions to shellcodes have to do entirely with what the vulnerable program is doing with the shellcode bytes before the remote code execution happens. Sometimes you have to avoid uppercase letters instead of null bytes, just to give you an example. There’s nothing “magical” about null bytes in particular. πŸ™‚

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s