2FA Bypass via Logical Rate Limiting Bypass

Jeppe Bonde Weikop
Jan 30 · 2 min read

My absolute favourite functionality to attack when bug bounty hunting is 2FA implementations. Something about being faced with a difficult, but simple challenge consisting of nothing more than a simple 2FA code input field brings me back to the HackThis!! challenges that I used to spend hours on back in the day.

A classical HackThis!! level.

2FA codes usually consists of either 4 or 6 digits, making them inherently vulnerable to brute force attacks unless proper rate limiting is implemented. Unfortunately for us bounty hunters, the 2FA functionality on bug bounty program web applications are usually well-protected by rate limiting. This is the story of a business logic error that enabled me to bypass the rate limiting on a private program’s 2FA implementation, effectively making it possible to bypass 2FA.

After logging in, the site would redirect the user to a 2FA security check page. I tried to brute force it, but after 10 incorrect 2FA authentication attempts, the site would lock the user account. Annoyed that my attack had failed, I pressed the “Unlock Account” link to continue my testing.

I was asked to provide an email address and a reset link was sent to my email inbox. Now, if you think like me, you may already have spotted the potential vulnerability. I tested if the “Unlock Account” functionality was rate limited. It was not.

Interesting…

I did some additional research and I discovered the following misfeatures:

  • There was no rate limiting on the login page if the submitted credentials were valid.
  • Unlock Account links could be requested by an account that wasn’t locked and the links would remain valid.

Exploitation

Now was the time for exploitation. I wrote a quick script that would

  1. Send a Unlock Account request email.
  2. Submit valid victim credentials.
  3. Attempt to randomly guess the 2FA code 10 times.
  4. Read my email inbox and find the Unlock Account link using Gmail API.
  5. Send a GET request to the endpoint to unlock the account.
  6. Repeat until the correct code is guessed.

The account unlocking request is sent at first to minimise time wasted waiting for the email to arrive to the inbox.

I submitted the report to the program including the PoC script. The Bugcrowd triager seemed a bit sceptical initially due to the email inbox access required, but luckily the security team quickly accepted the report and even praised me for my creativity. I was rewarded handsomely with a $500 bounty.

Takeaways

Unlike many bounty hunters, I’m not a professional penetration tester or security engineer. I find it’s pretty much impossible to compete when hunting classical vulnerabilities such as XSS and SQLi due to amount of extremely skilled hunters and advanced automated vulnerability scanning. In my experience, I have way more success when trying to cheat the system and searching for logical bugs. Also, it’s really fun.

Cheers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade