Decrypting Wireless Passwords on Windows

Introduction

We shall only focus on versions of Windows from Vista up to 10 since the location of wireless credentials prior to this are stored in the registry.

Enumerate Interfaces

C:\>reg query HKLM\SOFTWARE\Microsoft\Wlansvc\Interfaces

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{012C8D7D-D104-47F8-83FE-B9751F699A2F}
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{12487653-A815-4A9D-84E1-736D96554215}
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{13ECC539-1C25-4036-9615-D85A5D1B47CE}
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{295A80EE-8DC0-465F-ACF2-70DA1F036948}
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{3306C2A4-E4A5-42B3-A087-67EB542F0EC0}
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{40F69FB8-F23A-433E-94D9-D3983F220874}
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{66BA1985-E08C-4F57-9E36-2C229EB1BFCE}
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{6E318579-A15B-43AA-BC85-5A38133888A6}
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{AFEED710-CC5E-41BD-8975-E6EE0487B5C9}
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{F6B2D705-CCA4-439D-B7AF-4950A98CE00C}

To perform this programatically in C.

DWORD EnumInterfaces(VOID) {
  HKEY         hSubKey;
  DWORD        dwError, dwIndex, cbSize; 
  WCHAR        adapterGuid[256], profileList[4096*4];
  PWCHAR       pProfileGuid;
  std::wstring description;
  
  dwError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
      L"SOFTWARE\\Microsoft\\Wlansvc\\Interfaces", 0, 
      KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY, &hSubKey);
  
  if (dwError != ERROR_SUCCESS) {
    xstrerror(L"RegOpenKeyEx(\"SOFTWARE\\Microsoft\\Wlansvc\\Interfaces\"");
    return 0;
  }
  
  dwIndex = 0;
  
  for (;;) {
    cbSize = sizeof(adapterGuid) / sizeof(wchar_t);
    dwError = RegEnumKeyEx(hSubKey, dwIndex, adapterGuid, 
        &cbSize, NULL, NULL, NULL, NULL);
    
    if (dwError != ERROR_SUCCESS) break; 
  
    if (dwError == ERROR_SUCCESS) {
      description = GetAdapterDescription(adapterGuid);
      
      cbSize = sizeof(profileList) / sizeof(wchar_t);
      dwError = RegGetValue(hSubKey, adapterGuid, L"ProfileList", 
          RRF_RT_REG_MULTI_SZ, 0, profileList, &cbSize);
          
      if (dwError == ERROR_SUCCESS) {
        pProfileGuid = profileList;
      wprintf(L"\n\n  %s %s", description.c_str(), adapterGuid);
      
      wprintf(L"\n  %-20s  %-10s  %-20s  %-64s  %-20s", 
          std::wstring(20, L'-').c_str(), 
          std::wstring(10, L'-').c_str(),  
          std::wstring(20, L'-').c_str(), 
          std::wstring(20, L'-').c_str(),
          std::wstring(20, L'-').c_str());
      
      wprintf(L"\n  %-20s  %-10s  %-20s  %-64s  %-20s", 
          L"SSID", L"Auth", L"Encryption", L"Key(Ascii)", L"Key(Hex)");
          
      wprintf(L"\n  %-20s  %-10s  %-20s  %-64s  %-20s", 
          std::wstring(20, L'-').c_str(), 
          std::wstring(10, L'-').c_str(),  
          std::wstring(20, L'-').c_str(), 
          std::wstring(20, L'-').c_str(),
          std::wstring(20, L'-').c_str());
          
        for (;;) {
          DumpWLANProfile(adapterGuid, pProfileGuid);
          pProfileGuid += wcslen(pProfileGuid) + 1;
          if (pProfileGuid[0] == 0) break;
        }
      } 
    }
    dwIndex++;
  }
  RegCloseKey(hSubKey);
  return 0;
}

Each GUID represents a unique wireless adapter. To obtain a textual representation of this, we need to look at

reg query HKLM\SYSTEM\Select

HKEY_LOCAL_MACHINE\SYSTEM\Select
    Current          REG_DWORD    0x2
    Default          REG_DWORD    0x2
    Failed           REG_DWORD    0x1
    LastKnownGood    REG_DWORD    0x3

If we take the first GUID from the WLAN interfaces and query it.

C:\>reg query "HKLM\SYSTEM\ControlSet002\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\{012C8D7D-D104-47F8-83FE-B9751F699A2F}\Connection

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\{012C8D7D-D104-47F8-83FE-B9751F699A2F}\Connection
    DefaultNameResourceId    REG_DWORD    0x70e
    DefaultNameIndex         REG_DWORD    0x6
    Name                     REG_SZ       Wireless Network Connection 6
    PnpInstanceID            REG_SZ       {5D624F94-8850-40C3-A3FA-A4FD2080BAF3}\VWIFIMP\7&79A56D7&0&03
    MediaSubType             REG_DWORD    0x2

The PnpInstanceID

C:\>reg query "HKLM\SYSTEM\ControlSet002\Enum\{5D624F94-8850-40C3-A3FA-A4FD2080BAF3}\VWIFIMP\7&79A56D7&0&03"

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Enum\{5D624F94-8850-40C3-A3FA-A4FD2080BAF3}\VWIFIMP\7&79A56D7&0&03
    DeviceDesc             REG_SZ       @netvwifimp.inf,%vwifimp.devicedesc%;Microsoft Virtual WiFi Miniport Adapter
    LocationInformation    REG_SZ       VWiFi Bus 0
    Capabilities           REG_DWORD    0xa0
    UINumber               REG_DWORD    0x3
    HardwareID             REG_MULTI_SZ {5d624f94-8850-40c3-a3fa-a4fd2080baf3}\vwifimp
    CompatibleIDs          REG_MULTI_SZ {5d624f94-8850-40c3-a3fa-a4fd2080baf3}\vwifimp
    ContainerID            REG_SZ       {df3771ea-c60e-5fae-9656-83aa71808f29}
    ConfigFlags            REG_DWORD    0x0
    ClassGUID              REG_SZ       {4d36e972-e325-11ce-bfc1-08002be10318}
    Driver                 REG_SZ       {4d36e972-e325-11ce-bfc1-08002be10318}\0023
    FriendlyName           REG_SZ       Microsoft Virtual WiFi Miniport Adapter #3
    Class                  REG_SZ       Net
    Mfg                    REG_SZ       @netvwifimp.inf,%msft%;Microsoft
    Service                REG_SZ       vwifimp

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Enum\{5D624F94-8850-40C3-A3FA-A4FD2080BAF3}\VWIFIMP\7&79A56D7&0&03\Device Parameters
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Enum\{5D624F94-8850-40C3-A3FA-A4FD2080BAF3}\VWIFIMP\7&79A56D7&0&03\LogConf
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Enum\{5D624F94-8850-40C3-A3FA-A4FD2080BAF3}\VWIFIMP\7&79A56D7&0&03\Properties

Programatically in C

std::wstring GetAdapterDescription(std::wstring guid) {
  static       DWORD dwCtrlIdx = 0;
  LSTATUS      lStatus;
  DWORD        cbSize;
  std::wstring description = L"<unavailable>";
  wchar_t      path[1024], pnpInstance[1024], deviceDesc[1024];
  PWCHAR       pDesc;
  
  if (dwCtrlIdx == 0) {
    cbSize = sizeof(DWORD);
    lStatus = SHGetValue(HKEY_LOCAL_MACHINE, L"SYSTEM\\Select", 
        L"Default", 0, &dwCtrlIdx, &cbSize);
    if (lStatus != ERROR_SUCCESS) {
      dwCtrlIdx = 1;
    }
  }
  
  _snwprintf(path, sizeof(path) / sizeof(wchar_t), 
      L"SYSTEM\\ControlSet%03i\\Control\\Network\\"
      L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", 
      dwCtrlIdx, guid.c_str());

  cbSize = sizeof(pnpInstance) / sizeof(wchar_t);
  lStatus = SHGetValue(HKEY_LOCAL_MACHINE, path, L"PnpInstanceID", 
      0, pnpInstance, &cbSize);
  if (lStatus == ERROR_SUCCESS) {
    _snwprintf(path, 1024, L"SYSTEM\\ControlSet%03i\\Enum\\%s", 
        dwCtrlIdx, pnpInstance);
  
    cbSize = sizeof(deviceDesc) / sizeof(wchar_t);
    lStatus = SHGetValue(HKEY_LOCAL_MACHINE, path, L"DeviceDesc", 
        0, &deviceDesc, &cbSize);
    pDesc = wcsrchr(deviceDesc, L';');
    if (pDesc != 0) {
      description = ++pDesc;
    }
  }
  return description;
}

So there we have the description of adapter, and how to get profiles?

reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{012C8D7D-D104-47F8-83FE-B9751F699A2F}"

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{012C8D7D-D104-47F8-83FE-B9751F699A2F}
    PortType              REG_DWORD    0x2
    ProfileList           REG_MULTI_SZ    {AC1D44A3-9444-43E8-8496-E998433A5188}
    Parameters            REG_BINARY    0000000001000000010000000000000003000000
    Scan Interval         REG_BINARY    60EA0000
    Fail To Reset Time    REG_BINARY    60EA0000

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wlansvc\Interfaces\{012C8D7D-D104-47F8-83FE-B9751F699A2F}\Profiles

This profile list contains a string which corresponds to a file stored on disk with the profile.

dir C:\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces
    Volume in drive C has no label.
    Volume Serial Number is CFED-1E13

    Directory of C:\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces

    07/01/2017 02:25 PM .
    07/01/2017 02:25 PM ..
    09/30/2015 11:54 PM {012C8D7D-D104-47F8-83FE-B9751F699A2F}
    02/08/2015 10:31 AM {12487653-A815-4A9D-84E1-736D96554215}
    01/26/2016 12:13 AM {13ECC539-1C25-4036-9615-D85A5D1B47CE}
    04/15/2016 07:34 PM {295A80EE-8DC0-465F-ACF2-70DA1F036948}
    09/10/2015 07:50 PM {3306C2A4-E4A5-42B3-A087-67EB542F0EC0}
    04/15/2016 07:21 PM {40F69FB8-F23A-433E-94D9-D3983F220874}
    07/23/2013 06:54 PM {6E318579-A15B-43AA-BC85-5A38133888A6}
    07/01/2017 02:25 PM {AFEED710-CC5E-41BD-8975-E6EE0487B5C9}

Programming in C

void DumpWLANProfile(
  wchar_t adapterGuid[], 
  wchar_t profileGuid[]) 
{
  wchar_t                   path[MAX_PATH];
  wchar_t                   programData[MAX_PATH];
  HRESULT                   hr;
  CComPtr<IXMLDOMDocument2> pDoc;
  VARIANT_BOOL              bIsSuccessful;
  
  SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, 
      NULL, SHGFP_TYPE_CURRENT, programData);
      
  _snwprintf(path, MAX_PATH, 
    L"%s\\Microsoft\\Wlansvc\\Profiles\\Interfaces\\%s\\%s.xml", 
    programData, adapterGuid, profileGuid);

  hr = CoInitialize(NULL);
  if (FAILED(hr)) {
    wprintf(L"\nCoInitialize() failed : %08x", hr);
    return;
  }  
  
  hr = CoCreateInstance(CLSID_DOMDocument30, 
      NULL, CLSCTX_INPROC_SERVER,
      IID_IXMLDOMDocument2, (void**)&pDoc);
      
  if (SUCCEEDED(hr)) {    
    hr = pDoc->load(CComVariant(path), &bIsSuccessful);
    
    if (SUCCEEDED(hr) && bIsSuccessful)
    {
      profile_properties(pDoc, 0);
      profile_properties(pDoc, 1);
    } else {
      wprintf(L"\n  IXMLDOMDocument2->load() failed : %08x", hr);
    }
    pDoc = NULL;
  } else {
    wprintf(L"\n  CoCreateInstance() failed : %08x", hr);
  }
  CoUninitialize();
}

There are 2 different name space

// required to parse WLAN profiles
#define WLAN_NS   L"xmlns:s=\"http://www.microsoft.com/networking/WLAN/profile/v1\""
#define WLANAP_NS L"xmlns:s=\"http://www.microsoft.com/networking/WLANAP/profile/v1\""

void profile_properties(CComPtr<IXMLDOMDocument2> pDoc, DWORD idx)
{
  PWCHAR       xml[2]={WLAN_NS, WLANAP_NS};
  PWCHAR       profiles[2]={L"WLANProfile", L"WLANAPProfile"};
  HRESULT      hr;
  CComVariant  ns;
  PWCHAR       pt;
  std::wstring ssid, auth, enc, key;
  
  ns = xml[idx];
  pt = profiles[idx];
  hr = pDoc->setProperty(BSTR(L"SelectionNamespaces"), ns);

  if (SUCCEEDED(hr)) {    
    ssid = get_text(pDoc, pt, L"/s:SSIDConfig/s:SSID/s:name");
    auth = get_text(pDoc, pt, L"/s:MSM/s:security/s:authEncryption/s:authentication");
    enc  = get_text(pDoc, pt, L"/s:MSM/s:security/s:authEncryption/s:encryption");
    key  = get_text(pDoc, pt, L"/s:MSM/s:security/s:sharedKey/s:keyMaterial");
    
    if (!ssid.empty()) {
      wprintf(L"\n  %-20s  %-10s  %-20s", ssid.c_str(), auth.c_str(), enc.c_str());
    
      if (!key.empty()) {
        DecryptKey(key);
      }
    }
  } else {
    wprintf(L"\n  IXMLDOMDocument2->setProperty() failed : %08x", hr);
  }
  ns = NULL;
}

Demonstration

Source code

Requires MSVC with support for ATL to compile. See here.

Advertisements
This entry was posted in crypto api, networking, programming, security, windows, wireless. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s