Insecure Direct Object Reference with an OTP abuse bug led to full account takeover.
Things to Note
- Read the Disclaimer before reading this post.
- I can’t really talk about the android app, because of it’s private nature. So I’ve redacted a couple of things like the domain, auth tokens and stuff like that, but you should be able to understand how this bug works.
The app that I tested was a food delivery app. As usual, we get to have an account of our own, we can order food from different restaurants and stuff like that. After finding an SQL injection on the site, I wanted to find a “not so common bug”. So I started looking around and I actually found an Insecure Direct Object Reference(IDOR) vulnerability and with a little more work, I could completely takeover any account. I’ve broken down these steps into multiple sections, so you guys can understand it better.
Stage 1 - Information Disclosure
When I was looking at the login mechanism of the app, I noticed that the app was receiving some sensitive data back, even if the authentication failed.
As you can see, there’s the
PHONE key in the JSON response which has the phone number as the value of it. Clearly Information Disclosure, but let’s keep digging. I noticed that there was this
USER_ID key, and kept it in the back of my head.
And YES I see the
Content-Type: text/html; charset=UTF-8, I could trigger an XSS via my
USER_NAME or something, but this is an android app, I don’t want to popup alerts on their API domains.
Stage 2 - OTP Abuse
Since I wanted to takeover the account, I thought I could abuse the password reset functionality. I looked at it and it required a phone number, to which an OTP would be sent to. I believe it didn’t have any rate limiting, but it sure had the time limit of about 60 seconds. I thought I could bruteforce since the OTP was only 4 digits, but it’s something obvious to try, so I thought let’s look for some other way and if I ran out of ideas, then maybe fallback to this one. Alright now I wanted to somehow get the OTP of another user, I looked at it and tried a bunch of ways, it didn’t work. But I noticed that I could send OTPs to any number I want randomly. So I sent a request to my number and received an OTP.
Ok can’t do much now either, and I just did more recon thinking that this could help somewhere else.
Stage 3 - IDOR in Preferences
When I was looking at the settings activity, I saw that I could change my phone number. So I quickly tried to change it, but the catch was whenever you try to change the phone number, you’d get another OTP with which you have to verify the phone number. I went through my burp history, saw that there were 2 requests made to the server to verify and update the phone number.
- A request was made to generate a new OTP and send a SMS to the phone.
- Verification request was made, if the OTP was correct, it would update the phone number.
1st request looked exactly like the Stage-2.
2nd request looked something like this.
As you can see in the request it takes in
up_uid which has the value of 123456. We can also see the same User-ID in the Stage-1 response. So I simply changed the
up_uid to one of my other test account and replayed the request with a new otp. And it did change the phone number of my other account. This is a classic IDOR issue. The server blindly updates the phone number of the account via the
So now I could simply generate an OTP with the Stage-2 request and change the phone number using the IDOR bug from the Stage-3.
In the end we can do a simple forgot password and provide the new number which was updated to the victim’s account and reset the password. Erogo account takeover.
That’s all for now folks. Thank you for reading. Have a great day :)