TLDR:U2F prevents MITM attack between the victim and the Duo server, but not between the victim and the application. Because Duo is a 3rd-party service, we don’t have the same security properties that are associated with U2F between the victim and the server. This boils down to bypassing the Duo integration. If you can bypass the Duo prompt, then the phishing attempt will be successful, even if U2F is used. To prevent phishing, it is paramount that you enablehostname whitelisting[1].Without hostname whitelisting, Duo is similar to an OTP generator during a phishing attack.
I’ve contacted Duo PSIRT about this and their full reply is quoted at the end of the blog post. Here are their main points:
- Hostname whitelisting isn’t enabled by default because it’s difficult to know what hostname(s) are used by many Duo prompt integrations beforehand
- This feature is encouraged in the documentation and is proactively recommended by Duo support to its customers that use U2F or WebAuthn
- Fortunately, the Duo prompt and Web SDK are undergoing a major redesign that will eliminate the need for manual hostname whitelisting for all applications. This will be available soon.
Why is Default Web Duo Phishable
Because U2F is done through the an integration Duo and not directly on the application, the MFA can be bypassed without attacking the U2F directly. We just work around how Duo is integrated to the application.
U2F functionalities with Dashlane. Dashlane supports the FIDO Alliance™ universal two-factor (U2F) authentication standard, and we have partnered with Yubico, the provider of U2F YubiKeys. FIDO U2F is a convenient and secure way to complete two-factor authentication, freeing you from having to hunt for a code whenever you need to authenticate. 1Password Support Team. Moderator of r/1Password, speaking officially Original Poster. 2 years ago Stickied comment edited 1 year ago. You asked, we listened! You can now use Yubikey with our two-factor authentication to protect your 1Password account. Two quick notes: it'll require the Yubico Authenticator app so Mac, Windows, Android.
Here is an illustration of the process that results when implementing the Duo web (which we discuss in the next secions).
If we simplify this to two main connections:
- victim to application
- victim to Duo
U2F protects the connection between the victim and Duo. Any attempt to authenticate when there is a MITM between victim and Duo will fail.
Fortunately, with this setup, we only need to get a MITM between the victim and the application.
Since the victim connects to the Duo API host directly, the necessary HTTPS connections are established with the right domain, api-xxxxxx.duosecurity.com
, making U2F possible. Although you may be using U2F as part of this authentication process, you may get the U2F’s “anti-phishing” because of the way the Duo web is architectured.
The rest of this post discusses other related topics such as:
- How the Duo Web is integrated
- The security impact the architecture of Duo web
- Solutions and Mitigations
Introduction
In my previous blog post, “Bypassing LastPass’s “Advanced” YubiKey MFA: A MITM Phishing Attack,” I discuss at length why U2F is important to mitigate the risk of MITM attacks. I also demonstrate how to set up the phishing site using a fork of evilginx2, which we will use here.
I got a suggestion to try out U2F with LastPass’s integration with Duo. I’m not a Duo user but I was interested in trying this.
@__pberba__ Read your Lastpass/Yubikey article. Good stuff. Suggestion: Register for free Duo account, register Yubikey as U2F in Duo, enable Lastpass with Duo, now you have U2F/FIDO2 as 2FA.
— dreamer (@alabrian) May 29, 2020Unlike the previous blog post, this is not specific to LastPass (sorry LastPass). I use LastPass here because it’s the application that is readily available to me. I have also tested with 1Password.
To be clear, having MFA authentication is better than not having any at all, and although I am not a Duo user, I think there are clear benefits when using MFA features such as the push notifications where you get actively notified when somebody tries to log-in into your account. On top of that, when using these kinds of services, you get additional authentications logs and analytics for your protected application.
However, defaults matter and we analyze how the default Duo U2F configuration in the context of a phishing attack.
U2F with Duo Web and Phishing
Setting up Duo Web U2F
Here is a quick run-through of the setup process that I went through to integrate Duo with LastPass.
You click protect and you get the Integration Key, Secret Key, and API hostname.
You enter these to the LastPass MFA settings.
And that’s it. It is enabled with LastPass.
To add a security key, I went to Dashboard > Users > <USER>
and put in my security key.
Phishing Site
We use the same set-up from the previous blog post. Here is the set-up script for the phishing site.
What’s nice about this is that there are no special changes needed to do a MITM attack on a default Duo Web setup.
The victim lands on the fake log-in page and enters their credentials.
LastPass sends you an iframe with the Duo Web prompt. This connects to the real Duo API endpoint.
The victim authenticates with the Duo endpoint and Duo then returns a signed authentication token that will be used to finish the sign-in process with LastPass.
If you look at the Duo dashboard, you will see that this is indeed logged as U2F.
U2F but still phishable??
What happened? I thought U2F was not phishable?
If the integration of the U2F on the original application server, this attack will fail. If you try this with Github you will see that in a usual context, U2F is indeed not phishable.
The same attack fails with Github
It boils down to this. Whether it is the “Duo prompt”, TOTP, U2F, WebAuthn, etc… in the end, Duo will sign an authentication token which the application will verify to finalize the log-in process
Without additional security mechanisms, then Duo is like a fancy OTP generator during a phishing attack.
Understanding the Duo Web architecture
To understand this, let’s look at how Duo Web is set-up.
These instructions come from the Duo Web documentation [2]. This assumes that the application already has the Integration Key, Secret Key, and API hostname, that we set-up in the previous example.
Authentication flow with Duo
Step 1: Sign a request
This is done on the server. The akey
is some random data the server made.
Step 2: Initialize the Duo Web prompt in the form of an iframe
This is done on the client-side and renders as an iframe.
After the authentication, the iframe sends a post request to the URL defined in the post_action
field.
Step 3: Verify signature
On the post_action_url
you receive the response and verify the signature.
authenticated_username = verify_response(ikey, skey, akey, sig_response)
if authenticated_username:
log_user_in(authenticated_username)
Some notes here
Notice here that regardless of the authentication method, the server will receive a signed response. We can see that this is just like an OTP generator because nothing prevents a MITM phishing attack. The signatures prevent tampering of tokens in transit, but it doesn’t prevent someone from intercepting the tokens.
The initial request only has information about the username and not the IP address of the request. This comes in play later when we describe what the Duo endpoint “sees”.
From what I’ve read, the post_action
parameter is not checked against anything. So the signed authentication token that Duo generates can end up anywhere that the**post_action**
is pointed to (like our phishing site). The post_action
is similar to OAuth2’s redirect URI, which I will discuss more later.
Security Impact
These are the impact of keeping the default configuration of Duo Web to protect applications like LastPass and 1Password.
Phishable U2F
As we have shown, the first effect is that U2F is still phishable when using the default config of Duo Web.
If you set-up U2F on a site directly, you are protected from phishing by default because of HTTPS. So in a way, if you want to be really sure that you get all the benefits of U2F, it is better to set up your security keys with each website directly.
Duo Prompt
Because the browser talks directly to the Duo server, what Duo sees is the victim’s IP address. This means when a user uses the Duo push notification, they will not see anything suspicious and the MITM attack that we are using will be undetectable on the prompt.
Prompt picture from [4]
If an employee sees that their IP address and location are correct on the push notification during a phishing attack, they may let their guards down.
In such a case, the victim is better off relying on notifications from the web application itself, because that will show the attackers IP address.
Authentication Log
Similarly, authentication logs will reflect the victim’s information rather than the attackers. So when monitoring for phishing attacks, remember that authentication logs may not be as useful by default.
Below is an illustrative example.
Of course, if the attacker then tried to authenticate on their own browser, then their IP address will be the one that is logged.
Solutions and Mitigations
Here I will list down some of the solutions or ideas that can address some parts of this. The first one is the most flexible and straightforward to do with the current set-up. The latter ones may not be that applicable to some deployments.
Hostname Whitelisting
Because the Duo Web prompt is embedded as an iframe, then the browser’s requests to the Duo API endpoint would put the phishing domain as the referrer.
Since Duo knows that application the user is trying to authenticate one, then there is an opportunity to block unknown HTTP referers.
This is what I recommended to the Duo Security team when I reported this to them. What I realized, later on, was that this was already implemented as an optional configuration, I just didn’t realize it when I set it up.
If the incorrect referrer is blocked
If done properly, then the MITM will be forced to make the connections to the Duo endpoint so that they can put the right referer headers. This will make attacks a bit more complicated and more discoverable.
This helps to make IP of the MITM show up in Duo push notifications and the authentication logs.
Unfortunately, this optional feature is:
- not enabled by default
- has no preconfigured hostnames
- not mentioned or asked during the setup process (Do you want to turn on hostname whitelisting?)
- (in my opinion) not easy to find if you weren’t looking for it
It should be noted that these are mentioned in the documentation and briefly mentioned in the setup instructions [3]. However, I admit I missed these when I first set-up my Duo since they were in sections that I didn’t read anymore after the setup was successful.
Here I would argue that it should be recommended not just for WebAuthn or U2F, because of the impact I have listed previously.
For custom applications, deployments, and integrations, I understand that this has to be configured by the users.
However, I feel that if I’m are already choosing a commonly used application such as “LastPass” or “1Password”. It’s reasonable to expect that there’s an enabled pre-set whitelisted hostnames, like *.lastpass.com
for LastPass.
But this is a design decision, and, in the end, it’s the user’s responsibility to enable it. If you want to configure this, here is where you will find it
How OAuth2 handles redirect
This is similar to the hostname whitelisting, but we are filtering on the redirect URL. From what I’ve read in the Duo Web documentation, the post_action
URL is an open redirect. This contrasts with what OAuth2 does [5]:
Because the redirect URL will contain sensitive information, it is critical that the service doesn’t redirect the user to arbitrary locations.
The best way to ensure the user will only be directed to appropriate locations is to require the developer to register one or more redirect URLs when they create the application. [5]
If implemented when applications like LastPass and 1Password set up their integration with Duo, they would have to set up a whitelist of their redirect URLs.
In OAuth2, the onus of setting up the whitelist is on the developer of the application. In Duo, the responsibility is by default, on the IT administrators that try to use these integrations.
Remove the iframe
Although this is starting to introduce bigger changes in architecture and might be less flexible compared with the current set-up.
If the integration of the application and Duo happens on the server-side such that there is no need to have an iframe, then we are closer to the conditions where U2F is able to prevent the fishing attack.
This is similar to other setups like Universal FIDO server [6][7]
Nok nok lab [6]
However, this would mean that the users would still need to set-up the security keys per site since the signatures are going to be tied to the domain of the application (which is something that we may actually want).
More information in the signed request
I haven’t thought this one through that much, but I’m just putting this out there.
When the initial sign request is made by the application, part of the request should include the IP address of the client. In the case of a MITM attack, this IP address would be the IP address of the proxy.
This is the application telling Duo, “_Expect to authenticate [1] Duo: Protecting Applications, Hostname Whitelisting [2] Duo Web [3] Duo: LastPass [4] Duo Mobile on Windows Phone [5] OAuth2: Redirect URIs [6] Nok nok: What is FIDO2? [7] Google and Microsoft Debut: Replacing Passwords with FIDO2 Authentication Photo by stephen momot on Unsplash I’ve used Authy for several years to generate mytime-based one-time passwords(TOTP)for two-factor authentication(2FA). For variousreasons, I recently migrated to using Bitwardeninstead. Many services recommend using GoogleAuthenticator for 2FA. Ioriginally used it before switching to Authy, but I switched for a reason thatis still valid today: it doesn’t have any sort of backup or syncingfunctionality. Check out thereviewsto get a sense of how often people get burned by switching to a new phone forwhatever reason and realizing they’ve lost all their codes or need to go througheach service one by one and set up 2FA again. Google Authenticator is also a neglected app. The Androidappwas last updated on September 27, 2017, and the iOSapp was lastupdated on September 12, 2018. You could argue that these are relatively simpleapps that don’t need frequent updates, but take a look at what other apps likeandOTPand Aegis offer in terms of functionality that GoogleAuthenticator doesn’t have, like being able to search for a service instead ofhaving to scroll though the entire list to find it. While I have happily used Authy for several years, I also have some issues withit that caused me to look for a replacement. Authy doesn’t have a browser extension forFirefox, my primary browser. This is aproblem because an extension can offer some protection againstphishing, one of the main securityweaknessesof using TOTP for 2FA. If the extension fails to find an entry that matches thecurrent domain, that can alert me to a possible phishing attempt. The Chromeextensionalso hasn’t been updated in two and a half years and will no longer besupported goingforward. Authy doesn’t have a web client. While this could be considered a securityfeature, I’d rather have the option to access my codes through any browser in anemergency. It’s a security vs. usability tradeoff that I’m willing to make. Authy doesn’t have a CLIclient. I have some ideas for personal browser automation projects that could beeasier to implement with programmatic access to my TOTP codes. I use the Mac desktop program, but when it has a code open, the program usessignificantly more CPU. Here’s the CPU usage when it’s just displaying the listof services. And here’s the CPU usage when it’s showing the TOTP code. Since I don’t want the program to unnecessarily drain my laptop battery, I tryto remember to press the back button after copying the code. There’s no optionto automatically go back on copy or to just copy the code from the list viewwithout even seeing the code. When you create an Authy account, you have to provide a phone number rather thanan email address or username. I didn’t like this to begin with since I want asfew things tied to my phone number as possible, given how often phone numbersget hijacked. Authy thenencouragesyou to add the app to your other devices and then disable the multi-devicefeature. This means that your codes will keep working on your existing devices,but to add Authy to a new device, you need access to one of your old ones totemporarily re-enable multi-device and to grant access to the new device. If youdon’t have access to an old device, you have to go through a 24 hour accountrecoveryprocess. However, I want to be able to regain access to my 2FA codes, even if I’ve lostaccess to all my devices. For example, I could be in a foreign country withoutmy laptop and then lose my phone. I want to have a good contingency plan forthis kind of situation. Note that Authy doesn’t support an account level password. It does support apassword for your encrypted backups, but you don’t enter that until after youlog in. Authy also doesn’t support TOTP codes orU2F security keys forprotecting itself. Its sole authentication mechanism (beyond account recoveryprocesses) is access to an old device. I considered using my YubiKeys to generate TOTP codesusing YubicoAuthenticator,but a YubiKey can only store32TOTP secrets, and I already have 49 of them since I enable TOTP-based 2FAwhenever possible. I currently use LastPass to manage my passwords,but I am going to switch to 1Password soon. I decidedto use Bitwarden as well but solely for TOTP codes. 1Password can also handleTOTP codes, but I am willingto deal with the hassle of having two password managers to avoid using the sameservice for both passwords and 2FA. By using a password manager for TOTP, I get broad cross-platform support with aweb client, browser extensions, desktop programs, mobile apps, and even a CLIclient. I also get standard authentication mechanisms, including 2FA support. This does mean that I am treating my TOTP codes more like secondary passwords(something Iknow)rather than as something Ihave.Authy’s requirement to have access to an old device better fits the latterprinciple. This is a deliberate choice on my part. Note that Bitwarden requires a premium account that costs $10 a year in order togenerate TOTP codes. A premium account also adds U2F support, which I wanted aswell. U2F support is the last component of my authentication strategy. Going forward,it will be like this: I’ll store passwords in 1Password and TOTP secrets inBitwarden. I’ll use separate, high entropy masterpasswords that will only exist in my head. 1Password requires a secret key inconjunction with the master password in order to log in on a new device. Since Ican’t memorize it, I plan to store my secret key as a staticpasswordon my YubiKeys. This means that if I touch the metal contact for a few seconds,it will type out the secret key for me. For both services, I’ll add all my YubiKeys for 2FA. This means that all I needis one of my YubiKeys (one of which is on my keychain) and the master passwordsin my head to regain full access to all of my accounts. However, I can’t guarantee that I’ll be able to use my YubiKey on every device.For example, Bitwarden doesn’tsupport U2F inits mobile apps. I would also be paranoid about feeling like I need two YubiKeyswhen I travel in case I lose one. My plan to deal with these issues is to also set up TOTP-based 2FA for both1Password and Bitwarden. I’ll print those TOTP secrets, along with the 1Passwordsecret key, on a small card and laminate it. I can make multiple copies to putin my wallet and my bag. Sometimes being overly prepared is fun in itself, eventhough it might be overkill. To migrate to Bitwarden, I went through my Authy list one by one. In theory, I’dbe able to just copy the TOTP secret to Bitwarden, but Authy doesn’t expose thesecret. For each account, I logged in and reset 2FA to add the secret to Bitwarden. ThenI deleted the account from Authy. Authy marks it for deletion and then waits 48hours before actually deleting it in case you made a mistake. I did have trouble with adding some services, such asAlgolia and npm, that onlyshow the QR code and don’t have an option to display the TOTP secret. The QRcodes encode URIs that look like this, asdocumentedin the Google Authenticator wiki: I tried using my phone camera’s built-in QR scanner, but I couldn’t see the fullURI and opening it would open Authy, with no other option. I used GoogleLens instead to grab the secret. In retrospect, I wasonly having trouble because I was adding the services to Bitwarden through thebrowser extension. I should have installed the mobile app from the beginning andused that because it has an option to scan QR codes. I also had trouble with adding Twitch, which has aspecific integration with Authy instead of providing a generic QR code. To getaround the issue, I followed thisguide.You can use the deprecated Authy Chromeappto retrieve the TOTP secrets and configurations. This method entails usingChrome’s developer tools to execute customcode toprint the information. This revealed that Twitch uses 7 digit codes instead of the standard 6 and 10second intervals instead of the standard 30. At this point, I thought I hit a Bitwarden limitation because I mistakenlyassumed that the extension would only take the TOTP secret in the authenticatorkey field. However, I discovered that Bitwardensupportsputting the full URI with configuration into that field. I tested it and wasable to log in to Twitch using the code generated by Bitwarden. Migrating to Bitwarden took me about a full day, but I’m happy with the result.I’ve been using the Bitwarden browser extension to log in to accounts for thepast week, and it is much nicer than using the Authy desktop program. Next up ismigrating from LastPass to 1Password.Google Authenticator Issues
Authy Issues
No Browser Extension
No Web Client
No CLI Client
Mac CPU Usage
Authentication and Recovery
Yubico Authenticator
Bitwarden
Authentication Strategy
Migration
Best Passwords List
Conclusion
1password 6 For Mac