Guide: Developers - ReplayProject/ReplayHoneypots GitHub Wiki
Table of Contents
To begin development, there are two paths you can follow:
-
Develop taking advantage of the features Docker yields
-
Develop by installing dependencies and code directly on your machine
We recommend that developers take advantage of docker, as it is easier once you get used to the docker cli. Docker also has a wonderful VSCode extension. For this guide, we will not be using docker swarm mode, but rather the docker-compose functionality. Keep in mind you will need at least version 1.26.0 of docker-compose.
Before starting this process, decide if you want to “bundle” the docker images with snapshots of code or if you want the containers to react to code changes. From there, edit docker-compose.override.yml (volumes and bind-mount options) accordingly, looking for lines that say “toggle for dev...”. Additionally, you will need to update the config files and the frontend package.json file to reflect the fact that you are running on localhost or 127.0.0.1. Optionally, you can also change the sniffer mode in PorthThreadManager.py if you are recording too many logs.
Docker images are great, but it would be a huge waste of time to rebuild them each time we change a piece of our code. Because of that, it is important to familiarize yourself with the configuration in this repo. Using docker-compose, we can make the docker containers we are using more like a development environment, rather a production ready release of the software.
- Make sure you have docker-compose installed
$ docker-compose version
- Pull the github repo onto your development machine or virtual machine (VM)
$ git clone https://github.com/ReplayProject/ReplayHoneypots.git
# or if using ssh
$ git clone [email protected]:ReplayProject/ReplayHoneypots.git
# These commands setup the pre-commit checks
$ cd ReplayHoneypots/
$ sudo apt-get install python3-venv -y
$ python3 -m venv env
$ source env/bin/activate
$ pip install pre-commit
$ pre-commit install # you can run tests manually with "pre-commit run -av"
-
With the repo, prepare source files for the Docker image build step.
- update the public IP address (or localhost) in package.json to that of your
machine (or
localhost
).
- update the public IP address (or localhost) in package.json to that of your
machine (or
-
Build the replay-manager and replay-honeypot Docker images for local use
$ docker-compose build --parallel # (roughly 4-5 minutes first run)
- Launch the containers, you will need to toggle the DB_URL
in
/management/frontend/.env
, the DB_URL the service definitions for replay-honeypot in/docker-compose.yml
, and the config for couchdb indocker-compose.override.yml
$ docker-compose up # optionally use -d to send containers to the background
At this point, you should be able to see output from all containers in your terminal and
interact with the services on your own machine. You can run step 5 with the “-d"
flag to send the containers to the background. You can now attach to the containers,
change code on the host machine, and run whatever you would like to experiment and run
tests.
You can use docker inspect
to find the ephemeral ports the honeypot services were
bound to. If you ping one of these ports, then the traffic will appear on the frontend
and in the logs.
- To stop the containers, press
Ctrl+C
one time, and when the process is done, you may use the following command to remove the networks, configs, and containers made in step 5. Keep in mind that some caches for the frontend may still exist.
$ docker-compose down
To run these tests while not in a docker container, you will need to install the requirements file for the components you are testing. Also, every testing guide assumes you start off in the root of the repo. Here is an example of what that looks like for a python module:
$ pip3 install -r ./requirements.txt
This guide will take you through testing within Docker containers.
To run tests on the honeypot’s codebase, an instance of Couchdb must be running. At this
point, you should have gone through step 5 of the beginning steps in this document.
Also ensure that the source code has been bound to the container (see
docker-compose.override.yml
) After that, follow these steps:
- Attach to the replay-honeypot container
$ docker container exec -it honeypot ash
- Install requirements & run tests
$ ../../misc_scripts/honeypot_tests.sh
# if you have all requirements, you can run tests with
$ python3 -m pytest ./test/ --cov="." -vk "not Cron"
The coverage output as of 7-21-2020:
Name Stmts Miss Cover
------------------------------------------
Alert.py 13 7 46%
ConfigTunnel.py 71 15 79%
CronInstaller.py 65 57 12%
CronUninstaller.py 41 36 12%
Databaser.py 135 75 44%
LogEntry.py 19 0 100%
NmapParser.py 31 9 71%
PortThreadManager.py 108 43 60%
Sniffer.py 104 7 93%
TCPPortListener.py 25 0 100%
UDPPortListener.py 22 0 100%
__init__.py 0 0 100%
------------------------------------------
TOTAL 634 249 61%
Cron is deprecated at the moment, so testing there has been disabled. Pending alternative solution.
To run tests on the frontend's codebase, an instance of Couchdb must be running. At this
point, you should have gone through step 5 of the beginning steps in this document.
Also ensure that the source code has been bound to the container (see
docker-compose.override.yml
) After that, follow these steps:
- Attach to the replay-honeypot container
$ docker container exec -it manager ash
- Run tests through npm script
$ npm run test
- Optionally, you can run individual files
$ npx ava test/specs/index.spec.js
- To generate a report
$ npx nyc report
Coverage as of 5-01-2020 (abbreviated ):
All files | 65.86 | 54.74 | 48.31 | 66.07 |
---|---|---|---|---|
components | 37.84 | 57.89 | 0 | 38.89 |
doughnut.vue | 75 | 100 | 0 | 75 |
lineChart.vue | 75 | 100 | 0 | 75 |
metric-list-item.vue | 57.14 | 47.37 | 0 | 57.14 |
sparkline.vue | 19.05 | 42.86 | 0 | 20 |
title.vue | 60 | 88.24 | 0 | 60 |
pages | 75.46 | 53.38 | 59.72 | 75.48 |
about.vue | 73.77 | 48.28 | 58.33 | 74.58 |
details.vue | 62.16 | 56.41 | 40 | 60.56 |
index.vue | 94.12 | 56.52 | 85.71 | 93.75 |
login.vue | 78.79 | 48 | 66.67 | 81.25 |
overview.vue | 100 | 58.82 | 100 | 100 |
To run the CLI tests, follow these steps:
- Move to the test container folder
$ cd management/cli/test
- Start the test container
$ docker-compose -f blank_machine.yml up -d
$ sudo ./ssh_firsttime.sh
Are you sure you want to continue connecting (yes/no)? yes
[sudo] password for fakehoney: winniewazhere
openssh-server:~$ exit
- Move to the CLI folder
$ cd management/cli/
- Install requirements
$ pip3 install -r requirements.txt
- Clear out old tests
$ sudo python3 -m coverage erase
- Run module tests (takes 4ish minutes)
$ sudo python3 -m coverage run tests.py
- Move to the test container folder
$ cd management/cli/test
- Tear down the test container
$ docker-compose -f blank\_machine.yml down
At the top level, our repository has several bash scripts used to manage honeypots, some
other useful, but less important, ones are in the misc_scripts
folder descriptive
comments. Our folder structure is as follows.
Config — This contains data that is used to customize each honeypot and the services we launch with the system. Our honeypots will look for a default_hp_config.json file by default to get basic configuration information. This will be copied into the CouchDB database and used as a template for all additional honeypots. A honeypot configuration file, decides how long to delay port responses, what IP addresses and ports can safely be ignored in logs, and a list of ports and response information for each supported port & protocol. Our honeypots are made to reply to requests on certain ports. The frontend_auth.json file contains login information for the admin account on the replay-manger's frontend. This file serves as a default set of accounts that is copied into the database at first run.
Logs — Output folder for various logs. (deprecated)
Management — This contains code for both our administrative command line interface (CLI) and the frontend. The CLI subfolder has several python files, pertaining to the different operations our CLI can perform, including managing honeypots and installation. The frontend subfolder is what runs our web interface and the UI’s authentication server. This is primarily for allowing users to view logs and statistics about the honeypots deployed within the system.
Honeypots — This is where our honeypot logic lies. There are Docker configuration files that describe how to make a honeypot image. The honeypot subfolder is where the actual honeypot code is, and the test subfolder holds code and configurations to test the honeypots.
The main file for running our honeypots
- Collects configuration information, runs our Sniffer class, PortListeners, and waits for potential updates from the management server about configuration.
- The getConfigData() method is where configuration information is read from and is fairly concise. However, this eventually falls on the Databaser class to get the config.
- The activate() method runs the honeypot and could use a moderate refactor.
- Code for running Sniffer and PortListener classes could be abstracted to another method to be better tested.
- activate() returns a status number 0-3 depending on if anything was updated. This is based on hashed values of Sniffer and PortListener classes; if any changes actually occur, these values will change.
- An update-configuration alert is sent on startup. This alert could be removed in future iterations as it is redundant.
- Currently supports logging TCP/UDP/ICMP packets and responding to TCP/UDP.
This acts as a Wireshark of sorts in our honeypots. Any packet that goes into our honeypot is analyzed, filtered based on configuration, and sent to the database. The centerpiece of the program is the scapy library’s sniff() function. Pass this a filter and a processing function, and you can read incoming/outgoing packets.
- Sniffer’s self.config has several values and could be revamped. Base mode is meant to be a catch-all, but the filter ignores traffic on ssh ports; this was necessary due to the VPN setup on the NC State network, otherwise our database gets flooded with these packets.
- save_packet() could be refactored. Using a switch statement or abstracting TCP/UDP/ICMP sub-processing would reduce the messy look of the function.
- Currently, two data structures exist in Sniffer. self.RECORD is purely for
testing; it contains all logs sent out from Sniffer. self.PS_RECORD is used for
port scans. It is a dictionary of dictionaries, with the top level being IPs and
bottom level being Ports. This allows us to watch for port scans across multiple IPs.
- Recommend removing self.RECORD and adapting tests to use self.PS_RECORD.
This is a simple object containing packet data. Sniffer creates a new LogEntry for each packet it reads in and sends it off to our database.
The Alert class is the same, but for Alert entries.
Contains a TRIO socket, run by PortThreadManager. Upon receiving a packet on its unique port, it responds with a custom payload, specified in the honeypot's config.
ConfigTunnel — Encrypted TCP interface that the management server uses to communicate with honeypots to perform administrative tasks. The most important is “reconfiguration”. This tunnel can also be used to run predefined python functions.
Databaser — Interface used by honeypot classes to communicate with our database.
NmapParser — This contains functionality that parses an Nmap file into a json config file for use in a honeypot.
Couchdb - NoSQL database where we store logs and alerts coming from honeypots. Full HTTP API can be used as currently configured.
Passport.js - Framework for authentication that is used to log users into our frontend app.
You may have to manually delete docker images or volumes to get “fresh starts”. In most cases, a “docker prune --all --volumes” will do the trick.
Pay attention to how docker containers may be failing with
docker stack ps <stack_name>
, sometimes there may be port conflicts between the images
and the docker containers.
If the testing suites are not passing there are three things to do depending on the specific tests and type of failure.
- Edit the honeypot/manager code and rerun the tests suite
- Edit the Dockerfiles,
docker-compose down
, rebuild the images,docker-compose up -d
- Edit docker-compose files and environment variables,
docker-compose down
,docker-compose up -d