Password Algorithms: Internet Explorer 10 (Windows Vault)

Introduction

Microsoft added a new feature to Windows 7 called ‘Vault’ which you can access through the Credential Manager in control panel or vaultcmd from command line. It works very similar to Gnome Key Ring on Linux or the Apple Keychain on Mac OS.

In versions 7, 8 and 9 of Internet Explorer, passwords were protected using DPAPI and the login URL as entropy before being saved in the registry. The new algorithm in IE10 continues to use DPAPI but the encryption of credentials is now handled by the Vault Service.

Vault System Service

Like most Windows Encryption, the protection of Vault data occurs within a LocalSystem service. vaultsvc.dll contains the service code and is loaded by the Local Security Account Subsystem (lsass.exe) at boot time.

Between 18-24 functions (depending on OS) are exposed to clients over a local RPC end point. On Windows 7 is an additional KeyRing Credential UI application (VaultSysUI.exe) launched by the service if it requires information from the owner of a vault.

For example, you have the ability to lock a vault with a password.
windows_7_lock
You can also configure a vault to require permission from the user when an application attempts to access the password element.
windows_7_prompt
In both situations, VaultSysUI will display a window to the user and then write the response back to heap memory which Vault Service can access. :-)

Although both these features are useful and add further protection to a user’s credentials, they were removed in Windows 8 along with other functionality.

Vault Client Library Access

From the user session, RPC calls are made through API exported by vaultcli.dll
Explorer.exe loads Credui.dll and Vault.dll when accessing the Credential Manager through the Control Panel.
credman
You can also use vaultcmd.exe to add/remove credentials but it doesn’t display passwords on either 7 or 8.
vaultcmd7
On Windows 8 . . .
vaultcmd8
For whatever reasons, there was a pretty significant reduction in Vault features between Windows 7 and 8. Below is a list of what was removed.

  • Creation / Deletion of vaults.
  • Loading / Unloading external vault files.
  • Locking / Unlocking vaults with additional password protection.

Protection Methods

Windows 7 has 2 methods available but Windows 8 only has 1.
DPAPI (Data Protection API) is used by default but on Windows 7, you can also use a password.

The algorithm used to protect passwords is RSA PBKDF2.

Recovery of Web Credentials

As said, there were some changes to Vault service between Windows 7 and 8.
VaultGetItem requires an additional parameter on Windows 8 and the VAULT_ITEM structure has an extra property. Here’s the structure for Windows 7

typedef struct _VAULT_ITEM_W7 {
  GUID SchemaId;
  LPCWSTR pszCredentialFriendlyName;
  PVAULT_ITEM_ELEMENT pResourceElement;
  PVAULT_ITEM_ELEMENT pIdentityElement;
  PVAULT_ITEM_ELEMENT pAuthenticatorElement;
  FILETIME LastModified;
  DWORD dwFlags;
  DWORD dwPropertiesCount;
  PVAULT_ITEM_ELEMENT pPropertyElements;
} VAULT_ITEM_W7, *PVAULT_ITEM_W7;

And for Windows 8 . . .

typedef struct _VAULT_ITEM_W8 {
  GUID SchemaId;
  LPCWSTR pszCredentialFriendlyName;
  PVAULT_ITEM_ELEMENT pResourceElement;
  PVAULT_ITEM_ELEMENT pIdentityElement;
  PVAULT_ITEM_ELEMENT pAuthenticatorElement;
  PVAULT_ITEM_ELEMENT pPackageSid;
  FILETIME LastModified;
  DWORD dwFlags;
  DWORD dwPropertiesCount;
  PVAULT_ITEM_ELEMENT pPropertyElements;
} VAULT_ITEM_W8, *PVAULT_ITEM_W8;

I’ve written a tool to recover IE10 passwords using the Vault API, here’s example of output on Windows 7 machine.
ie10_decode
For those of you that want to know more about recovery process, you can grab source and binary here.
Because the Windows Vault Service remains undocumented, I can’t guarantee the accuracy of information provided. The latest protection of Web Credentials for Internet Explorer is indeed weaker than previous algorithm for 7, 8 and 9 but the upside is that with the Vault you can reliably backup/restore your passwords when needed.

Below is just a list of API available/removed between Windows 7 and 8.

Credential Vault Client Library Function Windows 7 Windows 8
VaultCreateItemType Yes Yes
VaultDeleteItemType Yes Yes
VaultEnumerateItemTypes Yes Yes
VaultAddItem Yes Yes
VaultFindItems Yes Yes
VaultEnumerateItems Yes Yes
VaultGetItem Yes Yes
VaultRemoveItem Yes Yes
VaultGetItemType Yes Yes
VaultOpenVault Yes Yes
VaultCloseVault Yes Yes
VaultGetInformation Yes Yes
VaultEnumerateVaults Yes Yes
VaultSetInformation Yes No
VaultCreateVault Yes No
VaultCopyVault Yes No
VaultDeleteVault Yes No
VaultLoadVaults Yes No
VaultUnloadVaults Yes No
VaultCopyItem Yes No
VaultMoveItem Yes No
VaultLockVault Yes No
VaultUnlockVault Yes No
VaultConfirmVaultAccess Yes No
VaultEnumerateSettingUnits No Yes
VaultGetSettingUnit No Yes
VaultApplySettingUnit No Yes
VaultRemoveSettingUnit No Yes
VaultTriggerSync No Yes

TOR Setup – Windows

/*
This is part one of a multipart posting series that’s gonna go on all evening before el grande finale of using TOR and suchlike to bypass Fortinet Web Filters and other such bullshit censorship warez. The two TOR install posts will go up first, followed by the ranty bypassing one, then some other stuff :3

Please note, these installation guides are for non technical people in a sense, I literally try hold the users hand as much as possible…
*/

Well, if anyone here is as paranoid as I am, they probably wonder how the hell they can prevent their online activities from being traced back to them. So, in the interest of helping others anonymize their online presence, I have decided to knock up a few simple enough guides on installing and using various pieces of anonymity software, starting with the TOR bundle for Windows.

So. You should navigate yourself to torproject.org, and go to the downloads section.

Downloading TOR

Downloading TOR

Assuming you installed Firefox ages back (I hope to god ye arent using IE…) install the Vidalia bundle. Just download it, run the executable file, tick all the boxes (i.e. full install) and fire ahead. It will pop during the install.

Installing Vidalia Bundle

Installing Vidalia Bundle

Finally, let TOR run, and you should see the following after up to two minutes or so:

TOR works

TOR is now running

Bingo. That is TOR installed and running, and as you can see, it is VERY simple to use. To make it work with Firefox for anonymized browsing: Edit -> Preferences -> Advanced -> Network -> Settings -> Set proxy as: SOCKS5 (type), and 127.0.0.1 as IP and 9050 as port. I don’t think I can get much more simple than that.
 

Exploit Demo – FreeFloatFTPd Remote SYSTEM. Oppa Stuxnet Style!

Ever since Kingcope released the “Stuxnet Style” MySQL exploit using .mof files to execute dropped binaries, illness there has been a rash of similar exploits cropping up – and I fully expect many more to come. This one is one of the interesting ones, as it demonstrates something extremely interesting. How improper FTP file access privileges can lead to trivial remote code execution.

This exploit works in an extraordinarily simple manner. The FreeFloat FTP Server is rife with security flaws. Not least the fact it has no authentication whatsoever, and drops one right into C: with privileges to write files as the SYSTEM user.

It uploads the binary (Meterpreter in the MSF exploit) to System32, then plants a .MOF file to execute it in the System32wbemmof directory, allowing Windoes Management Interface to execute it as SYSTEM – the same as the other exploits.

Essentially, you pop a SYSTEM shell within less than a minute.

I expect that future weeks will show us more and more “Stuxnet Style” exploits as this technique becomes more trendy, hence, “Oppa Stuxnet Style!”.

Without further ado, here is the video!

 

Exploit Demo – Windows MySQL Post Auth RCE using Stuxnet Technique

My previous post demonstrated the exploit @kingcope released, MySQLJackPot, that leveraged FILE privileges to take over a Windows MySQL server. That exploit worked by abusing the User Defined Function stuff.

This exploit goes a bit further, and is reliable on everything pre-Vista. It leverages the same technique used by Stuxnet’s MS-10-061 exploit, wherin arbritary file creation is turned into Remote Code Execution (under the context of the SYSTEM user) by dropping a binary and a .MOF file.

By using the INTO DUMPFILE method (assuming we have FILE privs on the remote server), we can create arbritary files with the permissions of the MySQL user, which just so happens to be NT AUTHORITY/SYSTEM.

So, we drop a binary (our payload) in System32 folder, and then drop a crafted .MOF file in System32\wbem\mof\. The Windows Task Scheduler (similar to CRON on Unix to my understanding) periodically scans this directory and executes any .MOF files in there. Our .MOF file executes our payload.

This is the same method that the MS-10-061 exploits use – by dropping a .MOF file in there along with a binary, the binary will be executed in short order, and et-viola: got shell.

Anyways, without further ado, here is the video of it in action. I ended up using the Metasploit module, as I did something nasty to my PERL installation while installing stuff from CPAN for another demo, and things started to “not work right”.

Exploit Demo – Windows MySQL Remote System (Post Auth) RCE

So, search last weekend we got to see @kingcope release approximately a dozen new exploits, some scanners, and in general, a shitload of incredibly awesome code. Some serious headaches for systems administrators in general. Grab the exploits from

Now, over the past week in my free time (it is exam season for me, hence no updates in a while, but after next week its back to work :D ) I have been fooling about with these exploits. As usual, Kingcope delivered some quality stuff.

This exploit in particular is not quite “new” per se, it is a fascinating abuse of FILE privileges in MySQL. Unless I am mistaken, the SQLmap guys implemented this as well. However, I never had much luck at all with it. This, on the other hand, is an extremely reliable exploit.

How it works is rather simple. It creates a table in the target MySQL database (Spearhead), and uploads a DLL file as a binary blob into said table. It then uses “INTO DUMPFILE” to dump the payload out into the MySQL Plugin directory. The payload being a DLL file which contains code that spawns a reverse shell.

Finally, it creates a User Defined Function, “mysqljackpot”, which loads said DLL file and causes the reverse shell code to be executed under the context of the MySQL process, which is normally the SYSTEM user. It also drops the created databases to clear some evidence.

Very clever way of popping a box, however I do imagine it leaving a lot of logs behind… And I am investigating doing this via SQL injection at the moment (I can see no reason why not!).

Anyways, thats how this works! Here is the video!

 

Password Algorithms: Internet Explorer 7, 8, 9

Introduction

IE10 on Windows 8 uses a different algorithm for encryption and storage so I might follow up with separate entry later. For now I’m analysing version 9.0.9 on Windows 7.
Everything here should work fine with legacy IE 7 and 8.

Considering customers may avoid migrating to Windows 8, I thought this protection was still worth covering in detail.

Storage

All autocomplete entries for a user are stored in NTUSER.DAT and they consist of a SHA-1 hash and DPAPI blob. Here’s a dump of some hashes from my own system..

C:\>reg query "HKCU\Software\Microsoft\Internet Explorer\IntelliForms\Storage2"

HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\IntelliForms\Storage2
    6FBD22A243E7F5A0D660199683F52543E80CEB99EC    REG_BINARY    01000000D08C9DDF0115D1118. . .
    DF11F9BE8F0049A2FBFF29C6D49FE77383C2A6783A    REG_BINARY    01000000D08C9DDF0115D1118. . .
    E4CE6B2B79515319A7360D97E3B217F2FC843CC019    REG_BINARY    01000000D08C9DDF0115D1118. . .

The blobs have been truncated to avoid potential offline decryption.
Whenever IE connects to a site which requires login credentials, it will:

  1. Derive SHA-1 checksum of lowercase(URL).
  2. Search for the checksum in autocomplete entries.
  3. If checksum is found, decrypt DPAPI blob using URL and autofill the login fields.

Generation

Take the second hash..

DF11F9BE8F0049A2FBFF29C6D49FE77383C2A678 3A

This is a SHA-1 checksum of the unicode string “https://accounts.google.com/servicelogin”
The last byte 0x3A is a checksum based on addition of each byte in SHA-1 result.
The following function demonstrates this with Windows crypto API

bool GetUrlHash(std::wstring url, std::wstring &result) {

  HCRYPTPROV hProv;
  HCRYPTHASH hHash;
  
  bool bResult = false;
  
  std::transform(url.begin(), url.end(), url.begin(), ::tolower); 
  
  if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 
      CRYPT_VERIFYCONTEXT)) {
      
    if (CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash)) {
      if (CryptHashData(hHash, (PBYTE)url.c_str(), 
          url.length() * sizeof(wchar_t) + 2, 0)) {

        BYTE bHash[20];
        DWORD dwHashLen = sizeof(bHash);
        
        if ((bResult = CryptGetHashParam(hHash, HP_HASHVAL, bHash, 
            &dwHashLen, 0))) {
            
          BYTE chksum = 0;
          wchar_t ch[4];
          
          for (size_t i = 0;i < 20 + 1;i++) {
            BYTE x;
            
            if (i < 20) {
              x = bHash[i];
              chksum += x;
            } else {
              x = chksum;
            }
            wsprintf(ch, L"%02X", x);
            
            result.push_back(ch[0]);
            result.push_back(ch[1]);
          }
        }
      }
      CryptDestroyHash(hHash);      
    }
    CryptReleaseContext(hProv, 0);
  }
  return bResult;
}

Each username and password is stored in unicode format.
If there’s more than 1 set of credentials for the same URL, these will be added to the existing data.

The problem is that the actual structure for an entry is officially undocumented.
Fortunately, there’s an older revision of the structure online which helps a lot! :)

enum { MAX_STRINGS = 200 };   
enum { INDEX_SIGNATURE=0x4B434957 };
enum { INIT_BUF_SIZE=1024 };
enum { LIST_DATA_PASSWORD = 1 };

struct StringIndex {
  DWORD   dwSignature;
  DWORD   cbStringSize;   // up to not including first StringEntry
  DWORD   dwNumStrings;   // Num of StringEntry present
  INT64   iData;          // Extra data for string list user
  
  struct tagStringEntry {
    union
    {
      DWORD_PTR   dwStringPtr;    // When written to store
      LPWSTR      pwszString;     // When loaded in memory
    };
    FILETIME    ftLastSubmitted;
    DWORD       dwStringLen;        // Length of this string
  }
  StringEntry[];
};

Parsing a decrypted blob using this structure for reference caused a few headaches and required minor changes. In IEFrame.dll, CryptProtectData() is used with URL as entropy to encrypt StringIndex + credentials.

The next problem is discovering the original URL used as entropy and this is what makes IE password algorithm quite good..

Obtaining URLs

There are a number of ways to harvest URLs for the purpose of recovering IE7-IE9 passwords. The Cache normally has a list of websites visited which can be enumerated.
Here’s one such way using COM

void EnumCache1() {
  HRESULT hr = CoInitialize(NULL);
  
  if (SUCCEEDED(hr)) {
    IUrlHistoryStg2 *pHistory = NULL;
    hr = CoCreateInstance(CLSID_CUrlHistory, NULL, 
        CLSCTX_INPROC_SERVER, 
        IID_IUrlHistoryStg2,(void**)(&pHistory));
    
    if (SUCCEEDED(hr)) {
      IEnumSTATURL *pUrls = NULL;
      hr = pHistory->EnumUrls(&pUrls);
            
      if (SUCCEEDED(hr)) {
        while (TRUE) {
          STATURL st;
          ULONG result;
          
          hr = pUrls->Next(1, &st, &result);
          
          if (SUCCEEDED(hr) && result == 1) {
           
            AddUrl(st.pwcsUrl);
            
          } else {
            break;
          }
        }
        pUrls->Release();
      }
      pHistory->Release();
    }
    CoUninitialize();
  }  
}

And another using WININET API

void EnumCache2()   
{   
  HANDLE hEntry;   
  DWORD dwSize;
  BYTE buffer[8192];
  LPINTERNET_CACHE_ENTRY_INFO info = (LPINTERNET_CACHE_ENTRY_INFO) buffer;
  
  dwSize = 8192;
  hEntry = FindFirstUrlCacheEntry(NULL, info, &dwSize);
  
  if (hEntry != NULL) {
    do {
      if (info->CacheEntryType != COOKIE_CACHE_ENTRY) {
        AddUrl(info->lpszSourceUrlName);
      }
      dwSize = 8192;    
    } while (FindNextUrlCacheEntry(hEntry, info, &dwSize));   
    FindCloseUrlCache(hEntry);
  }
}

To take things a bit further, you could also parse index.dat files but I won’t go into that here since it’s in the realm of forensics.
A better approach is probably reading a list of URLs harvested from the internet.

Recovery

Recovery is close to how IE7-IE9 process decrypts entries except we’re forcing the decryption process using a list of URL.
The following collects a list of auto complete entries


#define MAX_URL_HASH 255
#define MAX_URL_DATA 8192

typedef struct _IE_STORAGE_ENTRY {
  std::wstring UrlHash;
  DWORD cbData;
  BYTE pbData[MAX_URL_DATA];
} IE_STORAGE_ENTRY, *PIE_STORAGE_ENTRY;

DWORD GetAutocompleteEntries() {

  HKEY hKey;
  DWORD dwResult;
  
  dwResult = RegOpenKeyEx(HKEY_CURRENT_USER, 
      L"Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2",
      0, KEY_QUERY_VALUE, &hKey);
  
  if (dwResult == ERROR_SUCCESS) {
    DWORD dwIndex = 0;
    
    while (TRUE) {
      IE_STORAGE_ENTRY entry;
      
      DWORD cbUrl = MAX_URL_HASH;
      wchar_t UrlHash[MAX_URL_HASH];
      
      entry.cbData = MAX_URL_DATA;
      
      dwResult = RegEnumValue(hKey, dwIndex, UrlHash, &cbUrl, 
          NULL, 0, entry.pbData, &entry.cbData);
      
      if (dwResult == ERROR_SUCCESS) {
        entry.UrlHash = UrlHash;
        ac_entries.push_back(entry);
      } else if (dwResult == ERROR_NO_MORE_ITEMS) {
        break;
      }
      dwIndex++;
    }
    RegCloseKey(hKey);
  }  
  return ac_entries.size();
}

Now with list of URL strings and autocomplete entries, we can attempt to decrypt using CryptUnprotectData() The decrypted data is then parsed based on the StringIndex structure.

void ParseBlob(PBYTE pInfo, const wchar_t *url) {
  
  StringIndex* pBlob = (StringIndex*)pInfo;

  // get offset of data
  PBYTE pse = (PBYTE)&pInfo[pBlob->cbHdrSize + pBlob->cbStringSize1];
  
  // process 2 entries for each login
  for (DWORD i = 0;i < pBlob->dwNumStrings;i += 2) {
  
    // get username and password
    wchar_t *username = (wchar_t*)&pse[pBlob->StringEntry[i + 0].dwStringPtr];
    wchar_t *password = (wchar_t*)&pse[pBlob->StringEntry[i + 1].dwStringPtr];
    
    bool bTime;
    wchar_t last_logon[MAX_PATH];
    
    if (lstrlen(password) > 0) {
      // get last time this was used
      FILETIME ft;
      SYSTEMTIME st;

      FileTimeToLocalFileTime(&pBlob->StringEntry[i].ftLastSubmitted, &ft);
      FileTimeToSystemTime(&ft, &st);

      bTime = (GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &st, L"MM/dd/yyyy", last_logon, MAX_PATH) > 0);
    } else {
      bTime = false;
    }
    wprintf(L"\n%-30s  %-20s  %-15s %s", username, password, bTime ? last_logon : L"NEVER", url);
  }
}

Conclusion

Because the URL is used as entropy, that can be problemtatic recovering all autocomplete entries.
It would be simple to recover credentials of popular services like Facebook, Gmail, Instagram, Hotmail..etc but the less well known services would be problem unless URL was stored in cache.