Thursday, June 20, 2013

How Browsers Store Your Passwords (and Why You Shouldn't Let Them)

Introduction

In a previous post, I introduced a Twitter bot called dumpmon which monitors paste sites for account dumps, configuration files, and other information. Since then, I've been monitoring the information that is detected. While you can expect a follow-up post with more dumpmon-filled data soon, this post is about how browsers store passwords.

I mention dumpmon because I have started to run across quite a few pastes like this that appear to be credential logs from malware on infected computers. It got me thinking - I've always considered it best to not have browsers store passwords directly, but why? How easy can it be for malware to pull these passwords off of infected computers? Since sources are a bit tough to find in one place, I've decided to post the results here, as well as show some simple code to extract passwords from each browser's password manager.The Browsers

For this post, I'll be analyzing the following browsers on a Windows 8 machine. Here's a table of contents for this post to help you skip to whatever browser you're interested in:

Let's start with Chrome. Disappointingly, I found Chrome to be the easiest browser to extract passwords from. The encrypted passwords are stored in a sqlite database located at "%APPDATA%\..\Local\Google\Chrome\User Data\Default\Login Data". But how do they get there? And how is it encrypted? I got a majority of information about how passwords are stored in Chrome from this article written over 4 years ago. Since a bit has changed since then, I'll follow the same steps to show you how passwords are handled using snippets from the current Chromium source (or you just skip straight to the decryption).

Encryption and Storing Passwords
When you attempt to log into a website, Chrome first checks to see if it was a successful login:

We can see that if it's a successful login, and you used a new set of credentials that the browser didn't generate, Chrome will display a bar asking if you want your password to be remembered:

To save space, I'm omitting the code that creates the Save Password bar. However, if we click "Save password", the Accept function is called, which in turn calls the "Save" function of Chrome's password manager:

Easy enough. If it's a new login, we need to save it as such:

Again to save space, I've snipped a bit out of this (a check is performed to see if the credentials go to a Google website, etc.). After this function is called, a task is scheduled to perform the AddLoginImpl() function. This is to help keep the UI snappy:

This function attempts to call the AddLogin() function of the login database object, checking to see if it was successful. Here's the function (we're about to see how passwords are stored, I promise!):

Now we're getting somewhere. We create an encrypted string out of our password. I've snipped it out, but below the "sql::Statement" line, a SQL query is performed to store the encrypted data in the Login Data file. The EncryptedString function simply calls the EncryptString16 function on an Encryptor object (this just calls the following function below):

Finally! We can finally see that the password given is encrypted using a call to the Windows API function CryptProtectData. This means that the password is likely to only be recovered by a user with the same logon credential that encrypted the data. This is no problem, since malware is usually executed within the context of a user.

Decrypting the Passwords
Before talking about how to decrypt the passwords stored above, let's first take a look at the Login Data file using a sqlite browser.

Our goal will be to extract the action_url, username_value, and password_value (binary, so the SQLite browser can't display it) fields from this database. To decrypt the password, all we'll need to do is make a call to the Windows API CryptUnprotectData function. Fortunately for us, Python has a great library for making Windows API calls called pywin32.

Let's look at the PoC:

And, by running the code, we see we are successful!

While it was a bit involved to find out how the passwords are stored (other dynamic methods could be used, but I figured showing the code would be most thorough), we can see that not much effort was needed to actually decrypt the passwords. The only data that is protected is the password field, and that's only in the context of the current user.Internet ExplorerDifficulty to obtain passwords:Easy/Medium/Hard (Depends on version)
Up until IE10, Internet Explorer's password manager used essentially the same technology as Chrome's, but with some interesting twists. For the sake of completeness, we'll briefly discuss where passwords are stored in IE7-IE9, then we'll discuss the change made in IE10.

Internet Explorer 7-9

In previous versions of Internet Explorer, passwords were stored in two different places, depending on the type of password.

For the sake of this post, we'll discuss credentials from form-based authentication, since these are what an average attacker will likely target. These credentials are stored in the following registry key:

Looking at the values using regedit, we see something similar to the following:

As was the case with Chrome, these credentials are stored using Windows API function CryptProtectData. The difference here is that additional entropy is provided to the function. This entropy, also the registry key, is the SHA1 checksum of the URL (in unicode) of the site for which the credentials are used.

This is beneficial because when a user visits a website IE can quickly determine if credentials are stored for it by hashing the URL, and then using that hash to decrypt the credentials. However, if an attacker doesn't know the URL used, they will have a much harder time decrypting the credentials.

Attackers will often be able to mitigate this protection by simply iterating through a user's Internet history, hashing each URL, and then checking to see if any credentials have been stored for it.

While I won't paste the entire code here, you can find a great example of a full PoC here. For now, let's move on to IE10.

Internet Explorer 10Note: Please refer to the comment below by Amy Adams regarding the fact that Windows Store Apps cannot access stored credentials in the way described above. However, this method is still relevant for applications running in the context of the user.

IE10 changed the way it stores passwords. Now, all autocomplete passwords are stored in the Credential Manager in a location called the "Web Credentials". It looks something like the following:

To my knowledge (I wasn't able to find much information on this), these credential files are stored in %APPDATA%\Local\Microsoft\Vault\[random]. A reference to what these files are, and the format used could be found here.

What I do know is that it wasn't hard to obtain these passwords. In fact, it was extremely easy. Microsoft recently provided a new Windows runtime for more API access. This runtime provides access to a Windows.Security.Credentials namespace which provides all the functionality we need to enumerate the user's credentials.

In fact, here is a short PoC C# snippet which, when executed in the context of a user, will retrieve all the stored passwords:

When executing the program, the output will be similar to this:

Note: I removed some sites that I believe came from me telling IE not to record. Other than that, I'm not sure how they got there.
As you can see, it was pretty trivial to extract all the passwords in use from a given user, as long as our program is executing in the context of the user. Moving right along!FirefoxDifficulty to obtain passwords:Medium/Very Hard
Next let's take a look at Firefox, which was tricky. I primarily used these slides (among a multitude of other resources) to find information about where user data is stored.

But first, a little about the crypto behind Firefox's password manager. Mozilla developed a open-source set of libraries called "Network Security Services", or NSS, to provide developers with the ability to create applications that meet a wide variety of security standards. Firefox makes use of an API in this library called the "Secret Decoder Ring", or SDR, to facilitate the encryption and decryption of account credentials. While it may have a "cutesy name", let's see how it's used by Firefox to provide competitive crypto:

When a Firefox profile is first created, a random key called an SDR key and a salt are created and stored in a file called "key3.db". This key and salt are used in the 3DES (DES-EDE-CBC) algorithm to encrypt all usernames and passwords. These encrypted values are then base64-encoded, and stored in a sqlite database called signons.sqlite. Both the "signons.sqlite" and "key3.db" files are located at %APPDATA%/Mozilla/Firefox/Profiles/[random_profile].

So what we need to do is to get the SDR key. As explained here, this key is held in a container called a PKCS#11 software "token". This token is encapsulated inside of a PKCS#11 "slot". Therefore, to decrypt the account credentials, we need to access this slot.

But there's a catch. This SDR key itself is encrypted using the 3DES (DES-EDE-CBC) algorithm. The key to decrypt this value is the hash of what Mozilla calls a "Master Password", paired with another value found in the key3.db file called the "global salt".

Firefox users are able to set a Master Password in the browser's settings. The problem is that many users likely don't know about this feature. As we can see, the entire integrity of a user's account credentials hinges on the complexity of chosen password that's tucked away in the security settings, since this is the only value not known to the attacker. However, it can also been that if a user picks a strong Master Password, it is unlikely that an attacker will be able to recover the stored credentials.

Here's the thing - if a user doesn't set a Master Password, a null one ("") is used. This means that an attacker could extract the global salt, hash it with "", use that to decrypt the SDR key, and then use that to compromise the user's credentials.

Let's see what this might look like:

To get a better picture of what's happening, let's briefly go to the source. The primary function responsible for doing credential decryption is called PK11SDR_Decrypt. While I won't put the whole function here, the following functions are called, respectively:

ffpasscracker - I promised you Python, so here's a solution. This uses the libnss.so library as a loaded DLL. To use this on Windows, you can use these cygwin DLL's.

Conclusion

I hope this post has helped clarify how browsers store your passwords, and why in some cases you shouldn't let them. However, it would be unfair to end the post saying that browsers are completely unreliable at storing passwords. For example, in the case of Firefox, if a strong Master Password is chosen, account details are very unlikely to be harvested.

But, if you would like an alternative password manager, LastPass, KeePass, etc. are all great suggestions. You could also implement two-factor authentication using a device such as a YubiKey.

As always, please don't hesitate to let me know if you have any questions or suggestions in the comments below.

You say: "the password given is encrypted using a call to the Windows API function CryptProtectData. This means that the password is likely to only be recovered by a user with the same logon credential that encrypted the data. This is no problem, since malware is usually executed within the context of a user."

While that's true, malware running on the machine can also just log the users credentials (e.g. keylogger) or see the protected data. I don't think it's possible to create a password-storage system that's not vulnerable to local malware.

It seems like Chrome does the Right Thing in using a system-standard library to protect credentials in a way that requires some kind of local access (via malware/etc.) to decrypt.

You make a great point, and I appreciate the comment! It is important to note that these credentials are likely to not be recovered if the malware does not have some kind of local access. The goal of this post was to kind of show what "defense-in-depth" strategies browsers use for protecting these credentials.

For example, consider how IE7-9 protects the data. It puts an interesting twist on the standard API call by using the hash of the website as added entropy. While this certainly isn't perfect (especially if the user does not clear his/her history), it's still one more layer of defense.

Or we can consider Firefox, who allows the user to set a Master Password that must be known (and to my knowledge not stored) for decryption. This also provides another layer of defense.

I hope this helps. You are right in saying that it might be very difficult to protect data against local malware. In Chrome's case, I simply wish they had had a more layered approach. Doesn't mean I'll stop using it as my browser, though :D

I'm not so sure it really helps all that much unless the attacker is just looking for "passwords" as a whole, rather than specific passwords. If I'm a malware author, it's not *that* hard to check out a few major financial institutions or whatever else I'm targeting and determine the main URL for their login page, then just look for the relevant hash in the registry. Many modern web sites have a standard "http://domain.tld/login" or similar which they redirect users through no matter where they're coming from, so for any targeted attack this added about as much as ROT13.

Again though assuming the user clears their history it is pretty decent against someone just looking for any passwords at all.

I also don't think that the other browsers have a much higher security level. You have to have control over you system. When this is not the case the security mechanisms would not help you much.You also can have a vault with a master key for the passwords. But when the key for the vault is in another vault and the key for the second vault is on the system, this would not help you much, even if it looks like great security features.The key is that no one has access to your system. If this is the case, then the security of chrome is good.If anyone has access to your system, then nothing can help you, as the atacker can even get access to the master key for firefox, by just changing some files of firefox.

Why would I have any expectation that my saved passwords would be secure if you had access to my system? If you are getting me to run an arbitrary binary with my user's permissions, haven't you already pwned my account and possibly my box? This smells like a case of "it rather involved being on the other side of this airtight hatchway"

Chrome's password strategy is basically "your passwords are exactly as secure as your OS". On all platforms, Chrome tries to use the system keyring -- CryptUnprotectedData, KWallet, Gnome Wallet, Keychain, etc. -- and not do anything else. Chrome's security model is to protect you from getting malware on your machine in the first place, rather than to try to mitigate damage from malware introduced via other vectors.

While the defense-in-depth you discuss here is certainly valid, in the end, if someone has arbitrary code executing on your computer with your user credentials, you're hosed no matter what.

I don't think this thought approach is any good. Various data need various levels of protection. So although it's true that compromised computer is compromised ;) and the attacker could do whatever he wants, the added level of protection of something as valuable as passwords (as Firefox does) is important and could lengthen the window between compromise and successful data theft, in which the compromise may be detected. (You can break my house's windows, but the valuables are in safe).

Basically there is almost no difference between saving data in plaintext and the Chrome method (in case of local user account compromise).

I believe the only protection encryption can give you in this case is preventing decryption in the event the files are stolen because of a misconfigured share or P2P program. Which all browsers seem to be doing correctly.

Firefox is also trying to protect the file in case of a compromise, but it'll only work as long as the user detects the infection before actually typing the master password. So while it does add an extra layer of security, I can see why both Chrome and IE don't do this - the extra effort only protects you in a very limited scenario, and it can be damaging to the user experience.

The IE trick is by far the most imaginative, it also only adds very little extra protection but it doesn't really cost anything from the development standpoint, and it also doesn't change the user experience at all since it's completely transparent.

Jordan: Windows Store Applications cannot access IE or any other Windows Store Application credentials saved in the Credential Locker. More detail on this is described here: http://blogs.msdn.com/b/windowsappdev/archive/2013/05/30/credential-locker-your-solution-for-handling-usernames-and-passwords-in-your-windows-store-app.aspx

It would be good to remove the statement in your article about this as its not entirely correct and will cause some confusion. The code you wrote for the IE10 example wouldn't work in a Windows Store Application. However it can work as medium privileged application that a user would have to install on the machine (e.g. like an executable).

On OS X and Linux, we have keychain managers that put the onus of protecting password storage on the principle of least privilege. The idea is that privilege escalation is required to interact with the APIs to retrieve information stored within the keychain. A user would have to explicitly allow local malware to access the keychain when it requests permission.

An interest side-channel lies in extensions for a browser which already has permission to interact with the keychain; A well-designed extension system will have its own sandbox with access control levels, requiring a privilege "audit" step during installation to explicitly allow the privileges the add-on is requesting access. Chrome and Firefox handles it pretty well, as do Facebook apps, Android apps, iOS apps, etc. If you ever see "This app can access your passwords", that's an immediate red-flag.

Couldn't a hacker simply create a program that opens the browser, goes to the site they want to hack, then copy out the data remembered in the form fields? Not only would it just require some simple JS, it would be much easier than going into the actual data itself and copying out and decrypting from local files.

Even so, I trust that with some good antivirus and basic computer knowledge that won't happen.

But locally stored passwords have never been highest concern. Like posted above, if malware is running already nothing is save anymore.

I would be more interessted in the syncronization feature.I know from Firefox a public/private key method, not very user friendly but on the first look professional.In Chrome it seems to be the "google account token" to enable sync between devices.

As you where already diving in source code, is there anything special/interessting in that?

Did you by chance have a look at how well the master password is protected in Firefox's memory? A trojan (or a shoulder surfer who found his colleague's PC unlocked) should not have a hard time installing a Firefox addon. And since Firefox does not need to restart for installing and uninstalling most addons, if the master password is accessible via the extension API, it might be stolen that way without restarting Firefox at all.

Yes, I am aware that Firefox can show you a list of all stored passwords if you have already entered the master password, but you cannot copy them and trying to screenshot it in parts may be a bit harder than just copying the master password and the password db might be a lot faster if the user has stored a lot of unmemorizable passwords in his password safe.

This is helpful, however, it doesn't seem like you considered Chrome with the Sync Passphrase in effect. Also, you recommend password managers, but most people will use those with the 'remember me' option checked--so I'm wondering if Chrome is actually a better option in those cases.

Here's a security.stackexchange question I'm trying to get an authoritative answer on: http://security.stackexchange.com/q/40884/25338

Hey, saw your article and it was really helpful in understanding how the passwords are stored. I did notice though that there is no link when you mention "To use this on Windows, you can use these cygwin DLL's." when talking about ffpasscracker. Also, my attempts at converting this to Windows as a personal experiment with the necessary dll files have resulted in "WindowsError: Exception: access violation writing 0x00000000 when any libnss calls are done. Would you know offhand what could cause such errors or should I guide this question to the creator of that proof of concept?

I created a malicious browser extension for Firefox 2 years ago, it was able to grab the passwords protected by the master password - just after the user unlocked it. The code to steal it was super easy. https://github.com/Z6543/ZombieBrowserPack/blob/master/full/client/firefox/chrome/content/browserOverlay.js