Continuous CTF challenge deployments using Github Workflows

Andreas Pogiatzis
Nov 15, 2020 · 5 min read
Image for post
Image for post
Photo by Yancy Min on Unsplash

DevOps is an essential aspect of any software engineering project. On this note, CTF challenge design is no different. Being able to continuously push updates in a CTF challenge, and at the same time deploy it temporarily for testing, not only allows for better quality assurance practices, but it also gives the author the satisfaction (and bragging rights) when sending it over to fellow hackers to try it out!

In this context, this post provides a tutorial on how to continuously deploy your challenge by (ab)using the Github Workflows environment. Github’s Workflows feature allows developers to define and run workflow pipelines in a controlled environment using Github Actions as building blocks. Essentially, GitHub provides an ephemeral VM free-of-charge to run your workflows on. Interestingly, Github (or should I say… Microsoft) has been generous enough provide a workflow invocation timeout of 6 hours! Now the majority of the more common workflows that are used for packaging, deployment, testing do not exceed running times of an hour. But what if …. we make great use of this workflow time to host our challenge for a couple of hours? However, the problem is, that the workflow environment does not allow any ingress traffic, so how can people access the challenge, even if we host it there? Well…. there might be is a solution for that… keep reading.

Challenge Setup

First things first, you got to create a challenge right? Hopefully, you have already been through the hassle of challenge design and implementation so you should already have a challenge ready to be deployed! But if not, there is nothing to worry about! You can follow along with using a dummy pwn challenge I created for testing purposes. This is a containerized pwn challenge which simply prints back “Hello friend…” on any successful TCP connection.

In any case, I would greatly encourage you to always containerize your challenges with Docker so that you can always have full control over the environment that your code runs in. Details on how to achieve that, are out of the scope of this post, therefore, I trust that you are comfortable doing that. Feel free to tweak the code of the challenge to embed your challenge in the dockerized environment.

TCP Tunneling with Ngrok

Remember the problem stated above? In order to facilitate external access to our workflow environment, we can use an extremely handy tool called ngrok! With Ngrok we can bypass Firewall/NAT rules and expose localhost to the internet as depicted in the illustration below:

Source: https://medium.com/better-programming/ngrok-make-your-localhost-accessible-to-anyone-333b99e44b07
Source: https://medium.com/better-programming/ngrok-make-your-localhost-accessible-to-anyone-333b99e44b07
Source: https://medium.com/better-programming/ngrok-make-your-localhost-accessible-to-anyone-333b99e44b07

If this sounds interesting, I would encourage you to explore further details by visiting the origin post of the above image given in the caption.

As Ngrok allows for TCP tunnelling only to signed up members for free (with some limitations of course) go ahead and sign up for a Ngrok account here https://ngrok.com/. After signing in, you should be able to find an authorization token in your Ngrok dashboard.

Image for post
Image for post

Note that down because it will be used in the next steps.

Deployment Workflow

Now that we have a working containerized challenge, a Github workflow needs to be defined by creating a new YAML file in the .github/workflows/ directory. Create a new file called deploy.yaml in .github/workflows/ and paste the following workflow definition:

In the above workflow definition, we define 2 jobs to run in sequence whenever a new push is performed in the repository. The cancel job is an optional step to ensure that any previous workflows that are still running are cancelled in order to avoid having more than 1 workflows running at the same time. More importantly, the deploy job is where all the magic happens:

  1. The repository is checked out
  2. The challenge is deployed by running docker-compose up -d . Note that any other alternative command to deploy your challenge can be used here, but I always try to have single command deployments as it makes the process a lot easier.
  3. A custom Github Action is run which runs ngrok and tunnels any TCP traffic from/to port 4000. This is a Github Action that I published recently to abstract away some of the implementation details but if you are interested you can see the full source code of the action here.

You may have noticed the parameters, provided in the ngrok-tunnelling-action so let’s spend some time to explain those:

timeout: Keep in mind that the tunnelling step of the deploy job is blocking, that means that if not cancelled, the workflow will keep running until the timeout of 6 hours is hit. This parameter allows you to specify a shorter timeout when the full amount of 6 hours is not needed. This accepts numerous time units such as seconds or hours i.e. 100s , 2h

port: This specified the port that the traffic will be tunnelled to/from. This should be the port that your challenge exposes through the docker container.

ngrok_authtoken: This is simply your Ngrok authorization token acquired from the previous steps. Of course, since the token should not be visible in plain text, make sure it is defined in your repository secrets by navigating to your repository Settings -> Secrets -> New repository secret

Image for post
Image for post

We are almost done! Now, every time a new push arrives in the repository this workflow should be triggered! If everything went as planned, you should be able to navigate to your Ngrok dashboard and find the URL of your tunnel which can be used to access your challenge!

Image for post
Image for post
Ngrok tcp tunnel

Let’s go ahead and test this out!

Image for post
Image for post

Awesome! Works like charm! You can find the full code for this post in this repository:

There is definitely a lot of room for improvements so feel free to tweak/extend anything you like. Remember that the workflow definition can be amended so that is triggered only when a new release is created if that works better for your use case.

Any feedback is always much appreciated!

InfoSec Write-ups

A collection of write-ups from the best hackers in the…

Sign up for Infosec Writeups

By InfoSec Write-ups

Newsletter from Infosec Writeups Take a look

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Andreas Pogiatzis

Written by

☰ PhD Candidate @ UoG ● Combining Cyber Security with Data Science ● Writing to Understand

InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. In a nutshell, we are the largest InfoSec publication on Medium. Maintained by Hackrew

Andreas Pogiatzis

Written by

☰ PhD Candidate @ UoG ● Combining Cyber Security with Data Science ● Writing to Understand

InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. In a nutshell, we are the largest InfoSec publication on Medium. Maintained by Hackrew

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store