Coder Social home page Coder Social logo

pomo-mondreganto / forcad Goto Github PK

View Code? Open in Web Editor NEW
136.0 5.0 13.0 5.09 MB

Pure-python distributable Attack-Defence CTF platform, created to be easily set up.

License: GNU General Public License v3.0

Python 68.40% HTML 0.43% Shell 1.93% Dockerfile 1.96% JavaScript 5.14% Vue 19.45% PLpgSQL 2.11% Makefile 0.24% SCSS 0.35%
ctf ctf-scoreboard capture-the-flag python docker celery ctf-platform scoreboard attack-defense attack-defense-ctf

forcad's Introduction

tests

ForcAD

Front page

Pure-python distributable Attack-Defence CTF platform, created to be easily set up.

The name is pronounced as "forkád".

This documentation is for the latest (development) version of ForcAD. It might not be stable or even working. The latest stable version can be found here, see the README.md there.

Note that there's a wiki containing some useful queries for game statistics, services description, writing a checker, modifying the rating system, etc.

Table of contents

Running

5 easy steps to start a game (assuming current working directory to be the project root):

  1. Open config.yml file (or cp config.yml.example config.yml, if the latter is missing).

  2. Add teams and tasks to corresponding config sections following the example's format, set start_time, timezone (e.g. Europe/Moscow) and round_time (in seconds) (for recommendations see checker_timeout variable).

  3. Install cli/requirements.txt (pip3 install -r cli/requirements.txt)

  4. Run ./control.py setup to prepare ForcAD config. This command will generate a new login and password (if not provided in admin.username and admin.password) for the admin interface and services. Generated credentials will appear in command output and in the updated config.yml. Backup of the config file will be generated just in case.

  5. Run ./control.py start --fast to start the system. Wait patiently for the images to build, it could take a few minutes, but happens only once. Notice that --fast option uses the pre-built image, so if you modified the base images or backend requirements, omit this option to run the full build.

That's all! Now you should be able to access the scoreboard at http://127.0.0.1:8080/. Admin panel is accessible at http://127.0.0.1:8080/admin/. Celery visualization (flower) is at http://127.0.0.1:8080/flower/.

Before each new game run ./control.py reset to delete old database and temporary files (and docker networks)

Configuration and usage

Receiving flags

Teams are identified by tokens (unique and randomly generated on startup). Look for them in the logs of initializer container or print using the following command after the system started: ./control.py print_tokens. Token is private information, so send them to each team correspondingly.

Flag format

System uses the most common flag format by default: [A-Z0-9]{31}=, the first symbol is the first letter of corresponding service name. You can change flag generation in function Flag.generate in backend/lib/models/flag.py

Each flag is valid (received by flag receivers and can be checked by checker) for flag_lifetime rounds (game config variable).

Configuration file

Config file (config.yml) is split into five main parts:

  • game contains the following settings:

    • start_time (required): the datetime of game start (timezone will be taken from the timezone option). Example: 2019-11-30 15:30:00.

    • round_time (required): round duration in seconds. Example: 30.

    • flag_lifetime (required): flag lifetime in rounds (see flag format section). Example: 5.

    • timezone (optional, default UTC): the timezone in which start_time is specified. Example: Europe/Moscow.

    • default_score (optional, default 2500): default score for tasks.

    • env_path (optional): string to append to checkers' $PATH environment variable (see checkers section). Example: /checkers/bin/.

    • game_hardness (optional, default 10): game hardness parameter (see rating system wiki page). Example: 10.5.

    • inflation (optional, default true): inflation (see rating system wiki page). Example: true.

    • checkers_path (optional, default /checkers/): path to checkers inside Docker container. Do not change unless you've changed the celery image.

    • volga_attacks_mode (optional, default false): refuse to accept flags if the attacker's service is down.

  • admin contains credentials to access celery visualization (/flower/ on scoreboard) and admin panel:

    • username: forcad
    • password: **change_me**

    It will be auto-generated if missing. Usernames & passwords to all storages will be the same as to the admin panel.

  • teams contains playing teams. Example contents:

teams:
  - ip: 10.70.0.2
    name: Team1
  - ip: 10.70.1.2
    name: "Team2 (highlighted)"
    highlighted: true

Highlighted teams will be marked on the scoreboard with a rainbow border.

  • tasks contains configuration of checkers and task-related parameters. More detailed explanation is in checkers section. Example:
tasks:
  - checker: collacode/checker.py
    checker_type: pfr
    checker_timeout: 30
    default_score: 1500
    gets: 3
    name: collacode
    places: 1
    puts: 3

  - checker: tiktak/checker.py
    checker_type: hackerdom
    checker_timeout: 30
    gets: 2
    name: tiktak
    places: 3
    puts: 2
  • storages is an auto-generated section, which will be overridden by control.py <setup>/<kube setup> and describes settings used to connect to PostgreSQL, Redis and RabbitMQ:

    • db: PostgreSQL settings:

      • user: <admin.username>
      • password: <admin.password>
      • dbname: forcad
      • host: postgres
      • port: 5432
    • redis: Redis (cache) settings:

      • password: <admin.password>
      • db: 0
      • host: redis
      • port: 6379
    • rabbitmq: RabbitMQ (broker) settings:

      • user: <admin.username>
      • password: <admin.password>
      • host: rabbitmq
      • port: 5672
      • vhost: forcad

For those familiar with Python typings, formal definition of configuration can be found here . BasicConfig describes what is required before setup cli command is called, and Config describes the full configuration.

Checkers

Configuration

Checksystem is completely compatible with Hackerdom checkers, but some config-level enhancements were added (see below). Checkers are configured for each task independently. It's recommended to put each checker in a separate folder under checkers in project root. Checker is considered to consist of the main executable and some auxiliary files in the same folder.

The following options are supported:

  • name (required): name of the service shown on the scoreboard.

  • checker (required): path to the checker executable (relative to checkers folder), which needs to be ** world-readable and world-executable** (run chmod o+rx checker_executable), as checkers are run with nobody as the user. It's usually <service_name>/checker.py.

  • checker_timeout (required): timeout in seconds for each checker action. As there're at minumum 3 actions run (depending on puts and gets), it's recommended to set round_time at least 4 times greater than the maximum checker timeout if possible.

  • puts (optional, default 1): number of flags to put for each team for each round.

  • gets (optional, default 1): number of flags to check from the last flag_lifetime rounds (see Configuration and usage for lifetime description).

  • places (optional, default 1): large tasks may contain a lot of possible places for a flag, that is the number. It's randomized for each put in range [1, places] and passed to the checker's PUT and GET actions.

  • checker_type (optional, default hackerdom): an option containing underscore-separated tags, (missing tags are ignored). Examples: hackerdom (hackerdom tag ignored, so no modifier tags are applied), pfr (checker with public flag data returned). Currently, supported tags are:

    • pfr: checker returns public flag data (e.g. username of flag user) from PUT action as a public message, private flag data (flag_id) as a private message, and public message is shown on /api/client/attack_data for participants. If checker does not have this tag, no attack data is shown for the task.

    • nfr: flag_id passed to PUT is also passed to GET the same flag. That way, flag_id is used to seed the random generator in checkers so it would return the same values for GET and PUT. Checkers supporting this options are quite rare (and old), so don't use it unless you're sure.

More detailed explanation of checker tags can be found in this issue.

  • env_path (optional): path or a combination of paths to be prepended to PATH env variable (e.g. path to chromedriver).

See more in checker writing section.

Checkers folder

checkers folder in project root (containing all checker folders) is recommended to have the following structure:

checkers:
  - requirements.txt  <--   automatically installed (with pip) combined requirements of all checkers (must be present)
  - task1:
      - checker.py  <--   executable (o+rx)
  - task2:
      - checker.py  <--   executable (o+rx)

Writing a checker

See the corresponding wiki page on how to write a checker.

Wiki

More extensive reading can be found in the wiki pages.

forcad's People

Contributors

dependabot[bot] avatar jnovikov avatar lint-action avatar pomo-mondreganto avatar talkenson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

forcad's Issues

[Feature] Add tokens to final config.yml

I want to use telegram-bot for tokens & vpn's config sharing, so I think final version of config.yml is not bad to derive info about tokens, flag lifetime & round time (to escape annoying questions about it).

If this is a good idea, then I will be happy to implement this feature.

Unable to start ForcAD without creating undocumented files

I was expecting to be able to start a minimal working instance of ForcAD by just running docker-compose up, however, I'm getting the ERROR: Couldn't find env file: /home/nikolay/Docs/ctf/fffad/docker_config/postgres/environment.env message (and other similar messages after I create a file from the previous one). I don't see any documentation about it (neither in README.md nor in... nowhere, actually, because there are no other docs, are they?) nor an example config. I think this should be explained or at least mentioned in the docs because I don't even know whether I've done something wrong (have a wrong version of docker/docker-compose? checked out a wrong branch? live on a wrong planet?) or these errors should occur and I should manually create the config files based on errors I'm getting from the containers after I create all the env files.

Btw, I am also getting some errors from containers, for which I was not forced to create an env file by docker. I didn't yet dig into it, but at the moment I don't understand how I can pass environment variables to, for example, initializer (db_checker.py).

Here there are some details about my machine (however, I don't think any of these are related to the problems above):

  • OS: Linux Mint 20 Cinnamon (based on Ubuntu 20.04)
  • Docker version 19.03.13, build 4484c46d9d
  • docker-compose version 1.25.0, build unknown
  • ForcAD's HEAD is at master, ae0da63

FD leak in websockets manager

When a lot of socket messages are send (e.g. attacks), RabbitMQ & Sanic containers start to use suspiciously many file descriptors (and approximately the same amount). My guess is that due to some bug in socketio.AsyncAioPikaManager used to send messages from other microservices through the broker, leading to FD leak.

No such file 'docker-compose'

After I running this command without error:"./control.py setup"
I get the bellow error when I run this command:"./control.py start --fast" on version 1.2.1
No such file or directory: 'docker-compose'
What I should to do?

root@kali:~/ForcAD_v1.2.1# ls
backend     docker-compose-base.yml  docker_config  README.md
checkers    docker-compose-fast.yml  front          requirements.txt
control.py  docker-compose.yml       LICENSE

No preview images in README.md

Why the hell should I consider your system worth using without even being able to evaluate its design? It is so disrespectful of you not to let your potential users to preview it!

Checker tags

I am sorry for opening an issue, but can you please explain the pfr and nfr in tags, your examples are not very clear

RIght now I have written a checker but it does not get any flag id, when get is invoked, I wanted to use the flag id as the seed and I tried to use nfr tag, but it causes error

null value in column "public_flag_data" violates not-null constraint

Flag is invalid or too old

Hi,
Thank you for your great work.
I've put all of project like described in your documents, I 've a DestructiveFarm and CTF project, all of them are well configured and run well, but I've in Destructive Farm a message that flag rejected and like message: Flag is invalid or too old.
I look to all python codes's in all projects, but I can't figure out where are the problem.
I will be glad if I can run this project in local host.(127.0.0.1)
Thank you.

Connection error

I got this error while setting up, does I miss something or any config:

Using Forcad:v1.4.0
Running command ['docker-compose', '-f', 'docker-compose-base.yml', '-f', 'docker-compose-fast.yml', 'up', '-d', '--scale', 'celery=1']
/usr/lib/python3/dist-packages/requests/__init__.py:87: RequestsDependencyWarning: urllib3 (2.0.2) or chardet (4.0.0) doesn't match a supported version!
  warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/docker/api/client.py", line 214, in _retrieve_server_version
    return self.version(api_version=False)["ApiVersion"]
  File "/usr/lib/python3/dist-packages/docker/api/daemon.py", line 181, in version
    return self._result(self._get(url), json=True)
  File "/usr/lib/python3/dist-packages/docker/utils/decorators.py", line 46, in inner
    return f(self, *args, **kwargs)
  File "/usr/lib/python3/dist-packages/docker/api/client.py", line 237, in _get
    return self.get(url, **self._set_request_timeout(kwargs))
  File "/usr/lib/python3/dist-packages/requests/sessions.py", line 557, in get
    return self.request('GET', url, **kwargs)
  File "/usr/lib/python3/dist-packages/requests/sessions.py", line 544, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/lib/python3/dist-packages/requests/sessions.py", line 657, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python3/dist-packages/requests/adapters.py", line 439, in send
    resp = conn.urlopen(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 790, in urlopen
    response = self._make_request(
  File "/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py", line 496, in _make_request
    conn.request(
TypeError: HTTPConnection.request() got an unexpected keyword argument 'chunked'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/bin/docker-compose", line 33, in <module>
    sys.exit(load_entry_point('docker-compose==1.29.2', 'console_scripts', 'docker-compose')())
  File "/usr/lib/python3/dist-packages/compose/cli/main.py", line 81, in main
    command_func()
  File "/usr/lib/python3/dist-packages/compose/cli/main.py", line 200, in perform_command
    project = project_from_options('.', options)
  File "/usr/lib/python3/dist-packages/compose/cli/command.py", line 60, in project_from_options
    return get_project(
  File "/usr/lib/python3/dist-packages/compose/cli/command.py", line 152, in get_project
    client = get_client(
  File "/usr/lib/python3/dist-packages/compose/cli/docker_client.py", line 41, in get_client
    client = docker_client(
  File "/usr/lib/python3/dist-packages/compose/cli/docker_client.py", line 170, in docker_client
    client = APIClient(use_ssh_client=not use_paramiko_ssh, **kwargs)
  File "/usr/lib/python3/dist-packages/docker/api/client.py", line 197, in __init__
    self._version = self._retrieve_server_version()
  File "/usr/lib/python3/dist-packages/docker/api/client.py", line 221, in _retrieve_server_version
    raise DockerException(
docker.errors.DockerException: Error while fetching server API version: HTTPConnection.request() got an unexpected keyword argument 'chunked'
Command ['docker-compose', '-f', 'docker-compose-base.yml', '-f', 'docker-compose-fast.yml', 'up', '-d', '--scale', 'celery=1'] failed!

Highlight the firstbloods in frontend

Using the modified highlighting mechanism implemented in FE it's possible to highlight the tasks the team got first bloods on. Will require backend API changes, too.

Cant login with admin credential

image

I have successfully install then access the admin panel. I have use credential mention in config.yml but still cant get access. Did i do wrong in installation process?

Inventory notification

Your tool/software has been inventoried on Rawsec's CyberSecurity Inventory:

What is Rawsec's CyberSecurity Inventory?

An inventory of tools and resources about CyberSecurity. This inventory aims to help people to find everything related to CyberSecurity.

More details about features here.

Note: the inventory is a FLOSS (Free, Libre and Open-Source Software) project.

Why should you care about being inventoried?

Mainly because this is giving visibility to your tool and improve its referencing.

Badges

The badge shows to your community that your are inventoried. It looks good but also shows you care about your project, that your tool is referenced.

Feel free to claim your badge here: http://inventory.rawsec.ml/features.html#badges, it looks like that Rawsec's CyberSecurity Inventory, but there are several styles available.

Want to thank us?

If you want to thank us, you can help make our open project better known by tweeting about it! For example: Twitter URL

So what?

That's all, this message is just to notify you if you care. Else you can close this issue.

Add more monitoring

Export more metrics with monitoring service. Possibly add prometheus & Grafana to the main deployment (though it might be better to start as a side project).

Send flag stolen notifications asynchronously

Currently after each flag is approved, a notification is sent (to socket.io clients through RabbitMQ). This limits the rate of successful flag submits.

It's possible to use the attack results queue from monitoring to send these notifications instead.

Teams & tasks deletion issue

When removing a team or a task the object is marked as inactive, but not physically deleted from the database. That leads to this object being present later in teamtasks table. Removing them is not an option as it'll break the admin panel, so it might be better to patch game state caching to filter out inactive tasks and teams.

HTTP flag receiver

Add RuCTFe-like flag receiver, possibly with the same exact API to reuse the Destructive farm protocol.

Set checker permissions correctly

As celery runs with the user nobody, all checker executable files need to be world-readable and world-executable. It might be a good idea to create a control.py command, parsing config.yml for checker executables and setting permissions correctly.

Version tagging

Add version tags to the base image in releases. This will allow to push development changes to latest tag without disrupting user deployments.

Uninformative error message for invalid checkers

When checker crashes (finishes with an invalid return code), the private message is Check failed with ValueError: X is not a valid TaskStatus, which doesn't help with debugging. I suppose showing the stripped stdout & stderr of such checker would be better.

Round progress calculation is wrong (?)

See

this.roundTime) /

this.roundProgress =
    (new Date().getTime() / 1000 -
        this.roundStart -
        this.roundTime) /
    this.roundTime;

I haven't looked into the complete code yet, but I believe this.roundTime shouldn't be subtracted from the rest. This way you always have negative values unless the end of the round is reached in which case the progress would be 0 but never more than 0.

Generated page is empty

After running on your's guide all services are up and visible in the list of Dockers, but HTML page on 127.0.0.1:8080 is empty, but named ForcAD

Wipe DB & cache on reset

When using external db running reset action clears neither DB nor cache, leaving the configuration & game state unchanged, which is undesirable.

Like with print_tokens command, it's possible to run the existing reset_db script before bringing the project down, or even start initializer service to do so.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.