Skip to main content

Overview

The configuration module defines all framework-wide settings including network parameters, cryptography keys, logging configuration, and security controls. File: common/config_example.py (actual common/config.py not committed to repository)
The actual config.py file should never be committed to version control as it contains sensitive key material. Use config_example.py as a template.

Network Configuration

ALLOWED_HOSTS
list[str]
default:"['c2.lab.internal', '192.168.100.10']"
List of allowed hostnames/IPs for the C2 server. Used for host header validation.
SERVER_HOST
str
default:"'c2.lab.internal'"
C2 server hostname or IP address
SERVER_PORT
int
default:"443"
Server port for HTTPS connections
BACKEND_PORT
int
default:"8443"
Backend port when running behind a reverse proxy

TLS Configuration

TLS_CERT_PATH
str
default:"'certs/server.crt'"
Path to TLS certificate file for HTTPS

Beacon Timing

BEACON_INTERVAL_S
int
default:"30"
Base beacon interval in seconds. Agents check in at this frequency (before jitter).
Set to 5 seconds for lab experiments, 30-300 for production
JITTER_PCT
int
default:"20"
Jitter percentage (0-100) applied to beacon interval. Adds randomness to avoid pattern detection.Formula: actual_interval = BEACON_INTERVAL_S * (1 ± JITTER_PCT/100)

Traffic Padding

PADDING_MIN_BYTES
int
default:"0"
Minimum padding to add to messages in bytes
PADDING_MAX_BYTES
int
default:"128"
Maximum padding to add to messages in bytes. Random amount between min and max is added to each message.

Cryptography

PRE_SHARED_KEY
bytes
required
32-byte pre-shared key for session key derivationDefault: b'REPLACE_WITH_REAL_32_BYTE_KEY!!!'
CRITICAL: This MUST be replaced with a cryptographically random 32-byte key in production.
Generating a secure key:
import os

# Generate a secure random 32-byte key
PRE_SHARED_KEY = os.urandom(32)
print(repr(PRE_SHARED_KEY))

Logging Configuration

LOG_LEVEL
str
default:"'INFO'"
Logging level. Valid values: 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'
LOG_DIR
str
default:"'logs'"
Directory path for log files. Created automatically if it doesn’t exist.
LOG_MAX_BYTES
int
default:"5242880"
Maximum size of each log file in bytes before rotation (default: 5 MB)
LOG_BACKUP_COUNT
int
default:"3"
Number of rotated log files to keep

Security Controls

BLOCKED_COMMANDS
list[str]
List of command patterns that are blocked for security. Tasks containing these strings will be rejected.Default blocked commands:
  • 'reg' - Registry modifications
  • 'schtasks' - Scheduled tasks
  • 'at' - Legacy task scheduler
  • 'sc' - Service control
  • 'net use' - Network shares
  • 'arp' - ARP manipulation
  • 'nmap' - Network scanning
  • 'whoami /priv' - Privilege enumeration
  • 'net localgroup' - Local group enumeration
These blocks are for lab safety. In a red team scenario, you would customize this list based on scope and rules of engagement.

Lab Environment

LAB_MODE_ENV_VAR
str
default:"'LAB_MODE'"
Environment variable name to check for lab mode
LAB_MODE_REQUIRED
str
default:"'1'"
Required value for lab mode environment variable
BEHIND_NGINX
bool
default:"False"
Set to True when running behind nginx reverse proxy. Read from BEHIND_NGINX environment variable.
BEHIND_NGINX = os.environ.get('BEHIND_NGINX', '0') == '1'

Configuration Example

Here’s a complete example configuration:
import os

# Network
ALLOWED_HOSTS = [
    'c2.lab.internal',
    '192.168.100.10',
]

SERVER_HOST  = 'c2.lab.internal'
SERVER_PORT  = 443
BACKEND_PORT = 8443

# TLS
TLS_CERT_PATH = 'certs/server.crt'

# Beacon timing
BEACON_INTERVAL_S = 30
JITTER_PCT        = 20

# Traffic padding
PADDING_MIN_BYTES = 0
PADDING_MAX_BYTES = 128

# Cryptography - REPLACE THIS!
PRE_SHARED_KEY = os.urandom(32)

# Logging
LOG_LEVEL        = 'INFO'
LOG_DIR          = 'logs'
LOG_MAX_BYTES    = 5 * 1024 * 1024
LOG_BACKUP_COUNT = 3

# Security controls
BLOCKED_COMMANDS = [
    'reg',
    'schtasks',
    'at',
    'sc',
    'net use',
    'arp',
    'nmap',
    'whoami /priv',
    'net localgroup',
]

# Lab environment
LAB_MODE_ENV_VAR  = 'LAB_MODE'
LAB_MODE_REQUIRED = '1'
BEHIND_NGINX = os.environ.get('BEHIND_NGINX', '0') == '1'

Usage

Import configuration variables anywhere in the codebase:
from common import config

print(f"Server: {config.SERVER_HOST}:{config.SERVER_PORT}")
print(f"Beacon interval: {config.BEACON_INTERVAL_S}s ± {config.JITTER_PCT}%")

if config.LOG_LEVEL == 'DEBUG':
    print("Debug logging enabled")

Security Best Practices

  • Generate a cryptographically random 32-byte key using os.urandom(32)
  • Never commit config.py to version control
  • Rotate keys periodically
  • Use different keys for different deployments
  • Use ALLOWED_HOSTS to prevent host header attacks
  • Configure TLS with valid certificates
  • Use non-standard ports if appropriate for OPSEC
  • Never log sensitive data (keys, passwords, PII)
  • Rotate logs to prevent disk exhaustion
  • Secure log files with appropriate permissions
  • Customize BLOCKED_COMMANDS for your environment
  • Consider allowlisting instead of blocklisting for stricter control
  • Document any changes to security controls

Environment Variables

Some settings can be overridden with environment variables:
VariablePurposeExample
LAB_MODEEnable lab modeexport LAB_MODE=1
BEHIND_NGINXRunning behind reverse proxyexport BEHIND_NGINX=1

See Also

Build docs developers (and LLMs) love