HC's CTF site

Writing a CTF service

This document describes the basics of writing a CTF service. If you plan to write a CTF service for a real CTF, you should also read Writing good CTF services.

Purpose of a CTF service

A CTF service is a program serving network connections, usually implementing a more or less well known protocol like HTTP or IRC. A CTF service is specifically designed for a CTF contest and contains specially crafted security holes.

Each team participating in a CTF hosts an internet server with the CTF services running. To make deployment as easy as possible and to create a homogenous environment, a so called "vulnerable image", a hard disk image of an operating system (usually some UNIX flavour) with all services pre-installed, is created and supplied to all participating teams. All teams run this image, using vmware, virtualbox, qemu/kvm, or a similar software.

The task of the CTF participants is to find vulnerabilities in the CTF services to:

  1. Fix them on their own machine
  2. Exploit them on other teams' machines
  3. Report advisories

When writing a CTF service, you have to pay special attention to point 2. Creating security holes that can be exploited in a way measurable by the gameserver (the gameserver does all the scoring calculation) is the hardest thing about writing a CTF service. How it's done is described below.

Most services are supplied with full source code. Usually, one or two simpler services are provided with obfuscated source code, or even binary only.

Anatomy of a CTF service

Most CTF services are rather complex, but their primary design is simple. The most basic CTF service must be capable of two things:

  1. Receive and store arbitrary key, value pairs
  2. Answer to requests from anyone, sending the value of a previously stored key, value pair if the correct key was supplied

Note: In CTF terms, values are called flags, while the keys are called flag ids.

The gameserver distributes flag id, flag pairs to all services of all teams, remembering which flag was sent to which team. If a team later gains access to a flag belonging to another team, it can report that flag to the gameserver, receiving an offensive point in return. All flags not reported by teams within a certain period of time are considered "defended" by the scoring bot, if it is able to retrieve the flag by sending the according flag id to the service that was used to store the flag in the first place.

Consider the implications of Rule #2. Any person knowing a flag ID can retrieve the corresponding flag. While anyone may store flags with any service, only the scoring bot knows the flag ids that are associated with the "official" flags, the ones that earn a team offensive points if "captured".

This implies the service does not have to grant special privileges to the scoring bot. In fact, a CTF wouldn't work if it did. Any service must treat the scoring bot just like any other user of the service. The only thing the scoring bot knows other users of the service do not know is the flag ids of the "official" flags.

A simple example

For the easterhegg CTF, I wrote the simplest service ever, capable of doing just the two operations described above. Since it was so simple, I decided to obfuscate it before putting it on the vulnerable image. You can have a look at the non-obfuscated version here, along with its testscript.

The meaning of flags and flag ids

Flags and flag IDs represent real world data. Let's say you're writing an ATM software. Think of a flag ID as the account number; the flag might represent the current account balance. Do not implement ATM functionality, then some flag/retrieval functionality. Use the ATM functionality to store and retrieve your flags.

Keep that in mind. Be creative when writing your CTF service. I've seen people write CTF services with the most complicated functionality and then -- when everything else is finished, they implement flag storage and retrieval functionality, which is silly.

Make your service as complicated as it goes. Then think how you can use all the complexity to store and retrieve flags. Again, think of flags as confidential real world data. It makes your service much more interesting to crack.

The testscript

After having written your service, you'll need to tell the game server how to contact your service to store and retrieve the flags. That's what a testscript does.

You can write a testscript in any programming language, but it is recommended to use a scripting language like python or ruby -- not recommended is java, because it has a huge overhead on startup, and test scripts are run multiple times per second at times.

A test script is called with the following command line parameters:

testscript store|retrieve IP FLAGID FLAG

The store parameter instructs your testscript to store a flag with the specified flag id at IP. Later, your testscript is instructed to retrieve that flag from the same IP.

You indicate to the gameserver whether the request was successful or not by returning an error code. See the error code table for a list of all possible return values. In addition to returning an error code, you should return a text message that will be publicly viewable on the scoring board. Just write some text shorter than 256 bytes to stderr -- without a carriage return at the end.

The following assumptions can be made for testscripts:

  • Only one instance of a testscript runs per IP (store or retrieve)
  • Other than that, multiple instances of any testscript may run simultaneously

Check out my CTF game server for a more information on how to implement testscripts

$Id: services.html 532 2009-02-08 21:18:13Z root $ Impressum