Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
c9b83b2
del binary from plugins
Jacute Oct 24, 2025
14aeee8
feat: add log_writer into flag_sender & exploit_runner
Jacute Oct 24, 2025
8630e21
feat: add context into send flags req
Jacute Oct 24, 2025
86a985f
fix: bug with skipping flags after receiving from rabbit
Jacute Oct 24, 2025
fa8a6c8
update enabled comment
Jacute Oct 24, 2025
d574f65
feat: add utils & exploits tests
Jacute Oct 29, 2025
e798c45
Merge pull request #30 from Jacute/tests-jacfarm-api
Jacute Oct 29, 2025
22f199c
fix: write log into db
Jacute Oct 30, 2025
8b90947
feat: add logs enpoints
Jacute Oct 30, 2025
c57d907
docs: update swagger
Jacute Oct 30, 2025
b35c18c
Merge pull request #32 from Jacute/feature-db-log-write
Jacute Oct 30, 2025
50ae204
del env & port forward jacfarm-api from container into localhost
Jacute Oct 30, 2025
c87f744
Merge branch 'dev' of github.com:SgffCTF/JacFARM into dev
Jacute Oct 30, 2025
af08dc1
add ci & update golang version
Jacute Oct 30, 2025
3564089
add tests branch
Jacute Oct 30, 2025
3a99fc4
update ci
Jacute Oct 30, 2025
60b906f
fix workflow
Jacute Oct 30, 2025
58f6296
fix workflow
Jacute Oct 30, 2025
34ca79f
add test badges
Jacute Oct 30, 2025
d5a58d0
add badges
Jacute Oct 30, 2025
e44094c
add tests; update workflow
Jacute Oct 30, 2025
3ecdbe5
comment happy path plugin & config tests
Jacute Oct 30, 2025
2e94c60
docs: update documentation, add exploits examples
Jacute Nov 4, 2025
d22ba9b
tests: add for GetConfig handler
Jacute Nov 4, 2025
1d5c199
tests: add for UpdateConfig handler
Jacute Nov 4, 2025
58f5c39
ci: update workflow for jacfarm-api tests
Jacute Nov 4, 2025
0b0ee7c
ci: update test workflow
Jacute Nov 4, 2025
7e95982
fix test coverage & update makefiles
Jacute Nov 5, 2025
89dbe72
tests: add for ListExploits & ListShortExploits handlers
Jacute Nov 5, 2025
1f02894
tests: add for toggle, upload, delete exploits handlers
Jacute Nov 5, 2025
4fcb234
tests: add flags handlers
Jacute Nov 5, 2025
09c41b7
tests: add for team handlers
Jacute Nov 5, 2025
517b832
tests: add middleware
Jacute Nov 5, 2025
b9d63e2
tests: add service exploits tests
Jacute Nov 5, 2025
f2142fb
update envs & refactor if-else in main exploit_runner
Jacute Nov 6, 2025
96df100
add pprof in jacfarm-api
Jacute Nov 6, 2025
20b319b
tests: add uploadexploit service tests
Jacute Nov 8, 2025
1a7cceb
tests: add config, flags, statuses service tests
Jacute Nov 8, 2025
0dfab66
Merge branch 'dev' into tests-jacfarm-api
Jacute Nov 8, 2025
80b740e
fix merge from dev
Jacute Nov 8, 2025
ad80189
fix: double nack consuming flags from queue
Jacute Nov 9, 2025
7dcd603
Merge pull request #36 from Jacute/feature-saarctf-plugin
Jacute Nov 9, 2025
22e253d
tests: add teams service tests
Jacute Nov 9, 2025
3aeb739
update 'on' in workflow
Jacute Nov 9, 2025
66113c5
Merge pull request #37 from Jacute/tests-jacfarm-api
Jacute Nov 9, 2025
14defbb
fix: delete exploit without dir check
Jacute Nov 9, 2025
6593554
feat: 'up' in Makefile not update .env if exists
Jacute Nov 9, 2025
eec7608
del comments in makefile
Jacute Nov 9, 2025
022b0d0
fix: fix tests after 14defbb2e
Jacute Nov 9, 2025
ec928f7
del todo
Jacute Nov 9, 2025
eca808a
feat: update ui lang to english
Jacute Nov 9, 2025
f4779a6
feat: update ui lang to english
Jacute Nov 9, 2025
3dd00fe
feat: add bash type exploit
Jacute Nov 9, 2025
f657109
feat: add ip range config parameters
Jacute Nov 9, 2025
d3f503c
Merge pull request #39 from Jacute/feature-add-ip-range
Jacute Nov 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .env

This file was deleted.

61 changes: 61 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: tests

on:
push:
branches: [ "**" ]
pull_request:
branches: [ master, dev ]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25.3'

- name: Build jacfarm-api
run: cd ./jacfarm-api && go build -v ./...

- name: Build config_loader
run: cd ./workers/config_loader && go build -v ./...

- name: Build exploit-runner
run: cd ./workers/exploit_runner && go build -v ./...

- name: Build flag-sender
run: cd ./workers/flag_sender && go build -v ./...

tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25.3'

- name: Install gocovmerge
run: go install github.com/wadey/gocovmerge@latest

- name: Run tests on jacfarm-api
run: make coverage

# --- Upload to Codecov ---
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: Jacute/JacFARM
files: coverage.out

# --- Upload to Coveralls ---
- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: coverage.out
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ todo
database.db
error_writer
coverage.html
volumes
volumes
backend.sh
.env
57 changes: 53 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.PHONY: help up down clean-db clean-all reset coverage

# Цвета
GREEN := \033[0;32m
PURPLE := \033[0;35m
Expand All @@ -18,13 +20,26 @@ up: ## Start services
@echo "$(GREEN)[$(PURPLE)start$(GREEN)]$(RED) Starting services$(RESET)"
@mkdir -p volumes/exploits
@sudo chown -R 1000:1000 ./volumes/exploits
@echo "JACFARM_API_KEY=$(JACFARM_API_KEY)" > .env
@echo "ADMIN_PASS=$(ADMIN_PASS)" >> .env
@echo "$(PURPLE)Farm api key$(RESET) - $(JACFARM_API_KEY)"
@echo "$(PURPLE)Farm admin creds$(RESET) - admin:$(ADMIN_PASS)"
@touch .env

@if grep -q '^JACFARM_API_KEY=' .env; then \
printf "$(PURPLE)Farm api key$(RESET) - %s\n" "$$(grep '^JACFARM_API_KEY=' .env | cut -d'=' -f2-)"; \
else \
echo "JACFARM_API_KEY=$(JACFARM_API_KEY)" >> .env; \
printf "$(PURPLE)Farm api key$(RESET) - %s\n" "$(JACFARM_API_KEY)"; \
fi

@if grep -q '^ADMIN_PASS=' .env; then \
printf "$(PURPLE)Farm creds$(RESET) - admin:%s\n" "$$(grep '^ADMIN_PASS=' .env | cut -d'=' -f2-)"; \
else \
echo "ADMIN_PASS=$(ADMIN_PASS)" >> .env; \
printf "$(PURPLE)Farm creds$(RESET) - admin:%s\n" "$(ADMIN_PASS)"; \
fi

@sudo docker compose --env-file .env up --build -d
@echo "$(GREEN)Services started$(RESET)"


down: ## Stop services
@echo "$(GREEN)[$(PURPLE)stop$(GREEN)]$(RED) Stopping services$(RESET)"
@sudo docker compose down
Expand All @@ -39,3 +54,37 @@ clean-all: ## Remove all volumes (db, rabbitmq, exploits)
@rm .env

reset: down clean-all up ## Full reset: stop, clean and restart

coverage:
@echo "$(GREEN)Running tests$(RESET)"

@cd jacfarm-api && \
PKGS=$$(go list ./... | grep -vE 'mocks|cmd/jacfarm-api' || true) && \
if [ -z "$$PKGS" ]; then echo "No packages found in jacfarm-api"; exit 0; fi && \
CSV=$$(echo $$PKGS | tr ' ' ',') && \
echo "Running go test for: $$PKGS" && \
go test -v -race -coverpkg=$$CSV -covermode=atomic -coverprofile=../jacfarm-api.out $$PKGS

@cd workers/config_loader && \
PKGS=$$(go list ./... | grep -vE 'mocks|cmd/config_loader' || true) && \
if [ -z "$$PKGS" ]; then echo "No packages found in config_loader"; exit 0; fi && \
CSV=$$(echo $$PKGS | tr ' ' ',') && \
echo "Running go test for: $$PKGS" && \
go test -v -race -coverpkg=$$CSV -covermode=atomic -coverprofile=../../config_loader.out $$PKGS

@cd workers/exploit_runner && \
PKGS=$$(go list ./... | grep -vE 'mocks|cmd/exploit_runner' || true) && \
if [ -z "$$PKGS" ]; then echo "No packages found in exploit_runner"; exit 0; fi && \
CSV=$$(echo $$PKGS | tr ' ' ',') && \
echo "Running go test for: $$PKGS" && \
go test -v -race -coverpkg=$$CSV -covermode=atomic -coverprofile=../../exploit_runner.out $$PKGS

@cd workers/flag_sender && \
PKGS=$$(go list ./... | grep -vE 'mocks|cmd/flag_sender' || true) && \
if [ -z "$$PKGS" ]; then echo "No packages found in flag_sender"; exit 0; fi && \
CSV=$$(echo $$PKGS | tr ' ' ',') && \
echo "Running go test for: $$PKGS" && \
go test -v -race -coverpkg=$$CSV -covermode=atomic -coverprofile=../../flag_sender.out $$PKGS

gocovmerge jacfarm-api.out config_loader.out exploit_runner.out flag_sender.out > coverage.out
rm exploit_runner.out flag_sender.out jacfarm-api.out config_loader.out
87 changes: 80 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,79 @@
# JacFARM

Exploit farm for attack-defense CTF competition
<p align="center">
<picture>
<img alt="JacFARM Logo" src="https://raw.githubusercontent.com/Jacute/JacFARM/refs/heads/master/docs/logo.png" width="300">
</picture>
</p>
<p align="center">
<strong>Exploit farm for attack-defense CTF competition</strong>
</p>
<p align="center">
<a href="#quick-start">Quick Start</a> •
<a href="#features">Features</a> •
<a href="#components">Components</a>
</p>
<p align="center">
<a href="https://github.com/Jacute/JacFARM/actions"><img src="https://github.com/Jacute/JacFARM/actions/workflows/tests.yml/badge.svg" alt="CI Status"></a>
<a href="https://codecov.io/gh/ollelogdahl/concord"><img alt="Codecov" src="https://codecov.io/gh/Jacute/JacFARM/master/master/graph/badge.svg"></a>
<a href="#"><img alt="Coveralls" src="https://coveralls.io/repos/github/Jacute/JacFARM/badge.svg?branch=master"></a>
<a href="https://github.com/Jacute/JacFARM/releases"><img alt="Release" src="https://img.shields.io/github/v/release/Jacute/JacFARM"></a>
</p>

## Quick start

### Dependencies

- Docker
- Docker Compose
- Make

### Start

1. Configure *config.yml* for your competition. A detailed description of the quick configuration is [here](./docs/config.md)

2. Start the farm
```bash
make up
```

Credentials for basic auth and the token for sending flags via start_exploit.py will be printed to stdout.

3. After the game ends, turn off the farm and clean the database and queue
```bash
make down
make clean-all
```

## Features

- Uploading exploits in ui
- Real-time configuration farm options like number of concurrently running exploits, the size of the flag sending batch, team ip addresses, etc
- The ability to [change the plugin for sending flags to jury](./docs/flag_sender/flag_sender.md).
- There are already two sending plugins: [forcad_http](./workers/flag_sender/plugins/forcad_http/client.go) and [saarctf_tcp](./workers/flag_sender/plugins/saarctf_tcp/client.go).
- Different [exploit types](./docs/exploit_runner/exploit_runner.md):
- Python (one file)
- Python (zip)
- Bash script
- Binary
- View logs of running exploits and sending flags on ui
- Configuring vulnboxes ip addresses using [various methods](./docs/config.md)

## Components

### Arch Diagram
### Client

- **Frontend** - ui for
- viewing flags with any filters
- adding exploits of different types via '+' button
- deleting or updating exploits by right mouse button
- adding teams
- updating farm config
- viewing logs

![](./docs/img/frontend.png)

![](./docs/img/diagram.jpg)
- **start_exploit.py** - python cli tool for starting exploits on local machine (TODO)

### Server

Expand All @@ -15,8 +82,14 @@ Exploit farm for attack-defense CTF competition
- **JacFARM API** - API for frontend and cli start_exploit.py.
- **Config Loader** - loads config into db from config.yml on start. Next configuration editing is available through the frontend.

### Client
#### Plugins

- **start_exploit.py** - python cli tool for starting exploits on local machine (TODO)
- **Frontend**
![](./docs/img/frontend.png)
**Plugin** - is a function in a farm that sends flags to the jury system.

⚠️ Farm contains two plugins for [ForcAD](https://github.com/pomo-mondreganto/ForcAD) and saarCTF jury systems. If you write plugins for other jury systems, you can create a pull request to add them into repository.

[Plugin example for ForcAD](./workers/flag_sender/plugins/forcad_http/client.go)

### Arch Diagram

![](./docs/img/diagram.jpg)
15 changes: 14 additions & 1 deletion config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ exploit_runner:
- 10.10.1.2
- 10.10.2.2
- 10.10.3.2
team_ip_cidrs:
- "10.228.79.0/24"
- "10.229.79.0/24"
team_ip_ranges:
- "10.200.78.2-10.200.78.200"
- "10.200.78.221-10.200.78.233"
team_ip_from_N: # N - range(n_start, n_end); X = N / block + offset_x, Y = N % block + offset_y
n_start: 0
n_end: 2000
offset_x: 32
offset_y: 0
block: 200
ip_template: "10.{X}.{Y}.2"
flag_format: '[A-Z0-9]{31}='
run_duration: 10s
exploit_directory: ./exploits
Expand All @@ -15,7 +28,7 @@ flag_sender:
jury_flag_url_or_host: http://10.10.10.10/flags # url for http, host for tcp
token: asd123
flag_ttl: 5m
submit_timeout: 10s
submit_timeout: 30s
submit_period: 5s
submit_limit: 50
plugin_directory: ./plugins
Loading
Loading