siunam's Website

My personal website

Home Writeups Blog Projects About E-Portfolio

Finding and exploiting an unused API endpoint | May 10, 2024

Table of Contents

  1. Overview
  2. Background
  3. Enumeration
  4. Exploitation
  5. Conclusion

Overview

Welcome to my another writeup! In this Portswigger Labs lab, you’ll learn: Finding and exploiting an unused API endpoint! Without further ado, let’s dive in.

Background

To solve the lab, exploit a hidden API endpoint to buy a Lightweight l33t Leather Jacket. You can log in to your own account using the following credentials: wiener:peter.

Enumeration

Home page:

In here, we can purchase some products.

We can also go to “My account” to login as user wiener:

As for API testing, we can also gather a lot of information by browsing applications that use the API. This is often worth doing even if we have access to API documentation, as sometimes documentation may be inaccurate or out of date.

We can use Burp Scanner to crawl the application, then manually investigate interesting attack surface using Burp’s browser.

While browsing the application, look for patterns that suggest API endpoints in the URL structure, such as /api/. Also look out for JavaScript files. These can contain references to API endpoints that you haven’t triggered directly via the web browser. Burp Scanner automatically extracts some endpoints during crawls, but for a more heavyweight extraction, use the JS Link Finder BApp. You can also manually review JavaScript files in Burp.

When we first visit this web application, we can see that there’s a JavaScript file has been loaded at /resources/js/api/productPrice.js:

In this JavaScript file, we can see that it fetches an API endpoint to get a product’s price:

[...]
const loadPricing = (productId) => {
    const url = new URL(location);
    fetch(`//${url.host}/api/products/${encodeURIComponent(productId)}/price`)
        .then(res => res.json())
        .then(handleResponse(getAddToCartForm()));
};
[...]

That being said, the API endpoint is at /api/products/<productId>/price.

Exploitation

Once we’ve identified API endpoints, interact with them using Burp Repeater and Burp Intruder. This enables us to observe the API’s behavior and discover additional attack surface. For example, we could investigate how the API responds to changing the HTTP method and media type.

As we interact with the API endpoints, review error messages and other responses closely. Sometimes these include information that we can use to construct a valid HTTP request.

The HTTP method specifies the action to be performed on a resource. For example:

An API endpoint may support different HTTP methods. It’s therefore important to test all potential methods when we’re investigating API endpoints. This may enable us to identify additional endpoint functionality, opening up more attack surface.

For example, the endpoint /api/tasks may support the following methods:

Note:

When testing different HTTP methods, target low-priority objects. This helps make sure that you avoid unintended consequences, for example altering critical items or creating excessive records.

Let’s try to retrieve the price of a product by sending a GET request to the API endpoint /api/products/<productId>/price!

As you can see, it returned product ID 2’s price and its message!

Hmm… What if the API endpoint accept PATCH method to modify the price? Or using DELETE method to delete the price?

Let’s try modifying product ID 2’s price!

Based on the result of GET request /api/products/2/price, the current price is $66.91.

Now we can try to use PATCH method to modify the price:

Oh… HTTP status code 400 Bad Request? Looks like we’re missing some data and the data format.

API endpoints often expect data in a specific format. They may therefore behave differently depending on the content type of the data provided in a request. Changing the content type may enable us to:

To change the content type, modify the Content-Type header, then reformat the request body accordingly. We can use the Content type converter BApp to automatically convert data submitted within requests between XML and JSON.

That being said, we can add the Content-Type request header with value application/json and Content-Length based on the PATCH method error respond:

As you can see, we now triggered HTTP status code 500 Internal Server Error. This is because we didn’t provide any JSON data.

Let’s try providing an empty JSON object:

Now, it’s telling us we need a price parameter in the JSON object!

If we’re trying to modify product ID 2’s price, we can construct the following JSON data:

{"price": 49}

Oh! Now it returned price 0.49!

Hmm… What if the price is 0?

It sets the price to 0!

If we send a GET request to /api/products/2/price, it’ll show us the price is now 0!

That being said, we can purchase any products by modifying its price via API endpoint /api/products/<productId>/price with PATCH method!

Let’s modify the product “Lightweight “l33t” Leather Jacket”’s price to 0!!

By inspecting the product’s link, the product ID is 1:

Now we can set its price to 0:

Let’s go buy it!!

Conclusion

What we’ve learned:

  1. Finding and exploiting an unused API endpoint