Exploring Weird Account TakeOver (ATO) Vulnerabilities in APIs
Last updated
Last updated
It's been a while since I've published any new articles. I've been busy for last couple of weeks. In this post I'll be discussing weird API ATO bugs that could've been avoided during the development phases by applying simple input parameter, logical and authorization checks.
I always try to identify BOLA vulnerabilities as they are easy to find and exploit. We usually miss implementing simple authorization checks perform operations on API data objects while referencing them with IDs.
For finding any BOLA vulnerability I usually follow below strategy that I've built over the time.
Find an API endpoint that provides API data object information using their ID, example: /api/v1/user?id={user_uuid}
Find an API endpoint that directly provides API data object IDs or a way to enumerate their IDs, example:/api/v1/users/search?name=${payload}
Use API data object IDs and get its information from the BOLA vulnerable endpoint (1st). Always check whether you can update information or any sensitive information is being leaked into the response.
In such patterns, you'll usually find that sensitive information is being leaked which has high impact on CIA triad.
During my initial bug bounty journey, I've found several bugs which led to ATO. Let's discuss one of the scenario from it.
Assume there's a functionality in an API endpoint (/api/v1/users/search?name=${payload}
) which allows you to find users using their name and there's another endpoint ( /api/v1/user?id={user_uuid}
) which returns user data such as email, phone, id, addresses, interests, etc.
/api/v1/user
API endpoint is missing authorization checks. It also returns user generated JWT access and refresh tokens in response. Access token can be used to access and update user account details, while refresh token can be used for maintaining persistence to the account.
A malicious actor can fetch the list of IDs, extract access and refresh token that will allow them to dump user details, update information or delete their account.
Another Example:
API endpoint /api/v1/users/feeds
provides user ids, It can be used to harvest valid user ids.
API endpoint /api/users/detail
provides user data by providing user_id
in query param. User's auth_token
is being leaked in the response, which allows us to use the leaked token by updating Auth-Token
and Auth-Id
in request header.
A malicious actor can easily write a golang/python script to dump user details and their tokens which can be used later.
This vuln could've been easily avoided by excluding JWT token from the response.
I've included this vulnerability since I've found similar issue on multiple platforms.
Implementing password/OTP is most common authentication system used in many mobile and web applications.
The flow usually works as described below:
User opens the application
Application asks user for their unique id that could be username, email id or phone number.
User enters their unique id, they'll now need to enter password or OTP sent on their email/phone.
After user enters password/OTP they'll be able to access their resources.
The issue is not in the flow but the way we devs implement it.
A malicious user can try to find vulnerabilities on the endpoint by fuzzing it. During fuzzing there can be scenario when they'll provide empty password/OTP field or remove it from the payload.
Fuzzing API endpoints can always help to find weird API bugs. Have you tried latest OWASP OFFAT for identifying such vulnerabilities?
Here, if payload checks would've be implemented properly then this bug could've been avoided. Implementing payload checks is necessary to avoid injection attacks as well.
Most of the applications require unique IDs for identifying user's identities for enforcing access controls after authentication with password/OTP/magic link as described flow in above section. Unique IDs can include the following:
email id
phone number
username
Passport Number
Social Security Number, etc.
The problem arises when 2 or more identities are being used for allowing user to login and access resources while login functionality doesn't handle multiple ID logic also allows them to login via multiple ID methods such as email, phone, etc.
Let's say you have a target account which with below details.
target@example.com
phone
1234567890
target@example.com
phone
9321468828
While Signing Up attacker will use target email id and use his phone number for logging into the account. Attacker was able to sign up successfully.
While logging in, the login system doesn't consider multiple id cases, then in some cases, attacker will be able to login into the target account.
Code is pretty self explanatory, while generating token only email is considered due to which the target user will be fetched, later victim token will be generated and returned in response.
Always validate and test login logic correctly
If there are users generated with same email/phone or Id, do not allow them to login or ask them to verify all identity at initial login. (Could be bad for UX)
Let's say we were able to fix the above issue, but if attacker is able to email/phone, etc. after initially using unique email/phone then later exploiting BOPLA to update email/phone. And the user details endpoint is using similar logic (fetching user details based on email/phone), It also exposes sensitive information such as auth_token
then it'll still lead to ATO.
Cherry pick user fields that are being returned in response
Do not allow user to update unique IDs after verification, If this is not possible then atleast verify both IDs after any changes
I've encountered several API endpoints which were exposing user details and OTP in response π. If you're incase affected by it then you have security similar to below image.
I feel you're smart enough to figure it out on your own π
I've seen devs writing custom code for routing API level logic. Why do we need to re-invent the wheel when several frameworks has already implemented that for you? It'll only introduce new vulns in your codebase.
Example Code
If an attacker sends a POST request on /api/v1/login/xx1
or /api/login/anything
with user UUID then it'll still token for that user.
I haven't seen this bug anywhere else but I felt it could be a good read for devs to avoid common mistakes. Hence, I've included it in the list.
Use frameworks without implementing custom code as most of the frameworks follow best practices that we couldn't be aware of
Verify that if block also has else block followed by it for while writing critical business/auth logic
We've discussed about common API bugs that could lead to ATO and which can be avoided during peer/self reviews and including them in API testing. Most of the issues could've been avoided by implementing proper Authn, Authz, input validation and checking for data leakage.