How I was able to bypass OTP code requirement in Razer [The story of a critical bug]

Ananda Dhakal
InfoSec Write-ups
Published in
6 min readOct 16, 2019

--

It’s @dhakal_ananda from Nepal and this is my first blog post. Without further ado, let’s move on to the bug already.

So the story is a long one. Before Razer became public in Hackerone, it was a private program as most of you know if you had seen at the time it was public and I was also invited to the private program. But I dunno why I didn’t hack in the program and just rejected the invitation. After some time, it became public and when I saw that, it caught my attention very much. I got very interested in the program and started hacking immediately.

Since I am more interested in bypassing security functionalities rather than searching for XSS and SQLi, I got into bypassing the OTP token because it got my attention in the first look.

I fuzzed some times and found that the application was using a long token to validate whether the OTP code has been entered or not. The OTP token was only provided after entering the valid OTP code.

So what can we do to bypass the code?? I don’t know if that came to your hacker-mind but yeah, it’s using the attacker’s token to validate the victim’s token. I tried that method and it worked.

Here is how you could reproduce the issue:

  1. Login to the attacker’s account
  2. Go to https://razerid.razer.com/account and click on the email field
  3. You will see a dialog saying that you need to enter an OTP code
  4. Enter the valid code and intercept the request of changing the email
  5. Send the request to repeater
  6. Login to the victim’s account assuming that you have credentials of the victim
  7. Intercept the request of changing the name
  8. Copy the user_id and user_token and save it in a file
  9. Paste the victim’s user_id and user_token in the field of the attacker’s user_id and user_token at the request that was sent to the repeater
  10. Submit the request and see that the email address is added into the victim’s account without OTP token requirement
POST /api/emily/7/user-security/post HTTP/1.1
Host: razerid.razer.com
Connection: close
Content-Length: 260
Accept: application/json, text/plain, */*
Origin: https://razerid.razer.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
DNT: 1
Sec-Fetch-Mode: cors
Content-Type: application/json;charset=UTF-8
Sec-Fetch-Site: same-origin
Referer: https://razerid.razer.com/account/email
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: ...
{"data":"<COP><User><ID>user_id</ID><Token>user_token</Token><OTPToken>otp_token_value_here</OTPToken><login><email>attacker-email@example.com</email><method>add</method><primary>1</primary></login></User><ServiceCode>0060</ServiceCode></COP>"}

Note: This steps for reproduction is not the same as I submitted in the report. This is simplified and actual steps for reproduction with exploitable POC.

I did this because the application didn’t validate the cookies and other things. All it validated was user_id, user_token and OTP_token. But the OTP_token was only validated if it was a valid one. It was not validated if it is of the specific user. It means I could paste the attacker’s token in the victim’s request and bypass OTP validation for the victim account.

You know what?? The process didn’t end up smoothly. Here is the real story.

I submitted the report with steps for reproduction as below. The below steps for reproduction and the above steps for reproduction were the same at last. It's just that the below steps for reproduction is complicated and not understandable.

Yes, you could follow those steps to reproduce to access the victim’s settings and it was also what I found at first. It is by changing the response and doing things and things and things but, from the above steps for reproduction, the team members thought that it would require physical access to the victim’s device/browser. I had fuzzed so much to get these final steps for reproduction but Hackerone triage team-member asked for more information regarding it saying something like this:

I was like “what the hell?

I am exactly doing that thing. I replied with some shitty thing that had no answer to this question if I see it now. After my reply, the member closed the report as Informative. I asked him to let the internal team evaluate the issue. The internal team member said that this was not a valid issue i.e he also didn’t clearly understand what I was trying to say. I asked him to open the issue so that I can self-close it because they didn’t seem to understand it at all. To be more clear, I also didn’t understand it as I do now. He then opened the report for me to self-close because it didn’t have a negative impact on my signal.

#BugBountyTip: Before you submit bug like this, make sure that you have clear steps for reproduction. Try to simplify the steps as much as you can. The bug that you can understand could not be understood by the team member and you could end up getting an N/A or Informative like I did at first.

I completely left the report and moved on. After 3 days of moving on, I went back to the report because I realized a thing. Most of the application asks you to enter the 2FA code at the time you login but it asked when I tried to change the sensitive information. So I commented in the report that I was bypassing the 2FA requirement so it must be a valid vulnerability.

I got a reply after a day saying something like:

If you have a PoC where you have access only to the victim user’s Razer ID account and password and then can access or change profile information, it would be a valid report.

And I was like Challenge Accepted!!

The team member provided me the email address and password of a test account to change the email address. I changed the email address of that account without accessing the OTP token and removed the previous email. After doing that, I said that I had changed the email address and you could not access the account with previous email.

I with my brother and my cousin were together during this hack and we were really shouting after I completely exploited the bug early in the morning :P.

One day after that, he reopened the report and changed the status to Triaged with severity set as Critical. I was really happy since I was able to show a POC and exploit the vulnerability.

After 2 days, I thought I would do a writeup on this issue and save a video for it. But before I could create a video POC, it was fixed.

I was awarded a total of $1000 bounty for the issue. The bounty was $750 and the bonus was $250 for the very very long misunderstanding.

#BugBountyTip: Make sure you fuzz the parameters and use one user’s tokens in another user’s session. Sometimes, there could be token-validation but missing user-token validation.

After a few days of triage, I found another OTP bypass and it is already resolved. It was a really fast and efficient fix and the bounty is pending.

I hope you guys enjoyed this really long blog post. Feel free to send some feedback as I will really appreciate it. See you again in another writeup.

Hackerone profile: https://hackerone.com/dhakal_ananda

Twitter profile: https://twitter.com/dhakal_ananda

--

--