Note : All the testing performed on the company mentioned here was done legally and on the consent of the company . All the information here was only shared once the bug was officially disclosed .
There is a lot of discussion about security in Web 2.0, particularly concerning classic security flaws like XSS, SSRF, SQL injection, and more. If you are already well-versed in these topics, this blog might not be particularly interesting to you. However, I suggest reading it as it provides insights into hacking APIs like a pro, potentially profiting through penetration testing or bug bounties. API security largely falls under the developer’s control. Despite stringent security measures at the business logic level, it’s easy to overlook minor issues that can have a significant impact. In this blog, we will discuss some API-related security flaws I encountered during testing, which resulted in a total reward of $10,000.
Plugging in Extra parameter
During the security testing of the API, we review the API documentation. For POST and PUT requests, where the client needs to send data to the server, the fields are often correctly documented. However, in the actual application, there may be insufficient validation checks for the fields that need to be addressed. Below is an example of the JSON body that needs to be sent in the API for updating the user.
{
"username" : "bishesh",
"address" : "3363 Andell Road",
"....": .....
}
As seen here, consider that the application doesn’t allow updating the email from the UI, or the system doesn’t even consider the email as an update factor. From a black-box perspective, we have no insight into how the backend handles the parameters. There might be no checks for the incoming data, and the incoming values could be directly passed into the service or database transaction when updating user details, thus potentially updating the email address. Let’s look at this example:
Bad Practice :
async updateUser(updateUserArgs) {
return await this.mockDatabase.user.update({
where : { id : id},
data : {...updateUserArgs}
})}
Good Practice:
async updateUser(validatedUserArgs) {
/*
validatedUserArgs should be something like this
{ username:string; address:string}
*/
return await this.mockDatabase.user.update({
where : {id : id},
data : {...validatedUserArgs}
})}
In this example of bad practice, you can see that the data is directly sent to the service layer (the database query execution layer) instead of being properly selected or filtered. This might seem like a vague example, but consider a fast-paced development scenario where the developer might overlook such issues. These seemingly minor oversights can be catastrophic.
While looking for security flaws, I found a similar issue in Reddit’s ads platform. Like most ad platforms, users can create campaigns and ads, but the process is only completed once the ads are approved by the internal team. Reddit has a similar feature where the internal team reviews the ad and account before approval. However, due to a flaw in the API, I was able to bypass this check and approve my ads from my account. Analyzing the API requests, I saw the admin approval field in the response. By sending this field to the backend, I could inject the value “admin_approval” and set it to “true,” which was not documented in the API.
{
...
"ADMIN_APPROVAL": "APPROVED"
}
The admin approval field was not properly filtered, allowing me to update its value due to missing checks and validations in the backend. As a result, I was able to get my ad approved. Although the bug was simple and easy to exploit, it affected the permission model of the ads platform. Therefore, it was triaged as High severity and compensated accordingly.
Improper authorization
I discovered a similar flaw in Reddit’s ads platform, combining two issues to exploit the bug. Reddit’s collaboration feature allows admins to invite new emails, which can only accept the invite after verifying the email. Proper checks prevented unverified emails from accepting invites. However, I found an API endpoint showing the email field in the response for ad settings. Assuming missing checks, I added a new email to the request. Reddit didn’t allow email updates from the frontend and had no API for it, but during ad settings updates, it didn’t validate fields properly, causing the email to update and auto-verify. This let me verify any email and accept invites sent to it, including admin emails, hijacking invitations. This bug was also triaged and paid as High severity.
Key Takeways
Let’s discuss the thought process of a hacker attacking APIs. APIs are the easiest place to find bugs but also the most creative. APIs behave differently based on the application, so before legally attacking an application’s API, ensure you understand the application thoroughly. Use the application in every possible way. Instead of just black-box testing, having a basic idea of the application’s inner workings can help you filter out many fuzzing points. This is crucial for bug hunters due to the high competition and the fact that you’re often testing applications made by top engineers. It’s important to fuzz extensively, look for edge case logic, and exploit even non-security bugs, as they can sometimes combine to create security vulnerabilities. Focus on attacking the core business model of the application, as this can have a massive impact on the organization.
I am marking this as the end of this blog . I am gonna come up with more parts of hacking APIs with more tips and tricks along with other findings and other attack vectors and bug types . Do share if you like this blog ! Happy hacking …
Leave a Reply