/capital

A built-to-be-vulnerable API application based on the OWASP top 10 API vulnerabilities. Use c{api}tal to learn, train and exploit API Security vulnerabilities within your own API Security CTF.

Primary LanguageCSSGNU Affero General Public License v3.0AGPL-3.0

API Security Top 10 Vulnerable license

Quick facts

  • Name: 'c{api}tal'
  • Type: Vulnerable API Security application
  • Purpose: Educational
  • License: GNU AFFERO GENERAL PUBLIC LICENSE
  • Language: Python, JS
  • Author: Checkmarx Research team

Description

The Checkmarx research team created c{api}tal to provide users with an active playground in which they hone their API Security skills.
The c{api}tal application contains 10 API challenges which map to the OWASP top 10 API risks.
It is built with Python (FastAPI) and JS (React).

c{api}tal can also be used for conducting your own API Security CTF event.

Features:

Contains 10 challenges based on the OWASP top 10 API risks

  • Built on FastAPI (backend) and React (frontend)
  • UI - Blogging website (i.e medium)
  • OpenAPI3 API JSON specification file that can be imported as a POSTMAN collection
  • JWT token based authentication (lifetime can be adjusted in app)

c{api}tal is a blogging application which allow users to register, create and delete posts, create and delete comments, follow other users, and more.

Quickstart

Run the full application using docker-compose:

docker-compose up -d

The backend will be running on http://localhost:8000/
The frontend will be running on http://localhost:4100/
Check out the API endpoints specification page at http://localhost:8000/docs

Generate API requests to http://localhost:8000/api (via POSTMAN/Burp for example)
Import the API collection JSON file to POSTMAN and start generating API requests:
click here to download the c{api}tal API json collection file

To run the web application in debug:

First, run PostgreSQL, set environment variables and create database:

export POSTGRES_DB=rwdb POSTGRES_PORT=5432 POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres
docker run --name pgdb --rm -p 5432:5432 -e POSTGRES_USER="$POSTGRES_USER" -e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" -e POSTGRES_DB="$POSTGRES_DB" postgres
export POSTGRES_HOST=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' pgdb)
createdb --host=$POSTGRES_HOST --port=$POSTGRES_PORT --username=$POSTGRES_USER $POSTGRES_DB

[Option 1] Run locally

Then run the following commands to bootstrap your environment:

git clone https://github.com/Checkmarx/capital
cd capital
pip install -r requirements.txt

Then create .env file in project root and set environment variables for application:

export POSTGRES_DB=rwdb POSTGRES_PORT=5432 POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres
export POSTGRES_HOST=localhost
export DATABASE_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB
touch .env
echo APP_ENV=dev
echo DATABASE_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB >> .env
echo SECRET_KEY=$(openssl rand -hex 32) >> .env

Then run the backend server:

python3 
.py

[Option 2] Run backend using docker Run the backend using docker build:

docker build . -t capital
docker run -p 8000:8000  -e DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/rwdb --rm --name backend-capital capital

Run tests

Tests for this project are defined in the tests/ folder.

Set up environment variable DATABASE_URL or set up database_url in app/core/settings/test.py

This project uses pytest <https://docs.pytest.org/>_ to define tests because it allows you to use the assert keyword with good formatting for failed assertations.

To run all the tests of a project, simply run the pytest command: ::

$ pytest
================================================= test session starts ==================================================
platform linux -- Python 3.8.3, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: /home/some-user/user-projects/fastapi-realworld-example-app, inifile: setup.cfg, testpaths: tests
plugins: env-0.6.2, cov-2.9.0, asyncio-0.12.0
collected 90 items

tests/test_api/test_errors/test_422_error.py .                                                                   [  1%]
tests/test_api/test_errors/test_error.py .                                                                       [  2%]
tests/test_api/test_routes/test_articles.py .................................                                    [ 38%]
tests/test_api/test_routes/test_authentication.py ..                                                             [ 41%]
tests/test_api/test_routes/test_comments.py ....                                                                 [ 45%]
tests/test_api/test_routes/test_login.py ...                                                                     [ 48%]
tests/test_api/test_routes/test_profiles.py ............                                                         [ 62%]
tests/test_api/test_routes/test_registration.py ...                                                              [ 65%]
tests/test_api/test_routes/test_tags.py ..                                                                       [ 67%]
tests/test_api/test_routes/test_users.py ....................                                                    [ 90%]
tests/test_db/test_queries/test_tables.py ...                                                                    [ 93%]
tests/test_schemas/test_rw_model.py .                                                                            [ 94%]
tests/test_services/test_jwt.py .....                                                                            [100%]

============================================ 90 passed in 70.50s (0:01:10) =============================================
$

If you want to run a specific test, you can do this with this <https://docs.pytest.org/en/latest/usage.html#specifying-tests-selecting-tests>_ pytest feature: ::

$ pytest tests/test_api/test_routes/test_users.py::test_user_can_not_take_already_used_credentials

Web routes

All routes are available on /docs or /redoc paths with Swagger or ReDoc.

Project structure

Files related to application are in the app or tests directories. Application parts are:

app
├── api              - web related stuff.
│   ├── dependencies - dependencies for routes definition.
│   ├── errors       - definition of error handlers.
│   └── routes       - web routes.
├── core             - application configuration, startup events, logging.
├── db               - db related stuff.
│   ├── migrations   - manually written alembic migrations.
│   └── repositories - all crud stuff.
├── models           - pydantic models for this application.
│   ├── domain       - main models that are used almost everywhere.
│   └── schemas      - schemas for using in web routes.
├── resources        - strings that are used in web responses.
├── services         - logic that is not just crud related.
├── credentials      - list of common strings for Brute Force.
├── postman          - api json file for postman.
├── redis            - redis docker file and conf file.
├── scripts         
├── tests         
└── main.py          - FastAPI application creation and configuration.

Presented At

Blackhat Europe 2022 Arsenal

AppSec village at DefCon30

Write-ups & Referrences

c{api}tal CTF event sum-up blog

A great write-up by Maor Tal:
Part 1
Part 2

Stickers from DefCon30:

Development and Bugs

Found an issue, or have a great idea? Let us know:

Contributions are appreciated and can be done via GitHub.

See CONTRIBUTING.md for more information about how to submit them.

Thanks

This project was created at Checkmarx by Ravid Mazon with the help of these great contributors: Liad Levy, Yaniv Nizry, Guy Lyuboshits

The application was built base on real-world-app , we used these awesome repos:
Backend - FastAPI (Python)
Frontend - React (JS)
Thanks again for contributing to the open-source community!