Welcome to the Debugmen blog. We use this site to post tools, security findings, CTF writeups and anything else we find worthy of release to the public.

Custom CTF Platforms: Part 2

This is part 2 of the Custom CTF Platforms posts, where I explain some of the features and mistakes I made in the CTF platforms I have created

The Newest Platform

This platform was created about 2 years after my first platform, my friends and I had messed with a few other versions in between these two, however this one contains most of the features of all the platforms combined. When I started this version, CTFd 1.0 still hadn’t been released yet, I don’t exactly remeber correctly if ctfs were using a beta version of CTFd but I would imagine so.

My orginal team “Some Assembly Required” all graduated high school and we slowly stopped playing ctfs together and I did pretty much all the development for this final version, however my teammates helped out a lot in the prior version so I luckly did not have to do as much front end development.

Since I was mostly working alone, I neglected good development practices and only made 3 commits.



Because most of the design was created as a group with my teammates, I think the overall design looks much better than the orginal blue theme.

Main Page


We had a navbar containing links to:

  • Challenges
  • Scoreboard
  • News
  • About
  • Learn
  • Login
  • Register

Register Page

A couple extra fields were added since the first version. An affliation field and a password confirmation field.


Now, we added some restrictions to teamname and password and had a check for a valid email address.

Creating a team redirects to the main page and has a little notice saying team created. Not sure why I removed email verification.

Reset Password

Theres a reset page as well but was unimplemented.


Login Page

Login Page was a seperate page unlike the orginal version where you could login from any page.


Logging in redirects to the challenges page.

Challenges Page

Again, challenge categories were hardcoded.


A graph at the top was added to show solve counts for each challenge.

Clicking a challenge box this time lead to a challenge page.


A graph was added to show correct/incorrect submissions and this time individual flag submission forms and hints button.


The schema for a challenge is:

  create_table "challenges", force: true do |t|
    t.string   "title"
    t.string   "description"
    t.integer  "value"
    t.string   "hint"
    t.integer  "solves"
    t.integer  "submits"
    t.string   "category"
    t.datetime "created_at"
    t.datetime "updated_at"

And there was a relationship with the teams table:

  create_table "team_challenges", force: true do |t|
    t.integer  "team_id"
    t.integer  "challenge_id"
    t.datetime "created_at"
    t.datetime "updated_at"

Notice how a challenge record does not include a flag. I don’t know why I didn’t create a real relationship between a challenge and a flag.

The flag structure was:

  create_table "flags", force: true do |t|
    t.string   "grader"
    t.integer  "challenge_id"
    t.datetime "created_at"
    t.datetime "updated_at"

A flag was associated to a challenge by its challenge id and contained a path to a grader. A grader was created for each challenge. An example of a grader is:

class Grader
	def check(guess)
		guess = guess.downcase
		if guess=="flag{therac-25}"
			return true
		elsif guess == "flag{therac 25}"
			return true
		elsif guess == "flag{therac25}"
			return true
		elsif guess=="therac-25"
			return true
		elsif guess == "therac 25"
			return true
		elsif guess == "therac25"
			return true
			return false

This allowed for multiple ways to validate if a flag could be correct.

An example of creating a challenge through ruby is:

Challenge.create("title"=>"Song of my People","description"=>"I am a <a href='/challenges/songofmypeople.wav' target='_blank'>Robot</a>","hint"=>"I speak 1s and 0s","value"=>175,"solves"=>0,"category"=>"Misc").flag = Flag.create("grader"=>"songofmypeople.rb")

From the solves list on the challenge page, you can navigate to their team page.

Team Page

Team Page contains a couple graphs and a list of the solved challenges.

pic1 pic1

The challenge links back to the challenge page.


The scoreboard shows a graph of the solve times of the top 5 players.

The admin account is shown on the graph but hidden on the scoreboard.


Clicking a team on the scoreboard links to their team page.


The news schema is pretty similar to the orginal version but an author field is added:

  create_table "news", force: true do |t|
    t.string   "author"
    t.string   "title"
    t.string   "text"
    t.datetime "created_at"
    t.datetime "updated_at"


Not sure why I flipped it this time and newer posts were placed at the bottom.


About page just had info about what is a ctf and what the rules were.


Taking from picoCTF, where they had a learn page. We attempted to write a little about each category. Pretty much none of this information is useful.


Lessons Learned

I hate webdev, still missing a lot of features that standard for most ctf platforms. Ruby on Rails is pretty cool and as much as I hate webdev, I sorta want to work with Rails and see what cool features they have added in the past few years.

We never ran a real ctf off this platform so who knows what bugs and edge cases I missed.

Still need an admin panel, I actually had some code set up for an admin panel but really never implemented anything.

<% if current_team %>
	<li><a style="color: #C90000" href="/team/<%=current_team.id%>">			<%=current_team.name%> : <%=current_team.score%> points </a></li>
	<li> <a href="/logout" class="nav_link" >logout</a></li>
	<% if current_team.is_admin==1 %>
		<li><a href="/admin">Admin Panel</a></li>

All tags