👍Rules of Thumb
Documentation rules them all
I will not sugar coat this, this is the hardest part of every challenge for me. There are never enough details that you can put into the document. Your players will always ask something that you haven't predicted and you'll have to go to the source code of the challenge.
What I do to keep those to a minimum are as follows:
All challenges are on a single repository
Each challenge has its own
README.md
general purpose documentation that outlines some basic concepts of the challenge / machine explainingthe premise of the scenario
solution steps (eg
1. user does that...
)references to sources and material used during build
exploitation, detailed exploitation steps with copy/paste-able material
Challenges that run complicated applications also have an
ADMINISTRATOR.md
with administrative details and commands used to manage themWRITEUP.md
: A complete solution, preferably written by someone else who will also provide feedback
The documentation is not just for you
Depending on the team that provides support to the players some of these documents will be eventually shared with them. This is why you have to create the separate documents. You can give access to the README and ADMINISTRATOR documentations but not the WRITEUP. Its not about "trust" its about keeping it fair for everyone.
Keep local copies
In this day and age its hard to believe that anyone would want to keep a "backup" of a publicly accessible github repo but you'll be surprised at what can happen between the time you conceive your idea, develop and finally run it.
Repositories get moved around without notice, others truncate their history, others close all together, others will remove their vulnerable release version, other projects change names repos and history altogether. These and many more similar cases await you.
Create a folder, say ./assets/
, and use it to store there releases and the specific packages that your challenge or machine depends on.
You will thank me later for that...
Its not you vs players
Content creators often fall into the trap of feeling like its them against the player, when in reality it is not.
People try to harden their boxes, patch this and that to force the players on a very specific exploitation that they had in mind. STOP DONT DO THAT. Why do you expect that everyone should be thinking the same way you do?
One of the best things about creating content for CTF's is that you get to see all those crazy minds at work. See and learn from the ideas that all those participants will come up with in trying to solve your challenge.
My belief is that a smarter and more talented player should always be able to outsmart me. And that is a good thing 😄
The difficulty rating
The difficulty rating is one of the hardest things to do "accurately" and the truth is you will never get it just right, because its impossible to do.
Every player that approaches your challenge/machine has different background, experience and inspiration at that given time.
You will always get mixed results even if you are perfect at rating them:
you will get experienced players that find hard challenges easy and easy challenges hard
you will get noob players that will find easy challenges hard and hard challenges easy
The difficulty rating when it comes to a CTF has to take into consideration a lot of factors.
Is it online or onsite CTF
In online CTF's players work from the comfort of their systems which makes it a lot easier to research a certain subject.
Onsite events tend to put the players under more "stress" and thus a challenge that would normally take 40 minutes might take 1 or 2 hours.
The duration of the even
What is the total duration of the event? Is it going to be 3-4 hour event or entire day?
I try to make sure that for every individual participant there are enough challenges to go around. I try to make each of my challenges/machines in such a way that among all of them it will take, on average, 45 minutes to be solved by a normal player.
So depending on the duration of the even the i have as many targets and challenges as it will take to go just a tini bit above my mark. So for an 8 hour event, 460 minutes event / 45 minutes per machine ≃ 10 machines. Just to be safe i always prepare a few extra challenges usually a bit more hard than the rest, so as to keep any outliers occupied and serve as a buffer until the CTF concludes.
The estimated duration of the challenge
Team or individual participation
The difficulty changes over time
Even if you take everything into account and you manage to somehow nail the difficulty rating when the challenge/target was published, be ready for a disappointment. It is generally observed that difficulty of most challenges go up or down as time passes by.
But how could this be possible you may ask? Here are a couple of examples:
The challenge you developed require a specific version of a tool that is no longer easy to find making it harder to solve (eg older versions of chrome are harder to find)
The challenge/machine depends on technologies or architectures that are not generally available (ie SGI IRIX Unix was relatively easy to come by both systems and exploits back when the machines were still in circulation, nowadays not so much)
The challenge/machine is on subjects that are generally more well known (eg such as sql injections, started as something rare, now everyone seems to know how to do at least the basics)
The unsolvable challenge/machine
I've seen countless challenge creators brag about their unsolvable challenges and how crazy their scenario was that nobody thought about it...
Let me tell you a little secret, if a challenge stays unsolved because it was so hard that nobody could have solved it, then you failed as a challenge creator!
There is only ONE reason you make a challenge and that is to be SOLVED (eventually).
Keep in mind that this does not include challenges that players were unable to complete due to time running out. We're talking about challenges that under no normal circumstances someone could have solved them in the given time of the entire CTF.
docker containers
volumes
Make sure your container images have no volumes. Volumes solve a very specific problem with containers and that is persistent storage. Volumes allow containers to store data to be used and shared among them, even across restarts.
Volumes can be defined using the VOLUME
statement inside your Dockerfile
or by using an image that already has one, such as mysql. The first case is easy to spot, check your Dockerfile
for VOLUME
statements, in the later case though it gets a bit trickier.
The only 100% way to avoid having volumes inherited by your containers, is to write the entire Dockerfile
yourself. The usual docker inspect
, docker image inspect
commands will come in handy, as well as docker volume ls
.
As a last resort you can always run the image and see what volumes got created 😂
readonly
healthchecks
Last updated