Skip to main content
GZCTF supports container-based challenges using Docker or Kubernetes, providing isolated environments for each team with dynamic flag generation and resource management.

Container Lifecycle

Container instances in GZCTF progress through several states:

Container Status

Container is being created
ContainerStatus.Pending = 0
  • Initial state when instance is requested
  • Platform is pulling image and starting container
  • Waiting for container to be ready

Container Properties

Core Attributes

public class Container
{
    public Guid Id { get; set; }              // GZCTF internal ID
    public string ContainerId { get; set; }   // Docker/K8s container ID
    public string Image { get; set; }         // Docker image name:tag
    public ContainerStatus Status { get; set; }
    
    // Timing
    public DateTimeOffset StartedAt { get; set; }
    public DateTimeOffset ExpectStopAt { get; set; }
    
    // Networking
    public bool IsProxy { get; set; }         // Using reverse proxy?
    public string IP { get; set; }            // Local IP
    public int Port { get; set; }             // Local port
    public string? PublicIP { get; set; }     // Public IP (direct access)
    public int? PublicPort { get; set; }      // Public port (direct access)
}

Entry Point

How users access the container depends on the network configuration:
public string Entry => IsProxy 
    ? Id.ToString()                    // Proxy: Use container ID
    : $"{PublicIP ?? IP}:{PublicPort ?? Port}";  // Direct: IP:Port
Traffic routed through GZCTF proxy
Entry: 3fa85f64-5717-4562-b3fc-2c963f66afa6
Access: https://gzctf.example.com/api/proxy/3fa85f64-...
Benefits:
  • No need to expose ports
  • Built-in traffic capture support
  • Better security and isolation

Orchestration Platforms

GZCTF supports two container orchestration platforms:

Docker Provider

Docker Engine

Recommended for single-server deployments and testing
Features:
  • Direct Docker API communication
  • Simple setup and configuration
  • Port mapping for direct access
  • User-defined networks support
Configuration:
Container:
  Manager: Docker
  PublicEntry: "your.server.ip"
  DockerConfig:
    SwarmMode: false
    Uri: unix:///var/run/docker.sock

Kubernetes Provider

Kubernetes

Recommended for production and multi-server deployments
Features:
  • Horizontal scaling across nodes
  • Advanced resource management
  • High availability
  • Network policies and custom labels
Configuration:
Container:
  Manager: Kubernetes
  PublicEntry: "k8s.cluster.domain"
  K8sConfig:
    Namespace: "gzctf-containers"
    ConfigPath: "/path/to/kubeconfig"
    AllowCIDR:
      - "10.0.0.0/8"
    DNS:
      - "8.8.8.8"

Resource Limits

Each container challenge defines resource constraints:
ResourcePropertyDefaultDescription
MemoryMemoryLimit64 MBRAM allocation
StorageStorageLimit256 MBDisk space
CPUCPUCount1 (0.1 CPU)CPU cores in 0.1 units
PortExposePort80Container port to expose
CPU count is specified in 0.1 CPU units:
  • CPUCount = 1 → 0.1 CPUs
  • CPUCount = 10 → 1.0 CPUs
  • CPUCount = 20 → 2.0 CPUs

Example Resource Configuration

var challenge = new Challenge
{
    Type = ChallengeType.DynamicContainer,
    ContainerImage = "myregistry/pwn-challenge:latest",
    MemoryLimit = 128,      // 128 MB RAM
    StorageLimit = 512,     // 512 MB disk
    CPUCount = 5,           // 0.5 CPU cores
    ExposePort = 9999       // Expose port 9999
};

Network Modes

Containers can operate in different network isolation modes:
Full internet access
NetworkMode.Open = 0
  • Container can access external networks
  • Can download files from the internet
  • Suitable for challenges requiring external connectivity

Instance Management

Per-Team Limits

Games enforce concurrent container limits per team:
public int ContainerCountLimit { get; set; } = 3;
  • Default: 3 simultaneous containers
  • Teams must destroy instances to start new ones
  • Prevents resource exhaustion

Lifetime Management

1

Creation

Container starts when team activates a challenge:
StartedAt = DateTimeOffset.UtcNow;
ExpectStopAt = DateTimeOffset.UtcNow + TimeSpan.FromHours(2);
2

Extension

Teams can extend container lifetime (if permitted by platform config)
3

Destruction

Containers are destroyed when:
  • Team manually stops the instance
  • ExpectStopAt time is reached
  • Game ends (depends on practice mode)
  • Container limit is reached and new instance requested
The 2-hour default prevents immediate destruction after creation. Actual destruction time is managed by the container manager based on platform configuration.

Traffic Capture

GZCTF supports capturing network traffic for container instances:
public bool EnableTrafficCapture => 
    GameInstance?.Challenge.EnableTrafficCapture ?? false;

Capture Storage

Traffic captures are stored with the following path structure:
public string TrafficPath(string conn) =>
    $"captures/{ChallengeId}/{ParticipationId}/{ShortId}-{conn}.pcap";
  • ChallengeId: Identifies the challenge
  • ParticipationId: Identifies the team
  • ShortId: First 12 characters of container GUID
  • conn: Connection identifier
Example path:
captures/42/1337/3fa85f645717-eth0.pcap
Traffic capture requires reverse proxy mode (IsProxy = true) and is only supported for web-based challenges.

Container Metadata

Containers can generate metadata for logging and tracking:
{
  "Challenge": "Web Exploitation 101",
  "ChallengeId": 42,
  "Team": "TeamName",
  "TeamId": 1337,
  "ContainerId": "abc123def456",
  "Flag": "flag{dynamic_flag_here}"
}

Container Instances

GZCTF distinguishes between two types of container instances:

GameInstance

Competition challenge containers
public GameInstance? GameInstance { get; set; }
public int? GameInstanceId { get; set; }
  • Associated with a game participation
  • Counts toward team’s container limit
  • Subject to game timing constraints
  • Tracked for scoring and events

ExerciseInstance

Practice/training containers
public ExerciseInstance? ExerciseInstance { get; set; }
public int? ExerciseInstanceId { get; set; }
  • Independent of games
  • Personal practice environment
  • Not subject to competition rules
  • User-specific (not team-based)

Container Model Reference

The Container model is located at:
~/workspace/source/src/GZCTF/Models/Data/Container.cs
public class Container
{
    // Identity
    public Guid Id { get; set; }              // GZCTF GUID
    public string ContainerId { get; set; }   // Docker/K8s ID
    public string Image { get; set; }
    public ContainerStatus Status { get; set; }
    
    // Timing
    public DateTimeOffset StartedAt { get; set; }
    public DateTimeOffset ExpectStopAt { get; set; }
    
    // Networking
    public bool IsProxy { get; set; }
    public string IP { get; set; }
    public int Port { get; set; }
    public string? PublicIP { get; set; }
    public int? PublicPort { get; set; }
    
    // Computed properties
    public string Entry { get; }              // Access point
    public bool EnableTrafficCapture { get; }
    public string ShortId { get; }            // First 12 chars of GUID
    public string LogId { get; }              // For logging
    
    // Relationships
    public GameInstance? GameInstance { get; set; }
    public int? GameInstanceId { get; set; }
    public ExerciseInstance? ExerciseInstance { get; set; }
    public int? ExerciseInstanceId { get; set; }
    
    // Methods
    public string TrafficPath(string conn);
    public byte[]? GenerateMetadata(JsonSerializerOptions options);
}

Best Practices

  • Set appropriate memory limits to prevent OOM kills
  • Use isolated network mode for pwn challenges
  • Limit CPU to prevent resource hogging
  • Monitor container counts per team
  • Use specific image tags (not latest)
  • Test containers before deploying to competition
  • Include flag placeholders in Dockerfile ENV
  • Minimize image size for faster startup
  • Use isolated network mode when possible
  • Set appropriate resource limits
  • Regularly update base images
  • Enable traffic capture for monitoring
  • Pre-pull images before competition starts
  • Use local registry for faster pulls
  • Set appropriate ExpectStopAt times
  • Monitor container manager health

Challenges

Configure container-based challenges

Dynamic Flags

Learn about flag generation in containers

Games

Manage container limits and game configuration

Teams

Understand team instance management

Build docs developers (and LLMs) love