Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I like questions about Windows Security. So if I occasionally see such one I try to solve it.</p> <p>In your case you did already the first step by the usage of <code>netsh.exe wlan export profile ...</code> to export the data from the WLAN profile in XML file. The file contains <code>&lt;keyMaterial&gt;</code> element. The data inside of the element are binary data encoded as the Hex: (something like <code>01000000D08C9DDF0115D1118C7A00C0...</code>).</p> <p>So what you need to do first of all is to decode the string to binary data. You can use <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa380285%28v=vs.85%29.aspx" rel="nofollow noreferrer">CryptStringToBinary</a> with <code>CRYPT_STRING_HEX</code> parameter to decode the string to binary.</p> <p>The next step will be to fill <code>DATA_BLOB</code> with the binary data and call <code>CryptUnprotectData</code> to get the result, but... There are small problem. How you can read in the documentation of <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms706738%28v=vs.85%29.aspx" rel="nofollow noreferrer">WlanGetProfile</a> the following</p> <blockquote> <p>By default, the <strong>keyMaterial</strong> element returned in the profile pointed to by the <em>pstrProfileXml</em> is encrypted. If your process runs in the context of the <strong>LocalSystem</strong> account on the same computer, then you can unencrypt key material by calling the <strong>CryptUnprotectData</strong> function.</p> <p><strong>Windows Server 2008 and Windows Vista</strong>: The <strong>keyMaterial</strong> element returned in the profile schema pointed to by the <em>pstrProfileXml</em> is always encrypted. If your process runs in the context of the <strong>LocalSystem</strong> account, then you can unencrypt key material by calling the <strong>CryptUnprotectData</strong> function.</p> </blockquote> <p>So to be able to unencrypt the key we have to call <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa380882%28v=vs.85%29.aspx" rel="nofollow noreferrer">CryptUnprotectData</a> in <strong>LocalSystem</strong> security context. If your program already run under <strong>LocalSystem</strong> context you can do this directly. If it's not so, but you have administrative rights or you have at least Debug privilege, you can "to borrow" the <strong>LocalSystem</strong> token from some other process running on the computer. For example one can get the process token of "winlogon.exe" process and impersonate it.</p> <p>The following demo program enumerate processes using <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509%28v=vs.85%29.aspx" rel="nofollow noreferrer">NtQuerySystemInformation</a> method (see my <a href="https://stackoverflow.com/a/4110741/315935">old answer</a>) which I personally prefer. One can use <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms682629%28v=vs.85%29.aspx" rel="nofollow noreferrer">EnumProcesses</a> or other well-known ways to do the same. Here is the code which worked at me</p> <pre><code>#include &lt;Windows.h&gt; #include &lt;tchar.h&gt; #include &lt;stdio.h&gt; #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, &amp;luid)) return FALSE; if (!OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &amp;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, &amp;tp, sizeof(TOKEN_PRIVILEGES), &amp;tpPrevious, &amp;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 &amp; tpPrevious.Privileges[0].Attributes); AdjustTokenPrivileges( hToken, FALSE, &amp;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, &amp;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-&gt;NextEntryOffset + (PBYTE)pspid)) { if (pspid-&gt;ImageName.Length == uLen &amp;&amp; lstrcmpiW(pspid-&gt;ImageName.Buffer, pszProcessName) == 0) return (DWORD)pspid-&gt;UniqueProcessId; if (pspid-&gt;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 &lt;keyMaterial&gt; 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, &amp;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, &amp;cbBinary, &amp;dwSkip, &amp;dwFlags); if (!bIsSuccess) __leave; DataOut.cbData = cbBinary; DataOut.pbData = (BYTE*)byKey; if (CryptUnprotectData (&amp;DataOut, NULL, NULL, NULL, NULL, 0, &amp;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; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload