Skip to content

A multi-tenant network sandbox for security challenges

License

Notifications You must be signed in to change notification settings

tamuctf/Naumachia

 
 

Repository files navigation

Naumachia

Play some challenges! https://www.naumachiactf.com/

Discord

If you are interested in using or contributing to this project let me (nategraf) know! It will grow based on input from those who care to give it.

A multi-tenant network sandbox for security challenges

The ambition of Naumachia is to enable the deployment of multi-host interactive exploit challenges for fun and non-profit. The origonal inspiration was to enable network exploit challenges. The main target is providing fun and challenging exercises for CTFs and classrooms.

The inspiration for this project comes from my love of networking and especially network security. I wanted a platform to write and play challenges where everything was in-bounds including ARP spoofing, VLAN hopping (WIP), DNS poisoning, SNMP attacks as well as destructive attacks like dropping database tables and installing backdoors without interferring with other users. Naumachia is a system I came up with to do just that.

Naumachia provides:

  • Orchatration or "arbitrary" networks and hosts for challenges
  • Isolation of teams within dedicated challenge instances
  • "Full" ethernet access to the challenge network

The quotes around "full" and "arbitrary" indicate that this is not completely true, due to limitations tracked in GitHub issues and which are ongoing areas of development.

Access to a Naumachia-hosted challenge is achieved through an OpenVPN tunnel created for that challenge. The user is autheticated by a certificate and key-pair downloaded from the CTF website (or other authenticated web frontend) and generated by the Naumachia registrar. Upon connection, the VPN tunnel will place the connection information in a Redis database, and the manager will then create a challenge instance for that user if one is not already alive. The manager will then create a network path for the user to the challenge and the user can start playing! When the user leaves for a while, their challenge instance will be torn down to free up resources. Data can be persisted on a per-instance basis allowing things such as modified database state, a persistant backdoor, or other progress to be saved between user sessions.

Naumachia architecture diagram

Challenges are specified through Docker Compose config files (i.e. docker-compose.yml). This allows the challenge developer to design against a well-documented fully-featured orchatration engine for conatainers and bridged networks. Additional providers including Vagrant, and GENI and currently in the works.

Deployment

Initial Setup

  1. Install Docker and Docker Compose
  2. Clone Naumachia onto a Linux server (developed and tested with Ubuntu 16.04)
  3. Install requirements.txt for Python3 (i.e. pip3 install -r requirements.txt)

Create a Challenge

  1. Write a docker-compose.yml template and put it and any associated files in directory within the challenges directory. See challenges/example for some guidance
  2. Modify config.yml to include your challenge
  3. Run configure.py to generate the docker-compose.yml file from a Jinja2 template, OpenVPN config files, and PKI

WARNING: When writing the compose file, do not use bind volumes (i.e. mount local directories to the container). It will not mount properly when started from the cluster-manager which handles creating and stopping challenge instances. No workaround is provided as it is the eventual intention to move toward a scalable model when you cannot control (or care about) where your challenges are deployed. See moby/moby#28124 for technical discussion of the underlying reason

Distriute Access Credentials

In order to log into the VPN tunnel and access Naumachia a client needs the correct configuration, and a registered certificate. These two are bundled in an OpenVPN client config file.

To generate a client config for your challenge either:

  • Use the registrar CLI
    • Ex: ./registrar/registrar.py mitm add alice will create certs for Alice and ./registrar/registar.py mitm get alice with output the configuration needed for Alice to connect to the 'MITM' challenge
  • Use the registrar server
    • Add registrar: {} or a non-default registrar configration to the config.yml file.
    • Secure your server by ensuring it cannot be accessed by the public or enabling TLS client verification, which is described in config.example.yml.
      • WARNING: If left unsecure, the registrar server can be used to issue a trivial DoS attack or worse against your Naumachia installation.
    • Issue REST API calls to registrar server to manage certificates and retrieve configuration files
      • /<chal>/list?cn=<cn> (cn optional) : List all registered certificates or certificates for a specific cn
      • /<chal>/add?cn=<cn> : Create a new certificate with the specified common name (cn)
      • /<chal>/revoke?cn=<cn> : Revoke the certificate with the specified common name (cn)
      • /<chal>/remove?cn=<cn> : Remove the certificate with the specified common name (cn)
      • /<chal>/get?cn=<cn> : Get the OpenVPN configuration file for the user with specified common name (cn)

Run it!

To run Naumachia simply bring up the environment with the Docker Compose CLI (e.g. docker-compose up -d)

On Each Server Reboot

For lack of a better method there are two steps that will need to be completed on initial installation and every time Naumachia will be run after reboot. It is my intention to eliminate the need for these steps as development continues.

  1. Disable bridge-nf enforcement of iptables rules by running disable-bridge-nf-iptables.sh. This is needed to allow unrestricted access within the sandbox network Naumachia creates for each user. By default, Docker blocks certain traffic from connections into a Docker configured bridge which were not configured through Docker Networks. This does not effect layer 3 restrictions imposed by iptables
  2. Run an arbitrary docker container on the host network (e.g. docker run --rm --net=host alpine /bin/true) This create a link in the /var/run/docker/netns folder called default which allows access to the host network namespace. This will be added to the cluster-manager container at runtime to allow it to modify the bridges generated by Docker on the host.

How to Create a Challenge

Challenges in Naumachia are defined by a docker-compose.yml file and the resources it launches

Consider the example provided as challenges/example/docker-compose.yml

For examples of problems deployed in past CTFs go to the challenges repo

version: '2.1'

# The file defines the configuration for simple Nauachia challenge
# where a successful man-in-the-middle (MTIM) attack 
# (such as ARP poisoning) provides a solution

# If you are unfamiliar with docker-compose this might be helpful:
# * https://docs.docker.com/compose/
# * https://docs.docker.com/compose/compose-file/
#
# But the gist is that the services block below specifies two containers,
# which act as parties in a vulnerable communication

services:
    bob:
        build: ./bob
        image: naumachia/example.bob
        environment:
            - CTF_FLAG=fOOBaR

    alice:
        build: ./alice
        image: naumachia/example/alice
        depends_on:
            - bob
        environment:
            - CTF_FLAG=fOOBaR

# To avoid users from using this challenge as a personal VPN
# gateway to the internet, it is important to specify the
# default network as internal (i.e. not connected to the internet)

networks:
    default:
        internal: true

This example defines a challenge which will feature two containers networked together through the default network, which has been modified to be inaccessible from the external world (as should be down for all challenges unless you have a good reason not to)

The code defining Alice's behavior is in the folder ./alice where you will find a Dockerfile defining the containers properties, and a python script which will be run as defined in the Dockerfile (This python script send a message to Bob "asking" if she has the right flag repeatedly)

Similarly Bob's definition is in ./bob which is a simple server listening for the flag Alice sends and responding yes or no if it is correct

The user will log in to the VPN tunnel with a config provided by the registrar, and execute an attack to intercept the traffic and obtain the flag

Connection Instructions

Clients can use any OS supported by OpenVPN, although Linux is recommended for it's large number of hacking tools

To connect each user will need to: 0. Install OpenVPN

  • Can be found on most package managers (e.g. apt, brew, choco) or downloaded
  • Ensure the TAP driver is installed
  1. Obtain a configuration file with certificates for the challenge they want to connect from the host
  2. Launch openvpn with the correct configuration
  • CLI: openvpn --config
  • Windows GUI: Place the config file in %HOMEPATH%\OpenVPN\config and right-click the VPN icon on the status bar, then select the config you want

If using the CLI on Linux, or MacOS you may still need to more steps 3. Bring up the new TAP network interface

  • Ex: ip link set tap0 up
  1. Obtain an IP address by DHCP (if DHCP is enabled for the challenge)
  • Ex: udhcpc -i tap0
  • Ex: dhclient tap0

About

A multi-tenant network sandbox for security challenges

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 93.8%
  • Shell 4.3%
  • Dockerfile 1.9%