APIs (Application Programming Interfaces) enable software systems and applications to communicate and share data. API testing is important as vulnerabilities in APIs may undermine core aspects of a website’s confidentiality, integrity, and availability. Let dive into this lab dummy walkthrough :)

Exploiting an API endpoint using documentation

Objective: To solve the lab, find the exposed API documentation and delete user carlos. You can log in to your own account using the following credentials: wiener:peter.

Login in as user wiener and sending a request to burp we have this :

We can then start to look for common API endpoints like the following. You can also try to fuzz for the API endpoints using the following wordlist here.

  • /api
  • /swagger/index.html
  • /openapi.json

Fortunately for me i was able to discover the API endpoint by just making a GET request to /api without fuzzing which returned the API documentation.

I then made a GET request to retrieve series of account information trying out usernames we have at hand

[User => Wiener]

[User => Carlos]

[User => Administrator ]

We can also change the email of a particular user take for example user wiener by using the PATCH request method together with an provided data in JSON format.

  • Change request method to POST using burp functionality then manually change POST header to PATCH method.
  • Change content-type to application/json
  • Then use the JSON format to send the data.

We can then finally delete the user carlos as requested by changing request method to GET and then changing GET to DELETE manually

Finding and exploiting an unused API endpoint

Objective: 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.

As said by the objective we need to first of all add the item to cart

After moving this item to cart and login in with the given credentials we cannot purchase this item cos’ we have insufficient funds

Since i am using burp pro we need to setup jython in other to be able to download some extensions that need this. Download the first file from the given link and import it to burpsuite as shown below in the BApp store.

We then need to download two burp extensions by navigating to the burp extender tab :

  1. We can use the JS Link Finder BApp to crawl endpoints for sensitive files containing API information.
  2. We can use the Content type converter BApp to automatically convert data submitted within requests between XML and JSON.

Once downloaded we are good to go, Navigate to Targets > Site map, then click on the targets and select Engagements tools > Find scripts

This would pull up all scripts and we can try to see if there are any scripts literally related/can serve as a documentation for the API endpoint.

Sending this to the repeater tab and checking the response we finally found an API endpoint in the following format : ${url.host}/api/products/${encodeURIComponent(productId)}/price

We can also attempt to find this hidden API endpoints by crawling the site using burp suite pro feature which should give you the API endpoints

[API Endpoint Discovered]

Sending this requests to my repeater tab i noticed that the items are judged by their product ID which returns the price for that particular product.

Changing product ID to 1 we can see the price for the “Lightweight “l33t” Leather Jacket” item

Since there is typically no way to alter our own amount in our wallet we can actually alter the amount of the product changing it to $0.00 🤣.

Go ahead and right click then select Extensions > Content Type Converter > Convert to JSON, this should change the request method to POST and also add a content-type value to the request

As shown below we get the error “Method not allowed”, well we can use the PATCH request method also as this is accepted by most APIs

This successfully changes the price to $0.00

Then sending a GET request we can see that the product price has been changed to $0.00, sweet. Note that if you get the “Unauthorized” message then login as user wiener first before doing all of this (if possible you just need the new session key).

Navigating back to the website we can see that we have successfully reduced the price of this product and can add it to cart now.

You should be able to solve the lab now by purchasing the item.

Exploiting a mass assignment vulnerability

Objective: To solve the lab, find and exploit a mass assignment vulnerability to buy a Lightweight l33t Leather Jacket. You can log in to your own account using the following credentials: wiener:peter.

This vulnerability exists do to the fact that -:

  • the application supporting parameters that were never intended to be processed by the developer.
  • For example, if a PATCH request is made to /api/users/
  • that allows users to update their data with the following result;
{
    "username": "wiener",
    "email": "[email protected]",
}

A concurrent GET /api/users/123 request returns the following JSON data:

{
    "id": 123,
    "name": "John Doe",
    "email": "[email protected]",
    "isAdmin": "false"
}

This shows that the hidden id and isAdmin parameters are bound to the internal user object, alongside the updated username and email parameters.

An attacker can then send a PATCH request with the isAdmin parameter value set to true ;

{
    "username": "wiener",
    "email": "[email protected]",
    "isAdmin": true,
}

For the lab we need to download the Param miner BApp which guesses up to 65,536 param names per request, based on information taken from the scope. I won’t be using this though. but it is worth downloading. You can go ahead and the item to cart as requested. (Don’t forget to login as user wiener)

Then intercept the request with burpsuite

I noticed that after adding the item to cart an API request is made to /api/checkout as shown in the above screenshot.

Forwarding this request to the repeater tab, the response is a JSON data which contains the information about the present item we have in our cart

Decided to check other request method accepted by this endpoint and as shown below it only accepts POST and GET request methods.

So i decided to alter the request first of, by changing the request method to POST (Change request method), Then i used the Content type converter extension we used in the last challenge to change request body to JSON, then copied the whole JSON data we got from the response to our request tab.

Altering the item_price value to 0, nothing changes because we do not have that certain permission to do so as we can see below we are still getting the INSUFFICIENT_FUNDS error.

Then i decided to alter the percentage discount value giving our self an 100% discount

$$ \text{Discount Percentage} = \left( \frac{1337 - 0}{1337} \right) \times 100 = 100% $$

We should now have the lab solved.

Exploiting server-side parameter pollution in a query string

  • Query syntax characters like #&, and = can be used to test for this vulnerability
  • An attacker can then observe how the application responds.
  • It is also crucial to URL-encode this characters.
    • Otherwise the front-end application will interpret it as a fragment identifier and it won’t be passed to the internal API.

Objective: To solve the lab, log in as the administrator and delete carlos.

First of all we start by intercepting the login page cos’ we have not been given a username neither a password.

We can then provide wrong credentials and intercept, sending the request to the repeater tab

After several enumeration figured out there is probably no way in the previous endpoint and started to focus on the /forgot-password endpoint

adding a parameter with the URL encoded character of & as %26, i figured out that the extra username parameter is not been read at all so specifying wrong input in the first parameter leads to an “Invalid Username” error

Mean while reversing the case as shown below we have a valid response

Then i decided to move a step further by adding the # encoded character %23 to the end of the query and we have the error “Field not specified

Then decided to bruteforce this parameter by sending this to the intruder tab and selecting the second parameter as this position point for this attack. The major reason for doing this is because there is an hidden parameter which could be altered if we know it.

Then navigate to Payloads > Payload Options [Simple list] > Add from list and select “Server-side variable names” as the wordlist.

Start the attack and as shown below the length of the response from the “field” parameter is SUS

Changing the field value to username we can see that there is a change in the output.

Using burp pro crawling feature i was able to find the /static/js/forgotPassword.js endpoint with the following hidden reset_token parameter

forgotPwdReady(() => {
    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString);
    const resetToken = urlParams.get('reset-token');
    if (resetToken)
    {
        window.location.href = `/forgot-password?reset_token=${resetToken}`;
    }
    else
    {
        const forgotPasswordBtn = document.getElementById("forgot-password-btn");
        forgotPasswordBtn.addEventListener("click", displayMsg);
    }

Parsing the resest_token parameter as a value to the field variable, we have a reset token.

Copied this reset token and went over to the URL specified in the JS file /forgot-password?reset_token=${resetToken} specifying the reset token given which referred me to a page to reset the administrator password “admin:admin

Successfully logged in as administrator and deleted the user carlos to complete the challenge

Exploiting server-side parameter pollution in a REST URL

Objective: To solve the lab, log in as the administrator and delete carlos.

  • REST APIs may place parameter names and values in URL path, rather than the query string.

  • For example requests are made to the following endpoint as:

    GET /edit_profile.php?name=peter
    
  • This results in the following server-side request:

GET /api/private/users/peter

Just as mentioned in the academy section of this challenge we have to combine path traversal sequences to modify parameters and observe how the application responds.

First of we start by traversing twice and seeing if this application is truly vulnerable as shown below.

Again i tried to guess the users path by traversing 3 times which worked as shown below meaning there is correct path like ../../../users/carlos

Took it a step further again by guessing the field variable just as used in the previous challenge and we could actually read the email field correctly.

username=administrator..%2f..%2f..%2fusers%2fcarlos%2ffield%2femail%23

Just to be sure this parameter actually exists i decided to change the field value to username instead and got the below error talk about the API version.

Starting to research i came across this blog talking about API versioning and discovered we can traverse 4 times and then start our query with a encoded /v1.... which worked.

administrator..%2f..%2f..%2f..%2fv1%2fusers%2fcarlos%2ffield%2fusername%23

Now we need to find the hidden parameter for the password reset token. I started to look up JS files by using the crawl feature of burpsuite as used in other challenges and came across a JS file located at /static/js/forgotPassword.js which revealed the hidden parameter (passwordResetToken)

forgotPwdReady(() => {
    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString);
    const resetToken = urlParams.get('reset-token');
    if (resetToken)
    {
        window.location.href = `/forgot-password?passwordResetToken=${resetToken}`;
    }
    else
    {
        const forgotPasswordBtn = document.getElementById("forgot-password-btn");
        forgotPasswordBtn.addEventListener("click", displayMsg);
    }
});

Made a request and this was successful as expected we got the reset token value. administrator..%2f..%2f..%2f..%2fv1%2fusers%2fadministrator%2ffield%2fpasswordResetToken%23

We can place this value in the following parameter on your browser /forgot-password?passwordResetToken=${resetToken}, which should give you access to a password reset page.

Then we can login as user administrator and delete the user carlos as requested.

Resources