Skip to content

SaarCTF 2024 Scoring Formula

Scoring formula for SaarCTF 2024 organized by saarsec.

Summary

The total score of each team is calculated from offense, defense and sla components of every team for each of their services and rounds played.

The checker returns one of three results for each service: up, recovering and down. A service is considered recovering if SLA checks both suceeded and failed for one round (each) in the recovery period.

Additionally, the game server tracks the status of the vulnbox' VPN connection as, assigning either online or offline status accordingly.

The following python pseudo-code captures the team score calculation:

def score(rnd, team):
    attack = 0
    captures = [f for f in flags_captured_by(team) if flag_owner(f) != "NOP"]
    for flag in captures:
        attack += 1 + len(captures_of(flag)) ** -0.5 \
                 + scoreboard_pos(flag_owner(flag), flag_round(flag)) ** -0.5

    sla = 0
    defense = 0
    for r in range(rnd+1):
        online = [t for t in teams if vpn_status(r, t) == 'online']
        for service in services:
            if service_status(r, team, service) == 'up':
                for flag in flags_in(r, team, service):
                    defense -= (len(captures_of(flag)) / len(online)) ** 0.3 \
                             * len(online) ** 0.5
                sla += len(online) ** 0.5

    flags_per_round = sum(service.flagstores for service in services)
    attack /= flags_per_round
    defense /= flags_per_round

    return attack + defense + sla

def scores():
    return {rnd: {team: score(rnd, team} for team in teams} for rnd in rounds}

The final worth of a flag is only calculated once its validity is over. That means, everyone that submits a flag while it is still valid receives the same amount of points.

Review

  • Only small differences to the FaustCTF 2024 scoring formula, inherits most of the same strengths (simple, easy to implement) and weaknesses (score recalculation).
  • SLA is scaled using the number of online teams, which allows manipulation by registering fake teams ahead of time and connecting / disconnecting from the VPN depending on your own service status.
  • Attack and defense points are scaled by the number of flagstores, but SLA is not scaled by the number of services. For consistent scoring, SLA should be normalized such that SLA weight does not depend on the number services deployed.
  • Defense points scale with SLA, such that perfect SLA will always be worth atleast as much as the defense points lost. However, since the attacker still gains points when in the worst-case sla + defense == 0, this formula violates Tenet 4.