Skip to content

Scoring

There will be two competition days: jeopardy on the first day and attack defense on the second. Each competition will have a separate score, and the combined result of the two scores will determine the final scoreboard.

Jeopardy Scoring

The jeopardy competition will use the same dynamic scoring system you know from the previous years.

All challenges will yield one or more flags at the end.

Escape Room

In terms of scoring, the Escape Room is part of the jeopardy competition. The Escape Room should not be all or nothing. Therefore teams can obtain points reflecting their progress. The Escape Room operator will hand out QR Codes (with flag strings) for every stage to teams, depending on their final progress. Teams are expected to submit these flags themselves on the jeopardy platform on dummy challenges (e.g., "Escape Room Stage 1", "Escape Room Stage 2", ...). These dummy challenges are again subject to dynamic scoring.

Escape Room is solved by mixed teams (multiple countries). The draw for this teams will be done at the welcome event.

Hardware Challenge

As the hardware challenge will be part of the jeopardy competition, it will yield flags as any other jeopardy challenge.

Attack-Defense Scoring

Attack-Defense scoring is based on FaustCTF, as it proved in recent years to be almost linear, without creating significant gaps between teams. We only introduced minor changes to the formula to accommodate services with multiple flag stores.

The final Attack-Defense score of each team is the sum of the team's scores for each individual service. The score for each service is the sum of three components:

  • Offense: Points for flags captured from other teams and submitted to the submission endpoint before expiry.
  • Defense: Points deduced for having your flags captured by other teams.
  • SLA: Points for the availability and correct behavior of your services.

Scores per Service

For each service, the component scores for each team are calculated as follows:

Offense points are calculated as:

offense = count(flags_captured_by[team])
for flag in flags_captured_by[team]:
    offense += (1 / count(all_captures_of[flag]))

Note: Since the points for each captured flag depend on the number of capturing teams, flags can degrade in value over time. This can result in a negative offense point delta being displayed on the scoreboard.

Defense points are calculated as:

defense = 0
for flag in flags_owned_by[team]:
    defense -= count(all_captures_of[flag]) ** 0.75

SLA points for each service are based on the lowest availability status of all flag stores of that service and the number of flag stores the service has (services with more flag stores give more SLA points). The SLA points are calculated as:

sla = (count(ticks_with_status['up'] + 0.5 * ticks_with_status['recovering'])) * sqrt(count(teams)) * count(flag_stores_in_service)

For example, if a service has two flag stores, the possible availability status are:

Status Flag Store 1 Status Flag Store 2 Lowest Status Point Factor Description
up up up 100% To get full points, all flag stores must be up.
up recovering recovering 50% If one service is recovering and the rest are up or recovering, you obtain half the points for this round.
recovering recovering recovering 50% same as above
down/faulty - down/faulty 0% If any flag store is down or faulty, you obtain no points for the service in that round.

Total Attack-Defense Score

total = 0
for service in services:
    total += offense[service] + defense[service] + sla[service]

Scoring Freezes

We will freeze the scores on both competition days, to keep the excitement for the award ceremony.

Combined Scoring

Due to scoring freezes on both days, a real-time combined scoring would not reflect the participating teams' actual points and could be highly misleading. Therefore final combined scores will be announced after the competition.

Combination of scores will follow the approach used by international cyber security challenge , as it is simple and has already proven to work well.

normalized_score_ad = (top_score_jeopardy * score_ad) / top_score_ad
final_score = score_jeopardy + normalized_score_ad

For example:

# top score of team X at the jeopardy CTF
top_score_jeopardy = 4568
# top score of team Y at the A/D CTF
top_score_ad = 29856

# scores of team Z
score_jeopardy = 4219
score_ad = 25212

# normalization formula
normalized_score_ad = (top_score_jeopardy * score_ad) / top_score_ad

# final score of team Z
final_score = score_jeopardy + normalized_score_ad

# results for team Z
>>> normalized_score_ad
3857.4630225080386
>>> final_score
8076.463022508038