Decrypt wlan wlan profile key using CryptUnprotectData

I am trying to decrypt a WEP profile key using CryptUnprotectData . The way I retrieved the profile key is to export the profile using netsh.

netsh wlan export profile name="MyWEP" folder="./" 

Now I manually copied the key material from the XML file generated by the netsh command into my program. And the way I am decryption is

 DATA_BLOB DataOut, DataVerify; DataOut.cbData = encryptData.length(); DataOut.pbData = (BYTE*)("I_Manually_Copy_The_WEP_Key_Here"); if (CryptUnprotectData( &DataOut, NULL, NULL, NULL, NULL, 0, &DataVerify)) { printf("The decrypted data is: %s\n", DataVerify.pbData); } else { printf("Failed. Error Code: %d", GetLastError()); } 

But I get error code 13 , referring to Invalid data. What am I doing wrong? In Win 7 and later, I can directly use WlanGetProfile with the WLAN_PROFILE_GET_PLAINTEXT_KEY parameter. But I have NO Vista strong> option than using the CryptUnprotectData function. Here I saw similar entries here , but did not get much useful information. In addition, I use the same system with the same username as the credentials. Can someone suggest me how to proceed?

PS: I posted the same question on the Windows Desktop SDK forums, but haven’t received an answer yet. Trying good luck on SO.

+6
source share
1 answer

I like questions about Windows security. Therefore, if I sometimes see this, I try to solve it.

In your case, you have already taken the first step using netsh.exe wlan export profile ... to export data from a WLAN profile to an XML file. The file contains an <keyMaterial> element. The data inside the element is binary data encoded as Hex: (something like 01000000D08C9DDF0115D1118C7A00C0... ).

So what you need to do first is decode the string into binary data. You can use CryptStringToBinary with the parameter CRYPT_STRING_HEX to decode a string in binary format.

The next step is to populate DATA_BLOB binary data and call CryptUnprotectData to get the result, but ... There is a small problem. As you can read in the WlanGetProfile documentation the following

By default, the keyMaterial element is returned to the profile pointed to by pstrProfileXml encrypted. If your process is running in the context of the LocalSystem account on the same computer, then you can unencrypt key material by calling the CryptUnprotectData strong> function .

Windows Server 2008 and Windows Vista strong>: the keyMaterial element returned in the profile scheme pointed to by pstrProfileXml is always encrypted. If your process runs in the context of the Local System , you can decrypt the key material by calling the CryptUnprotectData function strong>.

So, in order to be able to decrypt the key, we must call CryptUnprotectData in the security context of LocalSystem . If your program is already running in the LocalSystem context, you can do this directly. If this is not the case, but you have administrator rights, or you have at least the Debug privilege, you can "borrow" the LocalSystem token from another process running on the computer. For example, you can get the process token of the process "winlogon.exe" and impersonate it.

The following demo program lists processes using the NtQuerySystemInformation method (see my old answer ), which I personally prefer. You can use EnumProcesses or other well-known ways to do the same. Here is the code that worked for me

 #include <Windows.h> #include <tchar.h> #include <stdio.h> #pragma comment (lib, "Crypt32.lib") #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) typedef enum _SYSTEM_INFORMATION_CLASS { SystemProcessInformation = 5 } SYSTEM_INFORMATION_CLASS; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING; typedef LONG KPRIORITY; // Thread priority typedef struct _SYSTEM_PROCESS_INFORMATION_DETAILD { ULONG NextEntryOffset; ULONG NumberOfThreads; LARGE_INTEGER SpareLi1; LARGE_INTEGER SpareLi2; LARGE_INTEGER SpareLi3; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ImageName; KPRIORITY BasePriority; HANDLE UniqueProcessId; ULONG InheritedFromUniqueProcessId; ULONG HandleCount; BYTE Reserved4[4]; PVOID Reserved5[11]; SIZE_T PeakPagefileUsage; SIZE_T PrivatePageCount; LARGE_INTEGER Reserved6[6]; } SYSTEM_PROCESS_INFORMATION_DETAILD, *PSYSTEM_PROCESS_INFORMATION_DETAILD; typedef NTSTATUS (WINAPI *PFN_NT_QUERY_SYSTEM_INFORMATION)( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT OPTIONAL PULONG ReturnLength ); // // The function changes a privilege named pszPrivilege for // the current process. If bEnablePrivilege is FALSE, the privilege // will be disabled, otherwise it will be enabled. // BOOL SetCurrentPrivilege (LPCTSTR pszPrivilege, // Privilege to enable/disable BOOL bEnablePrivilege) // to enable or disable privilege { HANDLE hToken; TOKEN_PRIVILEGES tp; LUID luid; TOKEN_PRIVILEGES tpPrevious; DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES); BOOL bSuccess = FALSE; if (!LookupPrivilegeValue(NULL, pszPrivilege, &luid)) return FALSE; if (!OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken )) return FALSE; // // first pass. get current privilege setting // tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = 0; AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious); if (GetLastError() == ERROR_SUCCESS) { // // second pass. set privilege based on previous setting // tpPrevious.PrivilegeCount = 1; tpPrevious.Privileges[0].Luid = luid; if(bEnablePrivilege) tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); else tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes); AdjustTokenPrivileges( hToken, FALSE, &tpPrevious, cbPrevious, NULL, NULL); if (GetLastError() == ERROR_SUCCESS) bSuccess=TRUE; CloseHandle(hToken); } else { DWORD dwErrorCode = GetLastError(); CloseHandle(hToken); SetLastError(dwErrorCode); } return bSuccess; } DWORD GetProcessIdByProcessName (LPCWSTR pszProcessName) { SIZE_T bufferSize = 1024*sizeof(SYSTEM_PROCESS_INFORMATION_DETAILD); PSYSTEM_PROCESS_INFORMATION_DETAILD pspid = NULL; HANDLE hHeap = GetProcessHeap(); PBYTE pBuffer = NULL; ULONG ReturnLength; PFN_NT_QUERY_SYSTEM_INFORMATION pfnNtQuerySystemInformation = (PFN_NT_QUERY_SYSTEM_INFORMATION) GetProcAddress (GetModuleHandle(TEXT("ntdll.dll")), "NtQuerySystemInformation"); NTSTATUS status; int uLen = lstrlenW(pszProcessName)*sizeof(WCHAR); __try { pBuffer = (PBYTE) HeapAlloc (hHeap, 0, bufferSize); #pragma warning(disable: 4127) while (TRUE) { #pragma warning(default: 4127) status = pfnNtQuerySystemInformation (SystemProcessInformation, (PVOID)pBuffer, bufferSize, &ReturnLength); if (status == STATUS_SUCCESS) break; else if (status != STATUS_INFO_LENGTH_MISMATCH) { // 0xC0000004L _tprintf (TEXT("ERROR 0x%X\n"), status); return 1; // error } bufferSize *= 2; pBuffer = (PBYTE) HeapReAlloc (hHeap, 0, (PVOID)pBuffer, bufferSize); } for (pspid = (PSYSTEM_PROCESS_INFORMATION_DETAILD)pBuffer; ; pspid = (PSYSTEM_PROCESS_INFORMATION_DETAILD)(pspid->NextEntryOffset + (PBYTE)pspid)) { if (pspid->ImageName.Length == uLen && lstrcmpiW(pspid->ImageName.Buffer, pszProcessName) == 0) return (DWORD)pspid->UniqueProcessId; if (pspid->NextEntryOffset == 0) break; } } __finally { pBuffer = (PBYTE) HeapFree (hHeap, 0, pBuffer); } return 0; } int _tmain() { BOOL bIsSuccess, bImpersonated = FALSE; HANDLE hProcess = NULL, hProcessToken = NULL; DATA_BLOB DataOut, DataVerify; // !!! in the next line you should copy the string from <keyMaterial> WCHAR szKey[] = L"01000000D08C9DDF0115D1118C7...."; BYTE byKey[1024]; DWORD cbBinary, dwFlags, dwSkip; DWORD dwProcessId = GetProcessIdByProcessName(L"winlogon.exe"); if (dwProcessId == 0) return 1; bIsSuccess = SetCurrentPrivilege(SE_DEBUG_NAME, TRUE); if (!bIsSuccess) return GetLastError(); __try { hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, dwProcessId); if (!hProcess) __leave; bIsSuccess = OpenProcessToken (hProcess, MAXIMUM_ALLOWED, &hProcessToken); if (!bIsSuccess) __leave; bIsSuccess = ImpersonateLoggedOnUser(hProcessToken); if (!bIsSuccess) __leave; bImpersonated = TRUE; cbBinary = sizeof(byKey); bIsSuccess = CryptStringToBinary (szKey, lstrlenW(szKey), CRYPT_STRING_HEX, // CRYPT_STRING_HEX_ANY byKey, &cbBinary, &dwSkip, &dwFlags); if (!bIsSuccess) __leave; DataOut.cbData = cbBinary; DataOut.pbData = (BYTE*)byKey; if (CryptUnprotectData (&DataOut, NULL, NULL, NULL, NULL, 0, &DataVerify)) { _tprintf(TEXT("The decrypted data is: %hs\n"), DataVerify.pbData); } } __finally { if (bImpersonated) RevertToSelf(); if (hProcess) CloseHandle(hProcess); if (hProcessToken) CloseHandle(hProcessToken); } return 0; } 
+7
source

Source: https://habr.com/ru/post/916738/


All Articles