So every now and then I give introductory courses to embedded systems security. To keep the students engaged, I mix in a CTF: most practical cases are actually challenges that earn points. At the end of the course, the team that has gained the most points wins a prize.
In the first iterations of the course, the students were asked to call me upon so that I could check their answer. The main issue with this approach is its lack of fairness: if two teams find the right answer at the same time, who wins is arbitrarily determined by which raised hand I saw first.
To solve this issue, I decided to deploy a CTF management web portal. After some research, I decided to use CTFd [1]. The platform is open source, but the developers also offer managed services. As I have a very low volume of users (between 8 and 15), I decided to self-host it.
My usual goto is CentOS 7.0. However, having never set up a Python Web Server before, I chose to follow the developers recommendations and used Ubuntu 18.04. Since my VPS does not run on Docker but on LXC, using a prebuilt image was not an option.
Installing CTFd
This is done starting from a fresh, fully updated Ubuntu 18.04. CTFd will be ran through gunicorn to serve the Python web service using a low privilege user.
The CTFd GitHub Wiki actually talks about using uwsgi, but I could not get it to work properly (challenge submissions failed) and the developers recommended that I use gunicorn instead.
Install the dependencies:
You now have a CTFd instance running on port 8000! I recommend that you put a reverse proxy (e.g. Nginx) in front of it to do static content caching and SSL, put that’s up to you.