I am back from Amsterdam after presenting our research at Blackhat “Even the LastPass Will be Stolen, Deal with It!” together with Alberto Garcia. We had a blast at the conference and we got great feedback from the audience. Many asked for the video, slides, etc. so I though it was worth writing a post with all the details of our talk.

Motivation

During one of Alberto’s red team pentests, he gained access to several machines and found that all of them had files with references to LastPass. He came to me and told me it would be cool to check how LastPass works and if it was possible to steal LastPass credentials. 10% of our time is for research so we made that our small project.

We found how creds where stored locally and wrote a Metasploit plugin so he could use it to extract vault contents from all the compromised machines. Thanks to the module, he was able to obtain SSH keys to critical servers and the pentest was a success.

I blogged about it in the past and it became very popular on reddit. We got a lot of feedback, questions, comments and suggestions. It was clear that the security community really cared about LastPass’ security so we though it was worth spending more time on it and do a proper research.

Focus

We looked at what was done already and we found previous research on password managers using DNS poisoning and iframes as well as attack vectors through XSS to steal specific credentials.

We decided that our focus would be to find ways to attack the vault directly and get access to all the content instead of leaking specific secrets. We wanted to do so in all 3 different scenarios:

Client side attacks : A post-exploitation scenario in which an attacker has certain access to the victim’s machine (no root access needed)

: A post-exploitation scenario in which an attacker has certain access to the victim’s machine (no root access needed) LastPass side attacks : A scenario in which LastPass employees, attackers compromising their servers, or anyone MiTMing the connection is the attacker

: A scenario in which LastPass employees, attackers compromising their servers, or anyone MiTMing the connection is the attacker Attacks from the outside: Attackers that are not on the client nor on LastPass servers side.

Client side attacks

The goal here was to reverse engineer the browser plugins, analyze all the files stored in the system and see if we could obtain the key that decrypts the vault (vault key from now on).

We found different methods to do so:

Cleartext password recovery

As explained in my previous post

But what about if “Remember Password” was not clicked?

Using cookies

Our first shot was simply to look at using cookies to obtain the vault key. While this sounds straightforward, because of how LastPass is designed, the cookies will only get you what LastPass stores in their servers, and as you may guess, it does not include the vault key.

We found that the vault key is actually stored locally encrypted. Where is the decryption key to decrypt the vault key? LastPass has the seed from where we can derive it.

As shown in the flow chart, we can use the session cookie to query LastPass and obtain the pwdeckey value. Once we have that, we can derive a key by doing SHA256(pwdeckey). Now we just need to extract the encrypted vault key from the SQLite DB and decrypt it using the key we just derived.

But what about if 2-Factor Authentication is enabled?

Bypassing 2 factor authentication

2FA is an additional layer of security for your account. It prevents access to your vault even if an attacker has your credentials. Authentication should be based on something you know, something you have and/or something you are. In this case, your master password is something you know, and 2FA is something you have (in form of a device, token, etc.)

LastPass supports a big variety of 2FA mechanisms including Google Authenticator, Yubikey, Toopher, etc. If you read my previous post, you already know how to steal the master password but if the victim has 2FA activated, you still won’t be able to login. Let’s take care of that now.

The first approach was to start Burp and look at the login requests coming from a trusted browser. We were expecting to see a “trust cookie” set by LastPass but there was not such thing. We tampered with the request parameters trying to identify which one was related to 2FA and removed one by one till we were prompted again for the 2FA code. The parameter that was making the difference was uuid.

UUID is a 32 character random string that can contain following chars: 0-9 A-Z a-z !@#$%^&*()_ It is used as the trust token and sent in every request. LastPass will compare this value server side and validate the request if the token is part of the list of trusted devices. It is generated at plugin installation time and it is stored on the machine in the browser’s local-storage.

Design problems

LastPass should have sticked to the common implementation of 2FA and use trust cookies. There are many things wrong with LastPass’ current implementation which has bad consequences:

Browsers don’t encrypt local-storage . This makes the token accessible without needing root. Cookie values do get encrypted by some browsers

. This makes the token accessible without needing root. Cookie values do get encrypted by some browsers The 2FA token is stored in plaintext

The token is injected into the DOM. An XSS would allow an attacker to steal 2FA tokens

An XSS would allow an attacker to steal 2FA tokens Same token is used for all browser users. You share the same 2FA token with other LastPass browser users

You share the same 2FA token with other LastPass browser users Token does never change. Untrusting the browser has no real effect neither does generating a new QR code

Untrusting the browser has no real effect neither does generating a new QR code Token fixation. An attacker can set a known token that will be used when 2FA is activated

An attacker can set a known token that will be used when 2FA is activated Proactive token stealing. An attacker can steal the token before 2FA was ever activated, and keep it for later use when the victim activates 2FA

But what about if there is no valid session cookie?

Abusing account recovery to obtain the encryption key

Even though we found several ways to obtain vault keys, we still had the problem that if the user was not logged in or there was no valid session cookie stored, we would not be able to query LastPass for the seed to derive the key. Another limitation was if there are multiple LastPass accounts, at best we only would be able to obtain the vault key from the account currently active (as the others would be missing the session cookie).

We wanted the silver bullet. A way in which we would be able to steal all secrets from an out-of-the-box, clean, LastPass installation. No matter if there was no valid session cookies, no matter if the user did not click “Remember Password” and no matter if there was 2FA.

We started to look at other LastPass features till we found “Account recovery”. It is a functionality that LastPass provides that allows users to recover their vaults if they forgot the master password. I know, I know… how is it possible to decrypt the vault if you don’t know the master password? After all, the decryption key is derived from the master password. We had the same thought when we stumbled upon this functionality and we wanted to understand how it worked.

The process

In order to recover/decrypt your vault if you happened to forget the master password, you’d need to visit the Recover Account site, provide your email and initiate the recovery. You will instantly get an email from LastPass with a unique link. When you click that link, it will take you to a page with a big button labeled “Press to recover account”. If you do that, you will see your entire vault decrypted without having ever provided your master password and bypassing 2FA.

What happens in the background?

When you click on the link in the email, you are redirected to a URL similar to /recover.php?&time=1412381291&timehash=340908c353c099c9FAKE6b387002c5a4881ebdf1&username=test%40test.com&usernamehash=fc7be7e5f6cbec9FAKE2995bd3331c097

This URL contains 4 parameters:

time : The timestamp from the moment you started the account recovery

: The timestamp from the moment you started the account recovery timehash : A salted SHA1 hash of the time-stamp

: A salted SHA1 hash of the time-stamp username : The LastPass username

: The LastPass username usernamehash: A salted SHA1 hash of the username

We wanted to see if we were able to generate this URL ourselves, for any victim. That way, there would be no need to have access to the victim’s email in order to steal the unique URL. There are 2 challenges; we need the exact timestamp and we need the salt to be able to hash the timestamp and username correctly.

Because we don’t have the salt, we got the valid URL for our own user (I initiated the account recovery myself) and we reused the timestamp and timestamp hash in the victim’s URL. It worked!

That tells us couple things:

Same salt is used for all users

Link does not truly expire, only the timestamp is validated against the hash

There is no need to initiate the account recovery, you only need a valid link

But we were still not able to generate a valid username hash because we did not know the salt. So, we moved on to the next part of the account recovery process.

Clicking the recovery button

If you click on the button, a POST request is made to LastPass with a URL like this one: /otp.php&hash=ccb2501724FAKE2b575a214e1052d0fa27b0726b6HASHdb2e1da3952e

In this case, there is only one parameter: hash. This parameter is a derived “disabled One Time Password”. Yes, LastPass has 2 types of OTPs: true OTPs (the ones you can use only once and are useful to login from untrusted machines) and disabled OTPs which are used for account recovery.

The disabled OTP (dOTP from now on) is set in your machine by default. This is key to understand the advantage of this attack versus stealing the master password which needs the victim to have previously clicked “Remember Password”.

As you can see in the illustration above, the plugin gets the dOTP from local storage. It then applies a SHA256 to the username plus the binary version of the dOTP. It does it again and that gives you the value for the hash parameter mentioned above.

Now, you can make the request directly with the correct parameter value and you will get the session cookie back together with the randkey.

What is randkey?

We don’t have yet the vault key. randkey is the vault key encrypted. That is what LastPass sends us back when we use the dOTP to authenticate. We just need to decrypt the vault key. And how do we do that? The vault key is encrypted using AES256 in CBC mode which key is derived from the dOTP as well. Specifically, the key is SHA256(dOTP).

What is dOTP again?

Think about it. dOTP is a master password on steroids:

You can use it to authenticate

You can use it to obtain the the vault key encrypted

You can use it to decrypt the vault key

It bypasses IP restrictions

It bypasses 2FA

It is stored locally by default

Metasploit module

We wanted to help pentesters with our research so we wrote a post-exploitation module in order to automate everything I just told you. You may have already used the one I wrote to steal the credentials so I simply updated it to add support to steal 2FA tokens, use cookies and dOTPs to derive vault keys, loot the vault for decryption and print out all the secrets stored in the vault. Now you get it all!

You can find the updated module in my github repo. I will make a pull request soon to the official repository so the next time you update Metasploit, the module will be doing much more for you.

LastPass side attacks

Because there was a breach in LastPass servers back in June, and also because LastPass claims that they have no access to your data, we wanted to investigate what could be done if we have the same data as LastPass. Specifically, we wanted to know if it is possible to decrypt vaults if you are LastPass, anyone with access to their servers, or the NSA pushing LastPass to allow access to their DBs.

LastPass claims that they have no way to decrypt your data, the hackers that breached into their servers just dumped their data to perform difficult-to-succeed offline attacks and NSA should not be able to do anything either against 100k rounds of PBKDF2.

Before we continue let me be clear, I am not saying, implying or suggesting that LastPass performs any of the attacks explained below. They do not, and when I put LastPass as the attacker is only for readability purposes. What I mean is a possible delinquent LastPass employee, a hacker compromising their servers, or a government putting pressure on them.

Let’s get paranoid!

What does LastPass actually see?

No PBKDF2 protection for the encryption key

When we look at the data shared with LastPass, we see that in order to authenticate, an “authentication hash” is created by performing a 1-round PBKDF2 of the vault key. PBKDF2 is used to derive the vault key from your credentials and supposedly to store the authentication hash in LastPass servers but the truth is that LastPass does not protect your encryption key with PBKDF2 from them. Don’t get me wrong, bruteforcing 256 bit is still very hard.



No real 256-bit protection with OTPs

LastPass also stores several versions of your vault key encrypted. One of them we already saw when I previously explained authentication with dOTPs. A dOTP is 32 chars so we have 256 bit protection. But if you use regular OTPs, LastPass will have a copy of your vault key encrypted as follows:

SHA256( SHA256(username+OTP) + OTP)

where OTP are 16 random bytes. Given that the username is known, and that there is no PBKDF2 used to derive the key, anyone on LastPass side would have to bruteforce only the OTP (128 bits) rather than 256. Again, don’t get me wrong, bruteforcing 128 bits is also hard (as of today) but much easier than 256.

The “encrypted” vault

The picture above is a screenshot of a encrypted vault. It probably does not look as encrypted as you would expect. Turns out, the vault is not an encrypted chunk of data, it is cleartext metadata with some encrypted values:

URLs/Icons are encoded, not encrypted : This means that there is no privacy . If you like shady pr0n or you are registered in questionable forums, anyone looking at your encrypted vault will know it. Also, if you reset your password in some site and update the LastPass vault account when prompted for it, the unique reset password URL may be stored as well . If the webmaster did not a good job of expiring the unique link, you gave LastPass the link to reset your password again.

: This means that . If you like shady pr0n or you are registered in questionable forums, anyone looking at your encrypted vault will know it. Also, if you reset your password in some site and update the LastPass vault account when prompted for it, . If the webmaster did not a good job of expiring the unique link, you gave LastPass the link to reset your password again. Credentials often encrypted with ECB mode: ECB is a weak encryption method that should never be used. LastPass will know if you are reusing passwords from looking at the cipher text. This is bad because LastPass can go check any of the existing password dumps out there, see if you are registered in one of the hacked sites (remember, URLs are not encrypted) and find your cleartext password. Because in ECB mode same plain text results in same cipher text, if you happen to have used the same password in any other account in the vault, they will know that by comparing cipher texts. And because they have the plaintext password, they will be able to access the other accounts as well.

The real threat, custom_js

While everything mentioned above is worrisome, we did not yet achieve our goal of finding a way to steal the all the secrets in the vault. While tampering with LastPass APIs, we came across a request that was returning a XML version of the encrypted vault. Thanks to this, we found a very interesting parameter called “custom_js” that was part of every Account node

What is custom_js for?

Turns out, LastPass is not always able to find the input nodes in the DOM to inject the credentials in login pages. This can happen because webmasters create flash sites or fancy login screens without a form or submit button. LastPass solves this problem by injecting Javascript payloads to the accounts where it is not able to infer where to inject the credentials.

What I am saying is that LastPass adds Javascript payloads to your encrypted vault in cleartext. Javascript code that will be injected and run in every page load in the domain’s context. While this is a legitimate feature, it gives LastPass the possibility of stealing all your credentials.

As you can see, the payload added to your encrypted vault on LastPass side is processed by the browser plugin and simply injected in the DOM. There is no validation happening on the client side. Also, the payload runs on every page load, not just in the login page.

The best part is actually that the LastPass plugin declares two variables that contain the cleartext credentials for the current site, lpcurruser and lpcurrpass making it even easier to steal them.

What happens if LastPass wants to steal data from a site that you did not store an account for in the vault? Not a problem! The vault is not a chunk of encrypted data but metadata with some values encrypted. LastPass can add new accounts to your encrypted vault with the desirable payload to steal session cookies, data, etc. as illustrated in the image below.

Attacks from the outside

Firefox operates differently than the rest of the browsers (I won’t get into too much detail, watch the talk when it becomes available). Specifically, Firefox does not use Sqlite DBs for storage. Instead, it stores data in a number of different files. The file that contains the encrypted LastPass credentials is prefs.js. This file is where many Firefox settings and configurations are stored, including the credentials.

As you can see, the credentials are stored as follows:

extensions.lastpass.loginusers : Contains the list of usernames

: Contains the list of usernames extensions.lastpass.loginpws: Contains the encrypted credentials

Google dorks

With this is mind, we though about what would happen if we google “extensions.lastpass.loginpws”. You guessed it! People are sharing their encrypted LastPass credentials with the rest of the world without their knowledge. You can also find credentials in pastebin. The best part is that now you know how to decrypt them and everything you need is right there.

The problem here is that people are posting their prefs.js in forums looking for help on broken Firefox configurations, removing spyware, toolbars, etc. but are unaware that at the same time they are exposing their LastPass credentials including the seed to derive the decryption key. We have also seen file dumps on antivirus/antispyware sites and forums.

Some results cannot be decrypted because users were lucky to be using the binary version of the plugin on Windows. This means that the credentials are encrypted using Data Protection API and cannot be decrypted outside the machine. Our intention is not to expose people, only to make a point. This example should be good enough to illustrate the case. We told LastPass about it so they could reach out to the affected users and also remove links from search engines.

Recommendations

For you

Use the binary version of the plugin

Do not store the master password

Activate the new Account Recovery over SMS

Audit your vault for malicious JS payloads

Don’t use “password reminder”

Activate 2FA

Add country restrictions

Disallow TOR logins

For LastPass

Get rid of custom_js!

Encrypt the entire vault in one chunk

Don’t use ECB

Use PBKDF2 between client and LastPass also

Use cert pinning

Embrace open source

Adopt a retroactive, cash rewarded bug bounty program ;)

Conclusions

Password managers are a great tool that everyone should use. Even though we exposed weaknesses in LastPass, it is still a solid tool and a better option than using the same password changing the last characters of your password everywhere. There are ways to harden your LastPass configuration that can avoid some of the explained attacks. Watch the talk and slides for more details on that. To finish, we want to point out that the security team at LastPass responded very quickly to all our reports and lot of the issues were fixed in just a couple days. It was very easy to communicate and work with them.

Important note

We have seen media and tweets mentioning that we “hacked LastPass”. We did not hack LastPass. We also don’t feel comfortable with those claims. What we did is find a number of bugs, bad practices and design issues which we used to obtain the vault key and decrypt all passwords in different scenarios. There is no bug-free software and any future research on other password managers would likely have similar results.

Blackhat video and slides

You can also check out the slides. If you have any questions/concerns, feel free to leave a comment. If one of those questions is what password manager you should use now, I can’t recommend any but make sure you use one!