Page cover

VAmPI

SUMMARY

VAmPI is an educational vulnerable API created by erev0s that includes vulnerabilities from the OWASP top 10 for APIs (2019). The API features an application where users can register and then login to post books. For any book the data accepted are the title and a secret about that book. Each book is unique for every user and only the owner of the book should be allowed to view the secret.

According to the documentation, the vulnerabilities contained in the source code are the following:

  1. SQLi Injection.

  2. Unauthorized password change.

  3. BOLA (Broken Object Level Authorization).

  4. Mass assignment.

  5. Excessive data exposure through debug endpoint.

  6. User and password enumeration.

  7. RegexDOS (Denial of Service).

  8. Lack of resources & rate limiting.

  9. JWT authentication bypass via weak signing key.

The exercise can be solved using Burpsuite, Postman or Curl. Since we have already used the first two ones in crAPI and vAPI respectively, we will use Curl this time for the sake of learning and trying different tools.

KEYWORDS

API, OWASP top 10 API, Curl, SQLi, SQLmap, BOLA, mass assignment, user enumeration, RegexDOS, evil regex, JWT vulnerabilities.

REFERENCES

https://github.com/erev0s/VAmPI

https://erev0s.com/blog/vampi-vulnerable-api-security-testing/

https://owasp.org/API-Security/editions/2019/en/0x11-t10/

https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS

https://devina.io/redos-checker

https://book.hacktricks.wiki/en/pentesting-web/regular-expression-denial-of-service-redos.html

INSTALLATION

Download the Docker image.

And run a container based on the image. Normally, VAmPI is designed to listen on port 5000, but in this case I used port 8011 because my local lab already has port 5000 in use.

The Swagger UI documentation site is now accessible on port 8011.

Let's try querying the welcome endpoint.

ENUMERATION

Port scan.

Before start attacking the API, we are advised to populate the database with dummy data, this is done by sending a GET request to the /createdb endpoint.

And we also need to register a new user in the /users/v1/register endpoint

We can now log in and get a token.

We are ready to start enumerating the vulnerabilities indicated by the author.

SQL INJECTION

The vulnerability is located in the file models/user_model.py

The user input is used to create and execute an SQL request without sanitization.

This vulnerability affects the endpoint users/v1/{username}. To confirm the vulnerability we will use a basic SQLi payload.

The application returns an error, but inspecting the output carefully we see the SQL request SELECT * FROM users WHERE username = 'g1vi'+OR+1=1 has been created taking our input without sanitization, so the vulnerability is confirmed.

Let's exploit the vulnerability with sqlmap

The tool is able to dump the users table.

And the books table.

UNAUTHORIZED PASSWORD CHANGE

This vulnerability is found in the file api_views/users.py

The application takes the password from a JSON parameter and uses it to modify the old one. This is possible as authorization is not made at object level as in BOLA vulnerabilities. In other words, the application does not check if the user token we are using to authenticate is authorized to change the password.

Let's exploit this by sending a PUT request to the /users/v1/name1/password endpoint to modify user name1 password. We just need to be logged with our own token, it will work because the application does not check if our user has permissions to modify somebody else's passwords.

The API returns with code 204. We can verify the password has been changed by logging in as user name1 with the new password, and then verifying the old password does not work.

BROKEN OBJECT LEVEL AUTHORIZATION

The vulnerability is found in the file api_views/books.py

The application takes the book name and retrieves all parameters from the database, including the book secret. No authorization check are made to verify if the user is allowed to retrieve this secret, contrary to what is said in the documentation: "each book is unique for every user and only the owner of the book should be allowed to view the secret".

To confirm the vulnerability, first we dump all book names using our token.

Then we query one of them, for example bookTitle1

And we verify we are able to see the book's secret using our token, when it is supposed to be allowed only for its owner. This is possible because no authorization checks are made at object (book) level.

MASS ASSIGNMENT

This vulnerability is found in the source file api_views/users.py

We are prompted to escalate our privileges by manipulating the POST register request adding an extra parameter.

According to the source code, as long as we register a new user adding an extra parameter called admin (with any value) we will receive administrative privileges.

EXCESSIVE DATA EXPOSURE THROUGH DEBUG ENDPOINT

During application development, programmers usually create endpoints for debugging purposes. These may remain active after entry into service, leaking all kind of sensitive information. We are prompted to find one of these debug endpoints.

The debug endpoint code is found in file api_views/users.py, where we find a call to get_all_users_debug()

Which in turn calls a method in models/user_model.py that basically makes a query to retrieve all user parameters in the database.

Let's query this endpoint and see what happens.

In fact we see all info related to the users, including changes we have made so far: our new user, the admin we have just created user and the password we modified before.

USER AND PASSWORD ENUMERATION

This is related to applications being too verbose when a failed login attempt happens, either by a wrong username or by a wrong password. Normally, the application should provide the same information or error message in both cases, so the attacker is not able to assemble a brute force attack.

Vulnerability is found in api_views/users.py

Here we see there are two different messages for both cases. This permits us enumerating usernames, and when a valid one is found, we can brute force the password.

To demonstrate this first we force two failed login attempts.

With the reply length data we can enumerate usernames with ffuf

For this, capture a login request with Burpsuite and edit to add FUZZ fields in the username parameter.

The resulting request should be something similar to this.

Now use ffuf to enumerate usernames, exclude responses with size 57 (to find this, check Content-Length parameter in the previous responses).

In fact, abusing the vulnerability we have been able to enumerate two valid usernames. Next step would be to brute force both passwords with a similar attack.

REGEXDOS (DENIAL OF SERVICE)

RegexDOS (Regular Expression Denial of Service) is a vulnerability affecting unsafe regular expressions. They are vulnerable if certain inputs provoke unreasonably long processing times, impacting application availability.

The vulnerable regular expression is located in the file api_views/users.py

This part of the code is supposed to validate user input when entering an email address. If the address is invalid an error message is reported.

Let's try an invalid email to see how the regular expression works.

This endpoint is candidate for regex denial of service. Now we have to check if the regular expression it is vulnerable and then, find a suitable input (evil regex) to cause the API to crash.

The following Python script creates an evil regex as suggested.

Now just send the payload to the endpoint to make it crash.

The API crashes. The server needs to be restarted to continue the test.

LACK OF RESOURCES AND RATE LIMITING

This vulnerability is related to applications that do not provide a limit to the amount of resources required to satisfy specific users requests. This is a useful protection against, for example, attacks that send a high number of requests in short time, such as user enumeration or password brute force.

This vulnerability has been previously confirmed, when we have been able to enumerate usernames.

JWT AUTHENTICATION BYPASS VIA WEAK SIGNING KEY

Generate an authentication token and inspect it with jwt_tool

The token uses symmetric encryption, so maybe we can crack the key if a vulnerable one has been used.

With the cracked password we can forge tickets for another user, for example, name2

And use the forged ticket to interact with the API as name2

WRAPPING UP

At this point we have been able to find and exploit the 9 vulnerabilities proposed by the author in the VAmPI documentation, using only Curl to interact with the API as we had proposed at the beginning of the exercise.

Last updated