Servers have a pre-installed set of vulnerable services.

The task of the participants is finding vulnerabilities, closing them on your own and using them to retrieve private information (flags) from your opponents. The game is continuously monitored by the checking jury system, regularly placing new flags on the teams' servers. In addition, the system accepts from the teams flags captured from the opponents.

It is difficult to give a complete set of rules for a CTF challenge, so these rules can change without notice at any moment prior to game start. That is why we recommend checking the rules one more time before the competition starts. Just in case :)

A group of people led by the captain. The size of any team except the visiting team shall not exceed 7 members.
A vulnerable application specially prepared by the development team for the game.
A string that matches regex: /^\w{31}=$/. The lifetime of a flag is limited, obsolete flags do not affect the scoring of points.
Check system:
An automatic system that logs flags into the services, checks that the services are working properly and awards points. Scores are shown on the scoreboard along with the status of the services.
A virtual machine that contains all the services. It is provided prior to game start in a form of game image. Game image is identical for all teams.
Game round:
A period of time for the check system to check and score all the teams. Game round usually takes about 1 minute.
A group of people that run the competition. Organizers do their best to provide a quality and fun event to all participants. Still, organizers are to penalize/disqualify teams for rules violation and to solve the critical situations not described in these rules. Teams should be prepared to meet such decisions with understanding. Also, organizers do determine the winner. In general, this decision is based on the scoreboard.
  • Do whatever they want within their network segment.
  • Most likely, the team would like to patch vulnerabilities in their services or block exploitation of vulnerabilities;
  • Attack other teams. Didn't expect that, huh?
  • Attack the game infrastructure operated by organizers;
  • Attack the game infrastructure operated by organizers;
  • Generate excessive amounts of traffic that pose a threat to network stability of any other team
The game starts by issuing the participants identical servers with a pre-defined set of vulnerable services. For the first hour after the game image is issued, the network segments are closed, and teams should concentrate on administering their game server and analysing the vulnerabilities. After this hour, the network opens and for 8 hours teams can exploit vulnerabilities to gain flags from other teams.

It’s very important to read this section. We’ve made some changes in scoring rules in comparison to our previous competitions. Please read all the text carefully to avoid misunderstandings.

Key parameters in the scoring system are SLA and FlagPoints. Their values are individual for each service of each team. A team score is calculated as the sum of the products of the corresponding SLA and FlagPoints of all team's services.

def get_score(team):
    score = 0
    for service in services:
         score += SLA(team, service) * FlagPoints(team, service)
    return score

SLA(team, service) is the ratio of the number of rounds when the service was UP to the service lifetime. For instance, if the service is always UP, SLA will be 1. If 4 hours passed from the beginning (or from the deployment of the service) and the service is UP during the first hour and then is not UP for the rest 3 hours, SLA will be 0.25.

FlagPoints(team, service) is the number that correlates with a team’s understanding of the service. FlagPoints depend on a team's attack capabilities (exploiting vulnerabilities against other teams) and defense capabilities (fixing vulnerabilities in their own service). At the beginning of the game, all teams have equal FlagPoints.

Each flag has its base price. The base flag price is calculated at the beginning of the round when this flag has been generated. All flags created in one round for one service have an equal base price.

If team A submits the non-expired flag from service X of team B then FlagPoints(teamA, serviceX) is increased by the base price of flag X raised to the power of Motivation(teamA, teamB). At the same time FlagPoints(teamB, serviceX) is decreased by the same value but never goes below zero.

WTF is a degree Motivation(teamA, teamB)?

Shortly, it’s just

where pos A and pos B are the positions of team A and team B in the scoreboard correspondingly. Both pos A and posB are integers between 1 and teams_count.

As you can see, Motivation(teamA, teamB) is a non-negative number that is less than or equal to 1. If team A has less score in the game than team B (thereby posA > posB), then team A gets the base flag price for this attack. Otherwise, their income decreases as the distance between teams grows on the scoreboard.

This parameter motivates you to hack teams stronger than you ^_^

Fortunately, this complex logic can be implemented by the following code:

def motivation(teamA, teamB):
    posA = scoreboard.get_position(teamA)
    posB = scoreboard.get_position(teamB)
    if posA >= posB:
        return 1
    return 1 - (posB - posA) / (len(teams) - 1)
def on_attack(teamA, teamB, flag):
    price = flag.base_price ** motivation(teamA, teamB)
    flag_points[teamA][flag.service] = flag_points[teamA][flag.service] + price
    flag_points[teamB][flag.service] = max(0, flag_points[teamB][flag.service] - price)
How is the base flag price calculated?

As we said before, the base flag price doesn’t depend on the team, it is calculated at the start of the round and depends only on the service. For any flag it’s base price never changes. Base flag price is always more than or equal to 1.

Service lifetime is divided into 3 phases: «Heating», «Cooling down» and «Dying».

The Heating phase starts when the service becomes available (at the beginning of the game or when we decide to add it). During this phase, the base flag price starts at START_FLAG_PRICE points and grows by a constant HEATING_SPEED each round. If the heating phase lasts too long, the base flag price freezes at MAX_FLAG_PRICE and doesn’t increase further. The Heating phase finishes when a total number of different submitted flags by all teams reaches HEATING_FLAGS_LIMIT.

In the next round after the Heating phase has ended, the Cooling down phase begins. At this moment, the base flag price (that was reached by the end of the Heating phase) is multiplied by the preselected constant COOLING_DOWN, which is less than or equal to 1.

As before, the base price of new flags is updated at the beginning of the corresponding round. It decreases linearly with the number of successful flag submissions that have been made by all teams since the beginning of the Cooling down phase. The phase finishes when this amount reaches COOLING_SUBMISSIONS_LIMIT.

The last phase is Dying. At this stage, the base flag price is constant and equals DYING_FLAG_PRICE.





HEATING_FLAGS_LIMIT = 20 × teams count