Recently, I got the request to pentest the application from two companies. For security purpose, I hide their identity, so, I called them with the name as X and Y. During the penetration test, I discovered the bug that led to Account Takeover (ATO), I found that the bug was simple, not superior. The more important was that I wanted to share the things what I have done. Somebody says “Sharing is Caring”.
What is ATO? ATO is the common name for bugs that can help the attacker control other user’s account, you can understand simply like that. For convenience of readers, I will split into two parts, part 1 is company X and part 2 is company Y.
Company X: Set new-password without matching Code
Briefly on the X’s business, this is a cryptocurrency exchange and X has headquarter in Europe. I also read quite a lot of write-up and blogposts about ATO and often see forgot-password feature led to this bug. I also test the forgot-password feature on this website; we usually see the forgot-password feature in two common ways: send reset-link or send code to email address. The X’s application uses the second way – to send the code.
The flow of the application: When you click on the forgot-password link, then enter the email address, after the server will return the response as shown below (BurfSuite’s screenshot):
Then we will be redirected to the address in the value of the url parameter, which is accompanied by a hash fragment that is very long and hard to understand, and I guess it will be mapping to the email address. Next we will see a pop-up notification. The password reset code will be sent to the email and you have to enter this code to reset the password.
The value of the code is sent to email containing 5 characters (only numeric characters), the brute-force will have to attack up to 100,000 values, unfortunately, the website uses google captcha and this code only lasts for a while, so brute-force will not work. And I did not know how to test. After a week, I suddenly had the idea to test, I created 2 accounts to test temporarily called email@example.com and firstname.lastname@example.org, each account I used on different browsers. At first, I made the Forgot-password for both emails, Code was sent to both, instead of using Code was sent to email@example.com, I used the Code was sent to firstname.lastname@example.org to reset the password for email@example.com… and that’s very fortunate, I changed the password for firstname.lastname@example.org, because sometimes we have no idea what the backend is doing so we have to test in all case. The bug was sent to the dev team to fix.
Company Y: IDOR leads to ATO
About IDOR, I will not explain here, because this bug is quite popular. Y is a company providing solutions and applications just for small enterprise such as work management; meeting, human management, etc. I am quite impressed with their product, many features as well as nice interface.
This time, I test the bug on android-app. In addition to the specific bug on the mobile, I usually focus more on the API backend, and often test IDOR first because it is very common on mobile-app. From IDOR, it leads to 2 major impacts: read the content from Y’s customers and ATO.
How does this mobile application works? The application is designed simply with the main features such as: exchange of messages, friends list, notifications, and list of links to other applications. When the user logs on, the server do authentication and returns an access_token and each subsequent request was sent to the server with this access_token.
Where does ATO occur? This app has a feature that links to other application. For example, a linked application are: job management, meeting, and mobile-app. User selects these apps for using and these apps are webapp actually. It is displayed via webview in android. This mobile application is published on both iPhone and Android, and iporn is available in my own so I test it. The request will look like this:
The value of the host field is the application that you want to use. The structure of access_token:
system_id: is the id of Y’s customer, that means all employees of their customer have the same system_id.
client_key: is added after I report (this screenshot is after the fix).
At this moment, I think the test is done because the server only checks the existence of system_id parameter. user_id value can be bruteforced. But, life is not easy. The application still request the login information. Probably, the server checked the hash of that user_id :(. I always test both mobile platform to determine if there is any difference. Lucky is the friend.
Below is the same iPhone’s sending request but captured on Android app:
There is a difference here: the request is sent with new parameter, __code = native. I thought it was just like the iPhone. But, hmm…, why I dont try to test IDOR bug.
I ignored the process of finding user_id and system_id because it is simply to do with Intruder feature in Burpsuite. So, what does the __code = native parameter do? This parameter tell the server that the request was sent from the mobile application and the response should be different from the webapp. On the server, it simply checks whether system_id exists, if it exists, checks for any user_id that exists, and forgets to validate whether the user_id belongs to that system_id and does not check hash for user_id + system_id. In conclusion, I access successfully to any customer accounts.