如何安全地获取和解密WiFi凭证

在连接到WiFi网络时,如果选择保存凭证,这些凭证不仅可以被Windows系统获取,任何知道如何查找的人都可以获取。开发了一个名为GetWifiData的小工具,用于显示任何已存储的WiFi数据。将维护这个工具,并在专门的网站上发布更新。

过去(在Windows XP中),凭证存储在注册表中,但从Windows 7开始,凭证存储在单独的XML文件中。原生WiFi提供了一个更好的方式访问WiFi凭证,因为它是任何API调用的前端,用于自动配置组件,连接或断开WiFi网络。此外,Windows原生WiFi可以以XML文档的形式存储与其交互的网络的配置文件。

WiFi凭证的存储方式

当连接到一个WiFi网络并选择保存凭证时,这些凭证可以被Windows系统或其他任何人在知道如何查找的情况下获取。不同版本的Windows中存储凭证的位置是不同的。

WindowsXP中,位置如下:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WZCSVC\Parameters\Interfaces\

在Windows Vista、7、8、8.1和10中,位置如下:

C:\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\{Random-GUID}.xml

在每个接口下,可以找到每个存储网络的单独文件。

Windows原生WiFi

较新的Windows“原生WiFi”提供了一种更好的方式访问WiFi凭证,因为它是任何API调用的前端,用于自动配置组件,连接或断开WiFi网络。此外,Windows原生WiFi可以以XML文档的形式存储与其交互的网络的配置文件。

XML凭证文件的解释

让以一个示例凭证文件为例。文件名为:

C:\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces\{9D0E4D68-B83A-4745-8021-DE4381E509BF}\{5094B710-D0BF-473A-BC7D-A51D4885F681}.xml

如上图所示,该文件包含名为Villa_Carriagehouse的WiFi网络的凭证,这是一个位于Indianapolis的优秀B&B酒店。几个月前住在那里(顺便说一句,这是一家很棒的酒店),所以凭证存储在PC中,可以被获取。

如何解密WiFi凭证

当WiFi凭证被加密时,可以使用Windows加密技术进行解密。微软的加密技术包括CryptoAPI、加密服务提供商(CSP)、CryptoAPI工具、CAPICOM、WinTrust、发行和管理证书以及开发可定制的公钥基础设施。

首先,需要定位一个名为keyMaterial的元素,将其隔离到一个字符串变量(strKey)中。给定strKey是一个CString变量,包含一个加密的WiFi凭证密钥(密码),以下代码块使用CryptUnprotectedData将其解密。

BYTE byteKey[1024] = {0}; DWORD dwLength = 1024; DATA_BLOB dataOut, dataVerify; BOOL bRes = CryptStringToBinary(strKey, strKey.GetLength(), CRYPT_STRING_HEX, byteKey, &dwLength, 0, 0); if (bRes) { dataOut.cbData = dwLength; dataOut.pbData = (BYTE*)byteKey; if (CryptUnprotectData(&dataOut, NULL, NULL, NULL, NULL, 0, &dataVerify)) { TCHAR str[MAX_PATH] = {0}; wsprintf(str, L"%hs", dataVerify.pbData); strKey = str; } }

结果,strKey现在将包含给定WiFi网络的解密密码。

现在,所需要做的就是遍历每个WiFi/网络接口,对于每个接口,遍历每个XML配置文件,并获取该配置文件的WiFi凭证,全部显示在屏幕上的报告中,并在文件中。

为此,以下是在Secured Globe, Inc中使用的一些辅助函数。

使用WriteStatus()进行日志记录

使用日志记录有多种目的,在大多数情况下,希望在控制台窗口(即使是基于UI的应用程序)以及文本文件('log')中看到任何重要的事情,以便以后使用。

void WriteStatus(LPCTSTR lpText, ...) { FILE *fp; CTime Today = CTime::GetCurrentTime(); CString sMsg; CString sLine; va_list ptr; va_start(ptr, lpText); sMsg.FormatV(lpText, ptr); sLine.Format(L"%s", (LPCTSTR)sMsg); _wfopen_s(&fp, utilsLogFilename, L"a"); if (fp) { fwprintf(fp, L"%s", sLine); fclose(fp); } wprintf(L"%s", sMsg); }

基本上,只需要使用WriteStatus调用相同的参数,而不是使用printf(或wprintf)。

确保管理员权限

此类程序需要管理员权限。首先可以通过强制用户提升来实现。

转到项目的属性。然后转到Linker -> Manifest File -> UAC Execution Level,并将其值设置为requireAdministrator(/level='requireAdministrator')。

此外,还有一种方法可以在运行时检测执行级别。使用以下函数:

BOOL IsElevated() { DWORD dwSize = 0; HANDLE hToken = NULL; BOOL bReturn = FALSE; TOKEN_ELEVATION tokenInformation; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) return FALSE; if (GetTokenInformation(hToken, TokenElevation, &tokenInformation, sizeof(TOKEN_ELEVATION), &dwSize)) { bReturn = (BOOL)tokenInformation.TokenIsElevated; } CloseHandle(hToken); return bReturn; }

然后,如果程序没有以“管理员”身份运行,可以警告用户,这在项目设置中并不真正需要,但为了描述IsElevated()函数,在源代码中放置了以下行:

if (!IsElevated()) WriteStatus(L"[!] Running without administrative rights\n");

使用漂亮的控制台窗口显示输出

为了在运行时显示程序的输出,而不必等待日志文件,使用以下函数和功能:

为了获取桌面尺寸,以便调整控制台大小以适应最大可能的尺寸(更大的尺寸=可以显示更多的数据),使用以下函数:

void GetDesktopResolution(int& horizontal, int& vertical) { RECT desktop; // Get a handle to the desktop window const HWND hDesktop = GetDesktopWindow(); // Get the size of screen to the variable desktop GetWindowRect(hDesktop, &desktop); // The top left corner will have coordinates (0,0) // and the bottom right corner will have coordinates // (horizontal, vertical) horizontal = desktop.right; vertical = desktop.bottom; }

然后使用以下函数控制文本的颜色:

#define LOG_COLOR_WHITE 7 #define LOG_COLOR_GREEN 10 #define LOG_COLOR_YELLOW 14 #define LOG_COLOR_MAGENTA 13 #define LOG_COLOR_CIAN 11 void SetColor(int ForgC) { WORD wColor; static int LastColor = -1; if (LastColor == ForgC) return; LastColor = ForgC; //This handle is needed to get the current background attribute HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbi; //csbi is used for wAttributes word if (GetConsoleScreenBufferInfo(hStdOut, &csbi)) { //To mask out all but the background attribute, and to add the color wColor = (csbi.wAttributes & 0xF0) + (ForgC & 0x0F); SetConsoleTextAttribute(hStdOut, wColor); } return; }

当然,这只是个例子,可以定义其他颜色,并设置更多的前景和背景颜色组合以满足需求。

然后结合所有内容,这里是一个示例:

SetColor(LOG_COLOR_CIAN); if (!IsElevated()) WriteStatus(L"[!] Running without administrative rights\n"); WriteStatus(L"WiFi Stored Credentials Report\nproduced by GetWifiData, by Secured Globe, Inc.\n\n"); SetColor(LOG_COLOR_MAGENTA); WriteStatus(L"http://www.securedglobe.com\n\n\n"); SetColor(LOG_COLOR_CIAN);
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485