Recently, I have been studying and enhancing my knowledge of API security, and throughout this journey, I have come across OWASP’s recommendations. These recommendations have led me to want to understand practically how the main vulnerabilities found in APIs can be exploited. To this end, some applications intentionally simulate these gaps, exposing in practice what these risks can lead to by not implementing basic controls and not following good security practices.

In this article, we will document the entire exploration journey of 10 exercises that demonstrate the main vulnerabilities reported by OWASP. To achieve this, we will use a testing API called vAPI.

vAPI is Vulnerable Adversely Programmed Interface which is Self-Hostable API that mimics OWASP API Top 10 scenarios in the means of Exercises.

Link to the official page: vAPI - http://vapi.apisec.ai/

For educational purposes, no flags will be disclosed through the walkthrough. The goal is to guide and show each step, encouraging you to follow all the steps and discover through practice.

I recommend that before each exercise, you consult the item directly on the OWASP page to understand the entire scenario and the risk of the exercise to be studied in that specific context.

Link to OWASP API Security: OWASP API Security - https://owasp.org/API-Security/

Let’s get started on the walkthrough!


API1:2019 - Broken Object Level Authorization

You can register yourself as a User , Thats it ….or is there something more?

In the first exercise, following the hint provided in the documentation, we will create a new user by following the instructions described in the API’s documentation itself. 

Navigate to the API1 > Create User item, and copy the payload presented on the right side to use as a template:

image-title-here

Using Postman, let’s create a new user following the example copied:

image-title-here

The response must be presented as shown in the following image:

image-title-here

We can now verify the information of the new user. To do so, we will only need the user’s id and an Authorization-Token, which can be generated using the following command:

echo -n "rod:P@ssw0rd" | base64

Copy and paste the output:

image-title-here

Update the user’s id to be queried in the first tab:

image-title-here

The response should be as per the following output:

image-title-here

Now, what can happen if we use the same token but any other id:

image-title-here

It looks like we successfully got our first flag ;)

We can go further and try to abuse this flow by taking advantage of the user update privilege. First, let’s check the user data id 2:

image-title-here

We’ll try updating the course and password for the account with id 2 using the token generated from id 9. We’ll accomplish this using the PUT method. Remember to adjust the parameter to id 2, include the Authorization-Token, and provide the necessary body:

image-title-here

The expected response is an HTTP 200 in this case with the following content in its body:

image-title-here

Let’s check if the data was updated successfully?

image-title-here

Yup, the data was updated successfully, it seems that the API and its controls do not correctly validate permissions when returning data, allowing data query and update permission from any user registered in the database.


API2:2019 - Broken User Authentication

We don’t seem to have credentials for this, How do we login? (There’s something in the Resources Folder given to you)

In this exercise we will need to use a resource previously and intentionally left in the Resources/API2_CredentialStuffing directory called creds.csv We will need to put these pieces together for a brute-force attack:

image-title-here

To confirm our theory, let’s set up the proxy on Postman to intercept all requests using Burp.

On Postman, go to Settings > Proxy and change your settings as shown in the image below:

image-title-here

Now we can view all requests made in Postman through Burp, as well as responses:

image-title-here

On the first try we got an unauthorized response, let’s now put the pieces together and test each email and password from the creds.csv file. Click on the request in Burp and send it to Intruder. Adjust the Attack type to Pitchfork since we will be using multiple payloads and mark the payloads in the body as shown in the image below:

image-title-here

Open the file and copy only the first values before the comma, which in this case are the email addresses. Click on Payloads and paste all emails.

image-title-here

Do the same with the values after the comma, however, this time we will configure it as payload 2 as passwords, copy and paste:

image-title-here

Don’t forget to uncheck the Payload encoding option for both payloads; we won’t be using it in this case. Next, click on Start attack.

image-title-here

To make it easier to view, sort by Status code, and the first results with http status code 200 are users and passwords that were successfully validated. Let’s run a test to validate the results. Go back to Postman and now, using the Get Details endpoint, fill in using the discovered information.

image-title-here

It looks like we have one more flag as per the JSON response.


API3:2019 - Excessive Data Exposure

We have all been there , right? Giving away too much data and the Dev showing it. Try the Android App in the Resources folder

On the next exercise, we will need to use a resource located in the directory Resources/API3_APK called TheCommentApp.apk. However, this time, we will also need additional resources and a mobile device.

Don’t worry, I have prepared an article on how to install and configure these resources using an emulator device.

How to route your traffic through (Burp Suite) from a mobile emulator (Android-x86)

After having the environment ready, you only need to install the APK and run it for the first time, during the first execution you will be asked for the configuration URL which in our example can be used as follows:

image-title-here

After clicking Save, the login screen will be presented as follows:

image-title-here

As we don’t have any accounts yet, let’s click on Create Account:

image-title-here

Click Register and now is the time to test the new account created:

image-title-here

Authentication completed successfully:

image-title-here

Let’s go back to Burp to check the requests. Right after the login, we notice that the response for the next request has more information than we need. Although the app shows just one comment, the Proxy reveals that many other details were returned.

image-title-here

This includes our third flag!


API4:2019 - Lack of Resources & Rate Limiting

We believe OTPs are a great way of authenticating users and secure too if implemented correctly!

For the next exercise we have 3 endpoints available, the first one only requires a mobile number as follows:

image-title-here

As observed in the response, a token containing 4 digits is sent to the mobile number. However, since we don’t have the sent code, we can use the next endpoint to check and try to guess the code, as the resource does not prevent or restrict the number of attempts.

image-title-here

This time, we will use wfuzz to try to discover the code. First, we need to generate a list of possible combinations using crunch to create a list of OTPs from 0000 to 9999.

crunch 4 4 0123456789 >> otps.txt

Then, we have to perform a test for each of the values generated on the endpoint using a brute-force attack:

wfuzz -d '{"otp":"FUZZ"}' -H 'Content-Type: application/json' \
-z file,otps.txt -u http://127.0.0.1/vapi/api4/otp/verify --hc 403

Once the correct value is found, we can abort the execution:

image-title-here

Now we can test the value using Postman to obtain our Authorization-Token:

image-title-here

Move on to the third and final endpoint to validate our Authorization-Token:

image-title-here

The key was successfully validated, resulting in another flag!


API5:2019 - Broken Function Level Authorization

You can register yourself as a User. Thats it or is there something more? (I heard admin logins often but uses different route)

In this exercise, through the tip above it is possible to understand that there are other undocumented routes or endpoints, for this we will need to use the brute-force technique. 

In our example, we will use a tool created by a friend of mine that can be found at the link:

Turbo Search - https://github.com/helviojunior/turbosearch

The tool is well-documented and can be used in our case using the command and parameters below:

./turbosearch.py -w endpoints.txt -t http://127.0.0.1/vapi/api5/ \
--ignore-result 403

The file endpoints.txt contains possible directories or paths. We will test each of them to discover if they are validated or not. I recommend creating and maintaining your own custom dictionary for each objective. Several examples can be found on the internet.

image-title-here

It looks like there is a users path, let’s investigate through Postman:

image-title-here

It seems we will need access credentials. Let’s create a user using the path and payload recommended in the documentation.

image-title-here

Let’s test using the same previous technique to generate the Authorization-Token, basically combining the username and password in base64:

echo -n "testuser2:test123" | base64

Don’t forget to set the api5_id parameter followed by the id of the new user:

image-title-here

What would happen if we use the same token that we used before against the undocumented path users?

image-title-here

We got it, another flag was successfully captured!


API6:2019 - Mass Assignment

Welcome to our store , We will give you credits if you behave nicely. Our credit management is super secure

In the next exercise we can see that we will somehow play with credits, first, we will create a new account following the documentation:

image-title-here

There is nothing new here. Let’s proceed and use the GET method to validate our new user. But first, don’t forget to create the Authorization-Token in the same way we did in previous exercises.

echo -n "rod:P@ssw0rd" | base64

The answer should be as shown in the image below:

image-title-here

A new attribute called credit was not initially included but was later assigned in the backend. What might happen if we add this new attribute along with a credit to the payload when creating an account? Even though it has not been specified in the documentation and is not mandatory, it is worth testing.

image-title-here

From the response we can assume that the payload was accepted, let’s validate the user, and don’t forget to generate the token according to the new credentials:

image-title-here

Okay, another flag was captured, along with good credit to our account!


API7:2019 - Security Misconfiguration

Hey , its an API right? so we ARE expecting Cross Origin Requests . We just hope it works fine.

For the next exercise we will need to interact with an attribute in the request called Origin, but first, let’s create a new user:

image-title-here

Next, we will test the new account, don’t forget to generate the Authorization-Token according to the previous exercises in base64:

image-title-here

Adjust the proxy in Postman’s settings, capture the request and send it to Repeater, finally just add a new attribute as shown in the image below Origin: Any Domain:

image-title-here

Done! We have successfully captured another flag!


API8:2019 - Injection

I think you won’t get credentials for this. You can try to login though.

In the next exercise, we will follow the instructions given in the documentation and attempt to log in:

image-title-here

As expected, since we don’t have any users, we got an access denied message. As this is an injection exercise, we will test some hypotheses and check the API’s return using different payloads.

We can send a single quote to force an error that leads us to signs of use of a database:

image-title-here

In this case, when using a single quote in the login, we received an error that guided us in the right direction. Now, let’s adjust the payload to make the application assume that the login was legitim.

image-title-here

After getting the authkey we can now proceed to the next endpoint:

image-title-here

Another flag was successfully captured!


API9:2019 - Improper Assets Management

Hey Good News!!!!! We just launched our v2 API :)

In this next exercise, we can see that it is a login path and after running some preliminary tests nothing was returned despite the status 200:

image-title-here

In the response we can also see that a rate limit was implemented, which will limit us to a brute-force attack:

image-title-here

We can see that after 5 consecutive attempts, we started receiving a 500 error:

image-title-here

We can try different approaches. The first would be to try to measure the duration of the blocks and check if it is feasible to perform 5 attempts and wait for the interval before proceeding. However, this still limits our testing capacity and can take a long time. 

Alternatively, we can search and try to find out if the previous version of this API is still available. Since the current path shows v2, let’s try v1 and see if it’s still accessible:

image-title-here

In this case, all we had to do was change our path from v2 to v1. We noticed that in the previous version, the rate limit method and control had not been implemented.

We will use the same file used in exercise 4, otps.txt with an attack carried out through wfuzz:

wfuzz -d '{"username":"richardbranson","pin":"FUZZ"}' \
-H 'Content-Type: application/json' -z file,otps.txt \
-u http://127.0.0.1/vapi/api9/v1/user/login --hw 0

Once the correct value is found, we can abort the execution:

image-title-here

Now that we have the pin, we can confirm it using the second available endpoint:

image-title-here

We can test the correct pin on API v1 or v2, and the result will be the same. Another flag was captured!


API10:2019 - Insufficient Logging & Monitoring

Nothing has been logged or monitored , You caught us :( !

In this next and final exercise, nothing is being monitored and the application does not record any activity. This way, the attack does not require anything complex and is just for demonstration:

image-title-here

Finally, the last flag was successfully captured!

If you have followed all the steps and have made it this far, congratulations on completing all the exercises. If any of them were unclear, feel free to leave a comment or redo the exercise while carefully reading about the type of attack on the official OWASP page and try your best to understand the examples.

Last but not least, remember to practice and keep up the good work!