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 obscurity, 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.
This issue arose 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 and re-signing.
Grandparent Entity Creation
There was an issue in the account creation process that allowed the user to create Grandparent entities without the company’s prior approval.
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.
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.
Part 2: Update, Jan 2023
Secondary context path traversal, pioneered by Sam Curry, is another uncommmon issue that occurs in APIs. It can be found when user input is insufficiently sanitised, and sent to a proxy. The proxy appends this value to a path, such as an internal API route, and the user is able to traverse this to perform unintended actions. Due to insufficient obscurity (in my opinion), I have taken down Part 2. Instead I will outline what was possible on that target in general terms.
- It was possible to switch virtual hosts using a parameter in the request body.
- From this point, the attacker could specify an API route in another parameter.
- This parameter could be leaked by putting it in an unexpected place to trigger an error, leaking the entire absolute path of the API route.
- Since a similar system was used for proxy headers, we were able to leak internal proxy authentication headers back to us, the client.
- We could bypass existing protections by specifying one route, then traversing upwards to move to another route using our knowledge of leaked paths. This meant that even if a particular API route was disabled from the wider internet, we could still manipulate the proxy to access it.
All in all, it was technically fantastic to hack on and while I wish I could describe it properly, this is all I can do for now.