Skip to main content
GZCTF provides comprehensive monitoring tools to track competition progress, detect anomalies, and ensure fair play.

Real-Time Monitoring Dashboard

The monitoring dashboard provides live insights into competition activity.
Users with Monitor role have read-only access to monitoring features without admin capabilities.

Accessing Monitor View

1

Navigate to Game

Open the game you want to monitor from admin panel
2

Open Monitor View

Click Monitor button to access real-time dashboard
3

Connect to Event Stream

Dashboard connects to SignalR hub for live updates
// Frontend connects to MonitorHub
const connection = new signalR.HubConnectionBuilder()
  .withUrl(`/hub/monitor?game=${gameId}`, {
    accessTokenFactory: () => token
  })
  .build();

await connection.start();

// Receive real-time events
connection.on('ReceivedSubmission', (submission) => {
  console.log('New submission:', submission);
});

Event Types

GZCTF tracks various event types during competitions:

Flag Submissions

Track every flag attempt:
  • Team identifier
  • Challenge name
  • Result (correct/incorrect)
  • Timestamp

Container Events

Monitor container lifecycle:
  • Container creation
  • Extension/renewal
  • Destruction
  • Resource usage

Team Actions

Track team activities:
  • Challenge unlocks
  • Hint requests
  • Writeup submissions

System Events

Platform operations:
  • Game state changes
  • Admin actions
  • Notice publications

Event History

Retrieve historical events for analysis:
GET /api/game/{id}/events?hideContainer=false&count=100&skip=0

// Parameters:
// - hideContainer: filter out container events
// - count: events per page
// - skip: pagination offset

// Response:
[
  {
    "id": 1,
    "type": "FlagSubmit",
    "teamId": 42,
    "challengeId": 10,
    "status": "Accepted",
    "answer": "flag{***}",
    "time": "2024-03-01T10:30:00Z"
  }
]
hideContainer
boolean
default:false
Filter out container-related events to focus on gameplay

Submission Monitoring

Track all flag submission attempts across the competition.

Submission Status Types

Correct flag - team earns points
Incorrect flag attempt
Flag from another team detected (duplicate flag)
Challenge or flag doesn’t exist
Team already solved this challenge
Submission after challenge deadline
Team exceeded submission limit for challenge

Viewing Submissions

GET /api/game/{id}/submissions?type=Accepted&count=100&skip=0

// Get all submissions for a game
// Filter by type (optional)

Submission Details

Each submission record contains:
interface Submission {
  id: number;
  gameId: number;
  challengeId: number;
  teamId: number;
  userId: string;
  submitTime: string;        // ISO timestamp
  answer: string;            // Submitted flag (masked)
  status: AnswerResult;      // Result status
  challengeName: string;
  teamName: string;
  userName: string;
}
Flag values are partially masked in API responses to prevent leakage. Full flags are only visible in database.

Cheat Detection

GZCTF includes automated cheat detection for flag sharing.

How It Works

1

Flag Tracking

System maintains mapping of which team received which dynamic flag
2

Cross-Team Detection

When team submits a flag:
  1. Check if flag belongs to another team
  2. If yes → mark as CheatDetected
  3. Log incident for admin review
3

Alert Generation

Cheat events are:
  • Highlighted in submission stream
  • Logged to admin event log
  • Available for export/analysis
Cheat detection only works for dynamic flags (Dynamic Container/Attachment challenges).

Investigating Cheating

1

Filter Cheat Submissions

GET /api/game/{id}/submissions?type=CheatDetected

// Returns all detected cheating attempts
2

Analyze Patterns

Look for:
  • Repeated attempts between same teams
  • Timing correlation (submissions within seconds)
  • Team relationships
3

Take Action

Based on findings:
  • Warn teams
  • Suspend participations
  • Disqualify if confirmed
// Get cheat attempts for game
const cheats = await fetch('/api/game/1/submissions?type=CheatDetected')
  .then(r => r.json());

// Group by team pairs
const pairs = cheats.reduce((acc, cheat) => {
  const key = `${cheat.teamId}->${cheat.flagOwnerId}`;
  acc[key] = (acc[key] || 0) + 1;
  return acc;
}, {});

console.log('Team flag sharing pairs:', pairs);
// Output: { "42->17": 3, "42->23": 1 }
// Team 42 submitted flags from teams 17 (3x) and 23 (1x)

Container Monitoring

Track container instances and resource usage.

Active Containers

View all running containers:
GET /api/admin/instances

// Response:
[
  {
    "id": "container-guid",
    "teamId": "team-hash",
    "challengeId": 5,
    "challengeName": "Web Challenge",
    "image": "gzctf/web-chall:latest",
    "status": "Running",
    "startTime": "2024-03-01T10:00:00Z",
    "expectStopTime": "2024-03-01T12:00:00Z",
    "ip": "10.244.0.5",
    "port": "32001",
    "publicEntry": "https://gzctf.com:32001"
  }
]

Container Lifecycle Events

Track container operations:

Created

Container successfully started

Extended

Lifetime renewed by team

Destroyed

Container stopped/removed

Forced Container Destruction

Admins can manually destroy containers:
DELETE /api/admin/instances/{containerId}

// Forcibly stops and removes container
// Use for stuck containers or rule violations
Destroying a container:
  • Terminates the running service immediately
  • Loses any ephemeral data inside
  • Teams must recreate to continue

Traffic Capture

For challenges with traffic capture enabled, monitor network activity.

Accessing Captures

1

Enable Capture

Set EnableTrafficCapture: true on challenge
2

Container Activity

All network traffic is captured as PCAP files
3

Download PCAP

Retrieve capture files for forensic analysis
Traffic captures are useful for:
  • Investigating exploits
  • Understanding attack vectors
  • Detecting automated scanners
  • Educational purposes

Scoreboard Monitoring

Track competition standings in real-time.

Scoreboard Cache

GZCTF caches scoreboard for performance:
Cache TTL
duration
default:"2 minutes"
Scoreboard refreshes every 2 minutes during competition
POST /api/edit/games/{id}/scoreboard/flush

// Force immediate scoreboard recalculation
// Use after:
// - Participation status changes
// - Manual score adjustments
// - Challenge enable/disable

Scoreboard Data

Scoreboard includes:
interface Scoreboard {
  teams: TeamScore[];
  challenges: ChallengeSummary[];
  topTimeline: TimelineEvent[];
}

interface TeamScore {
  id: number;
  name: string;
  organization: string;
  rank: number;
  score: number;
  solvedCount: number;
  lastSubmitTime: string;
  solvedChallenges: number[];  // Challenge IDs
}

System Logs

Access platform-wide system logs:
GET /api/admin/logs?level=Warning&count=100&skip=0

// Filter by log level:
// - All (default)
// - Debug
// - Information  
// - Warning
// - Error
// - Critical

// Response:
[
  {
    "time": "2024-03-01T10:00:00Z",
    "level": "Warning",
    "userName": "admin",
    "ip": "192.168.1.1",
    "message": "Container creation took 5.2 seconds",
    "status": "Success"
  }
]
  • Debug: Verbose information for troubleshooting
  • Information: Normal operations (user login, challenge solve)
  • Warning: Potential issues (slow operations, rate limits)
  • Error: Failures (container errors, DB timeouts)
  • Critical: Severe issues (system crash, data loss)

Real-Time Event Streaming

SignalR Hubs

GZCTF uses SignalR for real-time communication:

MonitorHub

Real-time game events for monitors/admins:
  • Flag submissions
  • Container events
  • Team actions
Endpoint: /hub/monitor?game={gameId}

AdminHub

Platform-wide events for admins:
  • System logs
  • User actions
  • Configuration changes
Endpoint: /hub/admin

Connection Example

import * as signalR from '@microsoft/signalr';

const monitorConnection = new signalR.HubConnectionBuilder()
  .withUrl(`/hub/monitor?game=${gameId}`, {
    accessTokenFactory: () => getAuthToken()
  })
  .withAutomaticReconnect()
  .build();

// Register event handlers
monitorConnection.on('ReceivedSubmission', (submission) => {
  updateSubmissionList(submission);
});

monitorConnection.on('ReceivedGameEvent', (event) => {
  updateEventLog(event);
});

await monitorConnection.start();
console.log('Connected to monitor hub');
SignalR connections require authentication. Pass JWT token via accessTokenFactory.

Performance Metrics

Monitor platform performance:

Response Time

Track API latency and slow endpoints

Container Stats

Monitor:
  • Active containers
  • Creation time
  • Resource usage

Database Load

Query performance and connection pool

Cache Hit Rate

Redis cache effectiveness
Enable telemetry (Prometheus/OpenTelemetry) in configuration for detailed metrics.

Best Practices

Monitor Actively

During competitions:
  • Watch submission stream
  • Check for unusual patterns
  • Respond to issues quickly

Investigate Anomalies

Look for:
  • Burst of failures from one team
  • Identical submission patterns
  • Container creation spikes

Export Data

Regularly export:
  • Event logs
  • Submission history
  • Traffic captures

Review Post-Game

After competition:
  • Analyze solve times
  • Review cheat alerts
  • Identify bottlenecks

Troubleshooting

Check:
  • WebSocket connection is established
  • No firewall blocking WebSocket
  • Auth token is valid
  • Hub connection logs for errors
Try:
  • Flush scoreboard cache
  • Check if submissions are being recorded
  • Verify Redis connection
Verify:
  • Container provider is running
  • Event logging is enabled
  • Database is accessible
Investigate:
  • Number of active containers
  • Database query performance
  • Cache hit rates
  • Consider scaling infrastructure

API Reference

  • GET /api/game/{id}/events - Get game events
  • GET /api/game/{id}/submissions - Get game submissions
  • GET /api/game/{gameId}/challenges/{challengeId}/submissions - Challenge submissions
  • GET /api/admin/instances - List all containers
  • DELETE /api/admin/instances/{id} - Destroy container
  • GET /api/admin/logs - Get system logs
  • /hub/monitor?game={gameId} - Game monitoring
  • /hub/admin - Admin events

Next Steps

Configuration

Configure platform settings

Creating Games

Create new competitions

Build docs developers (and LLMs) love