In modern web applications, almost all functionality offered to users is handled by an Application Programming Interface or API for short.

To help visualize how this works, think of a website like a coloring book, where all the borders and shapes are defined when you access it. However, in most cases, the website’s API actually “colors in” each region with data.

For example, consider the “Grocery Tracker Online” website below:

You can see that there are borders, shapes, and sections defined by the source code of the website. These are empty since an API has not been used by the client to fill in data.

Next, let’s see what happens when an API is used to populate data within these regions:

We can see that each section has been filled with data served by the API. We are also currently logged in as a user named “Ken Thompson”. This user has rights to view the current status of shipments of apples, broccoli, and milk, and can view a listing of site content. Additionally, a news feed is now populated on the right-hand side of the website.

Each of these data points has been populated by the API.

Let’s assume that our API’s URL is “API.grocerytrackeronline12345.com”, we can say that the following API routes were used to handle the population of this data:

  • API.grocerytrackeronline12345.com/api/v1.0/users/145
    •  Used to populate the “Ken Thompson” user data
  • API.grocerytrackeronline12345.com/api/v1.0/shipments/5685
  • API.grocerytrackeronline12345.com/api/v1.0/shipments/5646
  • API.grocerytrackeronline12345.com/api/v1.0/shipments/5335
    • Requests used to gather shipment information
  • API.grocerytrackeronline12345.com/api/v1.0/content/active
    • Used to populate the “Site Content” section with active grocery items
  • API.grocerytrackeronline12345.com/api/v1.0/news/all
    • Used to populate the “News” section with current news items.

 

Thus, we can see how a series of individual API “methods” or “routes” were used to fetch data to populate each relevant section of the website.

APIs are not just limited to handling data within an application. Commonly, developers will write a series of methods for user authentication, user management and modification, modification of data in the application, or the ability to interact with functionality provided by the application.

Each of these “methods” served by an API can be exploited by an attacker. Let’s look at how this typically occurs in more detail.

Insecure Direct Object References (IDOR)

When implementing the architecture of a web application, it’s useful to classify information with identifiers. Developers need to be able to group pieces of information. After all, how else will they know what info to provide users?

Take for example the API method we found used to populate the “Ken Thompson” user’s info earlier:

You might have noticed the “145” portion of the route. In the case of our Grocery Tracker Online application, we can assume that this is an identifier tied to the “Ken Thompson” user’s identity. In fact, even if you aren’t familiar with web applications, you probably deduced this anyway.

This leads us to the concept of Insecure Direct Object References (IDOR). Let’s take on the mindset of an attacker who wants to abuse our web application. We’ve observed that “145” is a user identifier; why don’t we try to replace this value with something else?

We replaced the “145” value with an alternate value of “1”. In the response, we can now see that the alternate “Dennis Ritchie” user’s information has been returned to us, including their credit card information!

This might seem simple and unrealistic, but IDOR attacks in the wild can very much resemble this approach. When issues like this exist within an API, attackers may script thousands of requests to quickly “farm” user data from the vulnerable route.

Excessive Data Exposure

Let’s say our attacker is not satisfied with the previous IDOR vulnerability they found, and instead is interested in the shipment information contained within our grocery tracker website. This brings us to another common API issue that is experienced quite often when interacting with environments, excessive data exposure.

We’ll focus on the “/api/v1.0/shipments/5685” route we documented earlier that was used to populate information on shipments of apples:

We want to gather as much of this information as possible. Let’s assume that we’ve tried to change the “5685” parameter to other values, but the API properly controls this information and only lets us view data tied to our account. How else might we abuse this route and gather more information?

What happens if we instead issue a request to the “/api/v1.0/shipments” API route?

Wow! It looks like the developers did not anticipate a user performing this activity, and this route exposes all records for each shipment. From this one request, we now have the entire registry of information in a single response. As an attacker, we are very happy.

This may seem insignificant within the context of our example. After all, how is someone going to harm me with the knowledge of when lettuce will be delivered next?

Consider this attack however in the context of an API that processes financial information. What would the impact be in that case? What about an application used to track medical documentation?

You may now be piecing together the impact of such a vulnerability within an API.

Broken Function Level Authorization

This exploit category refers to conditions where users can access API endpoints that are assumed to only be accessible by administrative or high-privilege users. While this may sound similar to the IDOR exploits we discussed earlier, it is a separate, unique issue.

For example, we found that user information is served through the following route:

/api/v1.0/users/:userid

However, let’s assume that the developers of our Grocery Tracker Online application wanted to implement a route that could be easily used by administrators to view all the users within the application:

/api/v1.0/admin/users

There’s one issue. They did not implement access controls on this route properly, which allows any low-privilege user to issue a GET request to the route:

We now have an easy way to quickly gather every single user’s information, again, including their credit card information!

This is what constitutes a Broken Function Level Authorization vulnerability. It can often lead to detrimental implications within applications depending on what functionality has been implemented through an API.

Renegade Labs has experienced abusing Broken Function Level Authorization vulnerabilities to impersonate alternate users, escalate privileges, and disclose sensitive information in live applications.

Frequently, it is possible to discover these vulnerable administrative routes by reverse engineering JavaScript source code. In other cases, naming conventions simply give these routes away.

So What Can You Do?

API security vulnerabilities almost always stem from a failure to properly control access to endpoints.

Organizations looking to get ahead of issues that may be identified by a penetration test (or an attacker) should prioritize performing access control reviews of each API endpoint from the perspective of each role within the application. This should also include testing each route without authenticating at all!

Ideally, this will allow your team to preemptively detect cracks that may have been overlooked during the development process. Make sure to safely test multiple HTTP methods as well.

Additionally, utilization of complex GUID identifiers within the API specification will allow you to give attackers headaches as they try to reverse engineer your routes. For example, which of the following API specifications would you rather target as a malicious attacker?

While this may not be a feasible change to implement depending on the development lifecycle of your application, it is worth considering.

Lastly (you probably saw this one coming), pursue performing regular penetration testing on applications and their APIs to help identify anything that might have been overlooked during development or testing processes.