This article is about how I found a vulnerability on Microsoft online services that might have allowed anyone to takeover any Microsoft account without consent permission. Microsoft security team patched the issue and rewarded me $50,000 as a part of their Identity Bounty Program.
After my Instagram account takeover vulnerability, I was searching for similar loopholes in other services. I found Microsoft is also using the similar technique to reset user’s password so I decided to test them for any rate limiting vulnerability.
To reset a Microsoft account’s password, we need to enter our email address or phone number in their forgot password page, after that we will be asked to select the email or mobile number that can be used to receive security code.
Once we receive the 7 digit security code, we will have to enter it to reset the password. Here, if we can bruteforce all the combination of 7 digit code (that will be 10^7 = 10 million codes), we will be able to reset any user’s password without permission. But, obviously, there will be some rate limits that will prevent us from making large number of attempts.
Intercepting the HTTP POST request made to code validation endpoint looked like this
If you look at the screenshot above, the code 1234567 we entered was nowhere present in the request. It was encrypted and then sent for validation. I guess they are doing this to prevent automated bruteforce tools from exploiting their system. So, we cannot automate testing multiple codes using tools like Burp Intruder since they won’t do the encryption part 😕
After some time, I figured out the encryption technique and was able to automate the entire process from encrypting the code to sending multiple concurrent requests.
My initial test showed the presence of rate limits as expected. Out of 1000 codes sent, only 122 of them got through, others are limited with 1211 error code and they are blocking the respective user account from sending further attempts if we continuously send requests.
Then, I tried sending simultaneous / concurrent requests like I did for Instagram, that allowed me to send large number of requests without getting blocked but I was still unable to get the successful response while injecting the correct 7 digit security code. I thought they have some controls in place to prevent this type of attack. Although I am getting an error while sending the right code, there was still no evidence of blocking the user like we saw in the initial test. So I was still hoping that there would be something.
After some days, I realized that they are blacklisting the IP address if all the requests we send don’t hit the server at the same time, even a few milliseconds delay between the requests allowed the server to detect the attack and block it. Then I tweaked my code to handle this scenario and tested it again.
Surprisingly, it worked and I was able to get the successful response this time 😀
I sent around 1000 seven digit codes including the right one and was able to get the next step to change the password.
The above process is valid only for those who do not have two factor authentication enabled, if a user has enabled 2FA, we will have to bypass two factor code authentication as well, to change the password.
I tested an account with 2FA and found both are same endpoint that are vulnerable to this type of attack. At first, user will be prompted to enter a 6 digit code generated by authenticator app, only then they will be asked to enter 7 digit code sent to their email or phone number. Then, they can change the password.
Putting all together, an attacker has to send all the possibilities of 6 and 7 digit security codes that would be around 11 million request attempts and it has to be sent concurrently to change the password of any Microsoft account (including those with 2FA enabled).
It is not at all a easy process to send such large number of concurrent requests, that would require a lot of computing resources as well as 1000s of IP address to complete the attack successfully.
Immediately, I recorded a video of all the bypasses and submitted it to Microsoft along with detailed steps to reproduce the vulnerability. They were quick in acknowledging the issue.
The issue was patched in November 2020 and my case was assigned to different security impact than the one expected. I asked them to reconsider the security impact explaining my attack. After a few back and forth emails, my case was assigned to Elevation of Privilege (Involving Multi-factor Authentication Bypass). Due to the complexity of the attack, bug severity was assigned as important instead of critical.
Bount email from MSRC
Microsoft Acknowledgement for Reporting this issue
I received the bounty of $50,000 USD on Feb 9th, 2021 through hackerone and got approval to publish this article on March 1st. I would like to thank Dan, Jarek and the entire MSRC Team for patiently listening to all my comments, providing updates and patching the issue. I also like to thank Microsoft for the bounty 🙏 😊
This article is available as PDF Download.
This article misses so many things, how the encryption worked and what you did to decrypt it, sharing the script code would be great too, how you bypassed the rate limit (details)? if it was a CTF it would be strange to read “there was a rate limit, there was an encryption, I wrote a tool for the encryption, I modified the tool once, it worked”, this is very superficial.
Hi Laxman I was following you since your first Insta hack you inspired but I don’t know where to start for become a bounty hunter like you . I have only hope on you please
Superb article.
May I know how is it possible to send those number of requests concurrently please ?
Can u pls share the source code for brute force?
Incredible!!!
” After some days, I realized that they are blacklisting the IP address if all the requests we send don’t hit the server at the same time”
How did you bypassed this?
Hello Laxman,
Congrats for your recognition from Microsoft for what you have. If possible please please make a course on bug bounty hunts.
Regards,
Vineeth.
Can you please explain how did you make sure that all 1000 requests hit the server at the same time?
Since network is not reliable requests have +-ms range, I was never able to do that.
hi, i guess the encryption technique is aes?