How I abused 2FA to maintain persistence after a password change (Google, Microsoft, Instagram, Cloudflare, etc)
TL;DR: Waiting in the 2FA page could allow you to log in without knowing the current password in many major websites.
This is a logic flaw vulnerability I initially found in Google, and then tested in other top companies (such as Microsoft, Instagram, Cloudflare, etc) to find out they were vulnerable as well.
1) The initial bug
It all started with the idea that, being 2FA newer than most login flows, it would have to be implemented by different teams at different times (in some cases, probably years apart).
As any project involving multiple teams, communication is hindered and coordination can be impacted.
So… what happens if you try to change something in the process, like changing your password, while being in the process of logging in, let’s say in the 2FA login page?
So I went, changed the password (triggering all sessions to be terminated), waited 10–15 min and then tried the 2FA code… It worked!.
Having this PoC, I immediately went and reported it to Google. After some exchange of emails, they acknowledge the issue but remarked that the sessions expired after 20 min:
“If you find a way to make this attack work for more than, say, two hours please let us know. This would indicate a problem in our session logic.”
2) Round two
After some weeks of slowly testing different scenarios (to be honest, I thought it was a dead-end) I found out a way of bypassing session expiration: if you went to ‘Try another way’ in the 2FA input page, chose 2FA as a method again (funny, right?) your session was renewed, and you had another 20 minutes to go. Automated this test, made a PoC, waited for +2 hours and it still worked.
But this was not the best part. Poking around the options available and all the possible flows, I tried all this process again but, in the middle, turned off 2FA. Being in the 2FA input page, the code should not work if 2FA is off, right? Well, wrong. The 2FA code was working even when the 2FA option was off!.
This changed everything. The attack scenario just got bigger.
This means that if an Attacker hijacks an account (leaks happen everyday), exploiting this vulnerability the new attack scenario would be:
- An Attacker enables 2FA in Victim’s account.
- In another browser, Attacker waits indefinitely in the 2FA input page (Image 1).
- Attacker disables 2FA.
- The Victim regains access to the account (changing password & resetting sessions)
- Then the Attacker could input a valid 2FA code and have access again to the account, without knowing the current password.
I quickly sent this new information to Google and got the confirmation of the bug:
After a few weeks, the panel awarded me a nice bounty and fixed the issue :)
3) The others
Some days later I thought ‘If this happened with Google, what about other companies?’.
I went on testing in other big companies (Facebook, Github, LinkedIn) and this was not working: whenever the password was changed or the 2FA was disabled, the session waiting in the 2FA input page would no longer be valid.
However, being Instagram one of Facebook's top acquisition, I tried it there as well and found it was vulnerable! Sadly, they labeled it as "theoretical attack". Microsoft Login was vulnerable too, but didn't fix it either (more on these later).
After some trial and error, I went through HackerOne/Bugcrowd directories and found many companies that were vulnerable to this attack (Cloudflare, Algolia, some private programs, etc). They all fixed the vulnerability and awarded me bounty/swag.
4) Not fixing
Two important companies labeled this vulnerability as "working as intended": Microsoft and Instagram.
Being Microsoft one of the top companies as well, and having their ‘Microsoft Identity Bounty Program’ released within those days (up to 100K bounty), I checked their centralized login: login.live.com. Tested Google’s exact same attack scenario and I couldn’t believe my eyes: it worked, too!
Sadly, it was not a good experience as it was with Google. All the responses I received seemed to fail understanding the vulnerability reported, and closed the report as “work as intended”.
After some time, I escalated through LinkedIn with someone from Security for them to re-review the report. Made them a blog post about it explaining the vulnerability and 2 PoC videos.
One of their answers was "if you are still seeing this issue post 24 hours of logout, this could potentially meet the bar.". Sent a PoC showing this was possible, but they still would not agree to fix it.
Asked if it was OK for me to publicly disclose this information and they agreed. Communications with Microsoft started 06/2017. This vulnerability still works in Microsoft Login.
As soon as I validated that this vulnerability was working in Instagram, I crafted a nice report and sent it to them.
However, the vulnerability was not fixed:
"[the attack] seems unlikely to happen commonly, making this more of a theoretical attack. The protection in this case is to not allow someone to steal your password"
I tried remarking that an "unlikely" in a +1B users platform could mean millions of users affected by this attack, but even then was not marked as valid.
Some months later, after Facebook’s security breach in 09/2018 (and posting that they would be “decreasing the technical overhead necessary to be eligible for bug bounty”), I re-opened the issue asking if this could be reconsidered as a valid vulnerability. However, they told me I was not the first one reporting this vulnerability, so if this vulnerability was someday marked as valid, my report would still be ineligible for a reward.