It’s too easy when hacking, to assume something is invulnerable and not interrogate it. This was the case for me when it came to Duo’s two-factor authentication solution. However, we were able to discover two variants of the same 2FA bypass. These rely on redirecting a victim’s push notifications to an attacker-controlled device, to authorise access to a victim account. Interactions with Duo had this fixed in record time, and were easily some of the best vendor/researcher interactions we’ve ever had. If you’re looking for their technical guidance around this, you can find it here.
As part of our assessment preparation work for a client, I like to read the older reports. One such report had details of a Duo 2FA bypass. I doubted the vulnerability still existed, but I was intrigued by the potential. With high spirits I started the assessment but it quickly became evident that the bypass was no longer possible. In fact, both the request and server response were now very different to those in the previous report. I shrugged off the finding and moved on to testing the rest of the application.
Discovering the initial bypass
While having a closer look at the generated HTTP traffic in Burp, I decided to give Duo another look. We had extra application accounts which we could use for testing, which is important as you’d see shortly. During a typical authentication flow, a user would eventually trigger a two-factor authentication verification that is sent to a Duo endpoint via a POST request, e.g. below:
I logged into the application with my attacker account and captured the aforementioned 2FA request. I copied the request (everything from the Cookie header down) and dropped the request. Next, I logged in with a second victim account. After intercepting that request, I replaced this with the attacker account request. And that did it! Submitting that sent the 2FA request to the attacker accounts’ device. But, I was now logged in as the victim account. The 2FA verification had been sent to the attacker’s device!
I was a little shocked that it had worked. I thought maybe it could have been a fluke, so we tested it with other accounts and device.
For the bypass to be successful an attacker would require a valid application account with Duo enabled on a device in their control, as well as access to just the victim’s credentials.
The next step was to identify which request parameter identified the user requesting the push notification. We first tried using the Cookie values. The Cookie value of several requests were compared and copied to identify any part of it that might be used to identify the user. That didn’t bare any fruit.
sid parameter in the request body was examined. We again looked at several requests to try and identify if any part of the
sid was the identifier. With no clear indication of which part of the
sid we needed, we just copied the entire value. That did the trick! We were now able to bypass the 2FA using just the
sid value instead of the full request.
An example request flow for the bypass is shown in the screenshots below:
To summarise the process, an attacker logs into the application and requests a 2FA push notification to be sent to their attacker-controlled device. The
sid from the request is copied and the request dropped such that it never reaches Duo and the push notification is never triggered. Next, the attacker logs in with the victim’s credentials and requests a 2FA push notification. The request is intercepted and the
sid in the request is replaced with the previously copied attacker
sid. This will cause the push notification to be sent to the attacker’s device allowing them to accept the 2FA prompt.
Now that we could reliably replicate the bypass on the client’s application, a colleague suggested we try it on another Duo instance we had access to, to confirm whether the problem was with Duo or with the client’s implementation. After some testing we found that the bypass also worked on the second instance of Duo meaning this was not an implementation error.
Discovering an attack variant
The first method was rather inconsistent and would often fail because the
sid‘s would timeout aggressively, making it very time sensitive, and would fail if you took too long to copy/paste. With one semi-reliable bypass discovered, Michael Kruger searched for an alternative method.
When requesting 2FA verification, a transaction ID (
txid) was returned. This token was continuously polled to confirm whether the user had accepted the push request.
The above screenshots show the
txid was returned from the server when a user requested a push notification. The
txid was then used in subsequent requests to query the status. By accepting the push on one device, dropping the request and then copying the
txid into a second user’s request, you could trick Duo into thinking the second user had accepted the push.
This method proved to be more stable. It also allowed a user to accept the push before making use of the
We drafted a report detailing the bypass and sent it to Duo Security. They responded quickly and fixed the bug. I attempted the bypasses again to confirm whether the temporary fix worked. I tried using both the
sid and the
txid values, but now neither method worked.
Each time either bypass was attempted the server would respond with “Invalid txid”.
I would like to thank my colleagues Michael Kruger and Thuliswa Funda for their help with discovering and testing this vulnerability. Credit to the team at Duo Security for their speedy response to the vulnerability report and time to implement a fix. And lastly a special thanks to the incredibly nice and awesome Jessey Bullock who was our primary contact at Duo and kept us up-to-date with the fixes and co-ordination of the disclosure.
A note on disclosure
Dominic here. I just wanted to add a note on how pleasant and unusual it was to work with Duo on this vulnerability. Often terrible disclosure stories accompany blogs like this, but this experience was so unusually nice, that we wanted to highlight it.
Duo responded immediately, got the technical team on a call shortly thereafter, had fixed it before the call and started an incident response process to identify any prior exploitation attempts (they found ours). In follow up calls they openly shared the results of what they had found and done during the fix and find phase. We are Duo customers ourselves, and this interaction gave me significant faith in their security and engineering processes.
- 11/12/2020 – Vulnerability Discovery
- 14/12/2020 – Reported to Duo Security
- 18/12/2020 – Duo confirmed the fix had been in place for a few days. We confirmed it for ourselves.
- 07/04/2021 – Public disclosure