Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / security / cryptography

The Secrets of Wi-Fi Credentials

4.99/5 (41 votes)
9 Jan 2017CPOL5 min read 40.9K   2.1K  
How to fetch and decrypt Wi-Fi stored credentials
The article focuses on Wi-Fi stored credentials and how they can easily be fetched and decrypted.

Image 1

Introduction

When you connect to a Wifi network and choose to save the credentials, they can be later fetched not only by Windows but by anyone who knows where and how to look for them. We developed a small utility named GetWifiData for the purpose of displaying any stored Wifi data. We will maintain this tool and publish updates in a dedicated web site. See also How Skype account details can be obtained.

Purpose of the Article

In the past (Windows XP), credentials were stored in the Registry, however since Windows 7, the credentials are stored in separate XML files. The Native Wifi also provides a centralized way to access the credentials, while Windows Cryptography provides the necessities to decrypt the encryption keys back. Several articles were published about Wifi credentials, but some of them are outdated which is why I wrote this article and created the utility to display all stored Wifi credentials.

How Wifi Credentials Are Stored

When you connect to a Wifi network and choose to save the credentials, they can be fetched later not only by Windows but by anyone who knows where and how to look for them.

The location is different among different versions of Windows.

On Windows XP, that place would be under the following Registry location:

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

On Windows Vista, 7, 8, 8.1 and 10 that place would be in a file (not in the Registry):

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

Under each interface, you can find separate files per stored network.

Image 2

Windows Native Wifi

The more recent Windows “Native Wifi” provides a better way to access the Wifi credentials as it is the front end of any API call to automatically configure component configures, to connect or disconnect from / to a Wifi network. Further, Windows Native Wifi can store profiles on the networks it interacts with in the form of XML documents.

The source code of this article uses a simple method to fetch each element from these XML files and to generate a report of all stored Wifi credentials.

We initilize our program as follows:

C++
WLAN_INTERFACE_INFO_LIST* pWirelessAdapterList = NULL;
dwResult = WlanEnumInterfaces(hWlan, NULL, &pWirelessAdapterList);
if (dwResult != ERROR_SUCCESS)
{
    WlanCloseHandle(hWlan, NULL);
    return result;
}

int nResCount = 1;
WLAN_INTERFACE_INFO* pWirelessAdapterInfo = NULL;

Interpretation of the XML Credential Files

Let's take a sample credential file as an example. The file name is:

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

Image 3

Image 4

As you can see in the photo above, the file holds the credentials of a Wifi network named Villa_Carriagehouse from a great B&B hotel in Indinapolis. We stayed there several months ago (great hotel, by the way) so the credentials are stored in my PC and can be fetched, as you can see.

Going Back to Our Topic...

Windows uses the WLAN_profile Schema to define each WLAN's profile using the following XML elements:

  • SSID - Both plain text and HEX versions can be found and contain the SSID of a wireless LAN.
  • name - The 'name' element is the SSID in the form of plain text.
  • authentication - The 'authentication' element specifies the authentication method to be used.
  • encryption - The 'encryption' element specifies the type of data encryption to be used.
  • keyMaterial - The 'keyMaterial' element contains a network key or passphrase. If the protected element has a value of TRUE, then this key material is encrypted; otherwise, the key material is unencrypted. Encrypted key material is expressed in hexadecimal form.

Image 5

How Wi-Fi Credentials Can Be Decrypted

When the Wi-Fi credentials are encrypted, they can be decrypted using Windows Cryptography. Microsoft cryptographic technologies include CryptoAPI, Cryptographic Service Providers (CSP), CryptoAPI Tools, CAPICOM, WinTrust, issuing and managing certificates, and developing customizable public key infrastructures.

First, we need to locate an element named keyMaterial and isolate it into a string variable (strKey).

Given strKey is a CString variable holding an encrypted Wi-Fi credential key (pass code), the following code block uses CryptUnprotectedData to decrypt it back.

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

As a result, strKey will now hold the decrypted password for the given Wi-Fi network.

Wrapping Up

Now, all we need to do is to go over each Wi-Fi / Network interface and for each interface, go over each XML profile and fetch the Wi-Fi credentials of that profile, all into one report on screen and in a file.

To do so, here are some helper functions we use at Secured Globe, Inc.

Logging using WriteStatus()

We use logging for several purposes and in most cases, we want to see anything important that happens, on a Console window (even with UI based applications) as well as in a text file (the 'log') which can be used later.

C++
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);
}

Basically, instead of using printf (or wprintf), you just call WriteStatus with the same arguments.

The output of the GetWifiData program is generated using this function.

Ensuring Administration Privileges

Such program requires Administrator privileges. That can be achieved first by forcing the user to elevate.

Go to the project's properties. Then go to Linker -> Manifest File -> UAC Execution Level, and set the value to requireAdministrator (/level='requireAdministrator').

In addition, there is a way to detect the execution level during runtime. We use the following function:

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

Then you can warn the user in case the program isn't running "As Administrator" which isn't really needed given the project's settings described herein, but for the purpose of describing the IsElevated() function, I placed the following line in our source code:

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

Displaying Output Using a Fancy Console Window

For the purpose of showing the program's output during runtime, without having to wait for the log file, we use the following functions and functionalities:

To get the Desktop measures for the purpose of resizing the console to fit the maximum size possible (larger size = more data to be displayed), we use the following function:

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

Then we control the color of the text using the following function:

C++
#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;
}

Of course, this is only an example and you can define other colors and set more combinations of foreground and background colors to fit your needs.

Then to combine all together, here is an example:

C++
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);

The Source Code

This article is accompanied with a Visual Studio 2013 Ultimate, C++ project. The source code is independent and generates a single executable that can run on its own with no external DLLs needed and no pre-installation required.

History

  • 9th January, 2017: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)