A Case Study of API Vulnerabilities

Overview

This writeup details a series of vulnerabilities I encountered a few months ago on a single private program. The company did specify that they would like to read the writeup before publication to approve it first. Unfortunately, the private program has since been shut down, and the email account that I was in correspondence with has been disabled, so I have decided to publish my writeup anyway in good faith without any identifiable information, for lack of other options. So here we go.

For the sake of privacy, I will be referring to the vulnerable entities as "Grandparent", "Parent" and "Child".

A "Grandparent" entity oversees several "Parent" entities, and the "Parent" entity manages the "Child" entity (end users). Each entity has an ID value.

Chaining API vulnerabilities

In this case, the Parent entity's ID value was a very powerful piece of information to have. Although it was a UUID, that doesn't mean anything if the value can be obtained through means other than guessing. In this case it was leaked within the API requests sent by a pre-auth user.

There was also a leak of the Grandparent ID in a request fetching content from an AWS bucket, but this is useless pre-auth.

The next vulnerability was that there was an IDOR in the account creation system that first allowed the user to assign arbitrary roles (such as Admin) in the Parent entity, and secondly allowed the user to create accounts in any Parent if the Parent ID was known.

At this point, the attacker could escalate to become an administrator in the Parent entity. Next, there was an endpoint for GetParentById that took the Parent ID as a parameter. This endpoint actually required no authentication, and leaked API keys, administrator details, the Grandparent ID, and more sensitive data.

Next, the Grandparent ID could be used alongside the API keys to list all of the Parent entities for that Grandparent, and the corresponding Parent IDs. The privilege escalation issue could then be reused to create arbitrary administrator Child accounts in any Parent of the Grandparent.

The end user could effectively take over other Parent entities preauth. The data at play here was incredibly sensitive.

Account Takeover

This issue arised from the endpoint that generated links that could be sent to Child entities for them to authenticate with. However, a weak JWT secret meant that the token could be compromised. Account takeover was possible by modifying the Child ID within the token.

Grandparent Generation

There was an issue in account creation that allowed the user to create Grandparent entities without the company's approval.

Information Disclosure

The private program's Grandparent ID was leaking in both the company's official Github within the commit history, and in a Javascript file used in the main web application. Chained with the earlier issues, they could be used to create admin accounts in the private program's own Parent entities.

Default Endpoint Behaviour

Removing the Parent ID value from a specific endpoint caused the API to return an arbitrary (production) customer's Parent ID. I was able to leverage this Parent ID to get both the API key and critical PII from the Parent through various API endpoints.

The Parent entity had a dashboard that was used to manage the Parent. Within this dashboard, it was possible to send a link to someone externally, who would have limited access and only be able to access certain features. This is a common role-based access control method in SaaS. However, by reusing the cookies of the limited-access user with the API rather than the dashboard, it was possible to retrieve the API key to perform almost any high-privilege action.

Conclusion

APIs do not always behave consistently. By understanding exactly how a web application works, and understanding the significance of each component in relation to other components, it is possible to uncover a wide variety of issues.