Extracting WLAN Passphrases From Windows

April 29, 2020 • Blog
Posted by
Benjamin McMillan
Share this article

Windows stores WLAN profile information in the following location.

%SYSTEMDRIVE%\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces\{INTERFACE_GUID}\{PROFILE_GUID}.xml

These files contain information such as the SSID, encryption type, and the encrypted passphrase stored as a HEX encoded string.

<?xml version="1.0"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
    <name>Chun-Li</name>
    <SSIDConfig>
        <SSID>
            <hex>4368756E2D4C69</hex>
            <name>Chun-Li</name>
        </SSID>
    </SSIDConfig>
    <connectionType>ESS</connectionType>
    <connectionMode>manual</connectionMode>
    <MSM>
        <security>
            <authEncryption>
                <authentication>WPA2PSK</authentication>
                <encryption>AES</encryption>
                <useOneX>false</useOneX>
            </authEncryption>
            <sharedKey>
                <keyType>passPhrase</keyType>
                <protected>true</protected>
                <keyMaterial>01000000D0...snip...DD0F6377F4</keyMaterial>
            </sharedKey>
        </security>
    </MSM>
    <MacRandomization xmlns="http://www.microsoft.com/networking/WLAN/profile/v3">
        <enableRandomization>false</enableRandomization>
    </MacRandomization>
</WLANProfile>

There are two interesting things I noticed.

  • The WLAN profiles will persist through a system reboot even when “connect automatically” is unticked when authenticating (this is the connectionMode element)
  • The XML files are accessible by all users.

The passphrase is encrypted with the machine credentials using Windows Data Protection API (DPAPI) before being converted to a HEX encoded string. The code block below shows how the plaintext passphrase could be retrieved.

using System;
using System.Text;
using System.Security.Cryptography;

public class WlanDecrypt
{

    public static void Main()
    {
        try
        {
            string hexEncodedPassword = "01000000D0...snip...DD0F6377F4";
          
            // convert to a byte array
            byte[] passwordByteArray = new byte[hexEncodedPassword.Length / 2];
            for (int i = 0; i < hexEncodedPassword.Length; i += 2)
                passwordByteArray[i / 2] = 
Convert.ToByte(hexEncodedPassword.Substring(i, 2), 16);

            // decrypt byte array
            byte[] unprotectedBytes = 
ProtectedData.Unprotect(passwordByteArray, null, 
DataProtectionScope.LocalMachine);

            string cleartextPassword = 
Encoding.ASCII.GetString(unprotectedBytes);
            Console.WriteLine(cleartextPassword);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

This is all just to demonstrate the decryption, since the cleartext passphrase can be easily retrieved with netsh, e.g.

Code 4

You can’t retrieve the plaintext passphrase using netsh from the context of a different user, but with access to the profile XML files you could take the HEX string and decrypt it with the ProtectedData class. You could also just use Metasploit or NirSoft WirelessKeyView.

This WLAN_profile XML schema is supported from Windows XP SP3 onwards, where prior to this the passphrases were stored in the registry at the following location.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WZCSVC\Parameters\Interfaces\{INTERFACE_GUID}

In addition, the passphrase here is stored in REG_BINARY format and will require some extra decoding.


Contact us

Speak with a Tesserent
Security Specialist

Tesserent is a full-service cybersecurity and secure cloud services provider, partnering with clients from all industries and all levels of government. Let’s talk.

Let's Talk
Tess head 9 min