Kyung Hee University's SW Security Competition: From Concept to Reality

Kyung Hee University's SW Security Competition: From Concept to Reality
Rome, Italy 🇮🇹

Introduction

Hi, I'm Seokchan Yoon. It's been a long time that I'm posting an article on my new blog 😅

Last year, in 2022, I had the honor of organizing a security competition for the students at my university, Kyung Hee University in Korea. It was a unique experience that I will always cherish.

Most security competitions follow a common format called 'CTF' (Capture The Flag) with Jeopardy. As a CTF player, I'm sure you won't disagree with me on this. Actually except for the special CTF such as Def Con, etc.

Although playing this CTF was still fun, but I found it a bit too predictable and lacking in novelty. So, I decided to create a new form of CTF. As luck would have it, I had some knowledge about Docker and was aware that I could automate a series of Docker commands using the Docker SDK in Python. This gave me the idea to develop a 'Secure Coding Competition System' using automated Docker commands in Python. Without wasting any time, I got started right away!


Motivation to new form of CTF

In 2021, I had the opportunity to participate in CCE (Cyber Conflict Exercise & Contest), which is one of the biggest CTF in Korea, organized by the Korean National Intelligence Service (NIS). This competition had a unique format compared to others. Instead of just providing challenges like jeopardy format, the administrators give each team instances to work on, and we have to access them through SSH and patch hidden vulnerabilities and backdoors to maintain our team's score.

During the competition, an automated tool ran every 30 seconds to check the health, functionality, and vulnerability of the instances. If it detected any issues, such as security vulnerabilities or incorrect functionality, it would decrease our team's score. This made the competition more thrilling for me, and I was particularly fascinated by this new format.

So I came up with an idea to automate this series of processes (managing instances, checking instance health, functionality, and security) using Docker SDK. I plan to implement this mechanism on my CTF platform, which will include functions such as creating vulnerable instances, giving users access-point to the instances, and checking their functions to ensure that they run securely and properly.

>>> import docker
>>> client = docker.from_env()
>>> client.containers.run('alpine', 'echo hello world')
b'hello world\n'
Docker SDK example

How could I implemented this?

1. Docker SDK

Docker SDK (Software Development Kit) is a set of APIs and libraries that allow developers to interact with the Docker daemon programmatically. You can use docker commands, which can be used by docker [command] form, in your python code.

Docker SDK for Python — Docker SDK for Python 6.0.1 documentation

This library is like a http client for the Docker Engine API. As you know, docker commands use internal HTTP API via unix socket mounted on /var/run/docker.sock. You can understand what we can do for using 'Docker SDK' by refering to code examples below.

>>> import docker
>>> client = docker.from_env()
>>> client.containers.run('alpine', 'echo hello world')
b'hello world\n'
Using echo command in alpine image
>>> client.containers.list()
[<Container '45e6d2de7c54'>, <Container 'db18e4f20eaa'>, ...]
>>> container = client.containers.get('45e6d2de7c54')
>>> container.attrs['Config']['Image']
"bfirsh/reticulate-splines"
>>> container.logs()
"Reticulating spline 1...\n"
>>> container.stop()
Managing your containers

I could automate a set of Docker commands using this library.

2. Dockerizing

You can also dockerize a service using the Docker SDK, as shown below. Provide the base_url parameter with a Unix socket like this:

import docker
client = docker.DockerClient(base_url='unix://var/run/docker.sock')

By doing so, you can conveniently interact with the Docker service through the SDK. Additionally, to interact with the Docker service from within a container, you must mount the /var/run/docker.sock file inside the container. This allows the container to communicate with the Docker daemon running on the host system.

3. Django Inheritance

As I analyzed Django to find a security vulnerability, I gained a good understanding of its structures. Django is well-structured using Object-Oriented Programming techniques, and I realized that by using class inheritance, I could easily map Docker commands and automate them.

For example, you can get docker container with code as below.

import docker
from django.db import models
from util.docker import client


class ContainerManager(models.Manager):
    def get(self, **kwargs):
        try:
            container = super().get(**kwargs)
        except Container.DoesNotExist:
            return None
        
        try:
            client.containers.get(container.get("name"))
        except docker.errors.APIError as error:
            return None
        
        return container


class Container(models.Model):
    name = models.CharField(max_length=128)
    image = models.CharField(max_length=64, null=True, blank=True)
    environment = models.TextField(default=None, null=True, blank=True)
    ssh_port = models.IntegerField(default=None, null=True, blank=True)
    ports = models.TextField(default=None, null=True, blank=True)
    
    objects = ContainerManager()
container/models.py

4. Implementing WEB IDE

I had concerns about potential hackers trying to ruin my server if I provided them with SSH credentials. Additionally, some of my friends were unfamiliar with Linux bash commands. So I decided to implement a system that provides a web-based IDE instead of using SSH.

I discovered a browser-based web IDE library called 'Monaco', developed by Microsoft. It is user-friendly and easy to use, as it shares a similar interface with Visual Studio Code.

GitHub - microsoft/monaco-editor: A browser based code editor
A browser based code editor. Contribute to microsoft/monaco-editor development by creating an account on GitHub.

To sum up, I created this WEB IDE using React and Flask. In React, I implemented a WEB editor based on the Monaco library, and in Flask, I implemented the functionality to read and write files in specific directory paths. And then I dockerized it as a Docker image for its reusability.

The process of creating a Docker container for running a WEB IDE based on the created Docker image is as follows:

  1. Run a container based on the vulnerable service image.
  2. Copy the source code files from the target_dir path stored in the Challenge model to the host OS.
  3. Delete the container that was run in step 1.
  4. Run the image containing the WEB IDE to execute the Docker container for running the WEB IDE.
  5. Copy the source code files from the container to the WEB IDE.
  6. Display the WEB IDE container access information (such as port) to the user.

5. SLA checking

SLA checking can be seen as a process of verifying the availability and vulnerabilities of a service. I took a long time to implement this feature. The steps to explain the process are as follows:

  1. Extract the user-modified files from the WEB IDE container to the host OS.
  2. Create a container for the build purpose.
  3. Copy the files extracted in step 1 to the container created in step 2.
  4. Perform the commands specified in the TestCase model designated by the problem setter and store the results.

The code for the 'TestCase' model for reference is below.

class TestCase(models.Model):
    """
    TestCase for SLA check
    """
    TYPES = [
        ("VULNERABILITY", "Security vulnerability check"),
        ("AVAILABILITY", "Availability check")
    ]
    
    type = CharField("TestCase Type", max_length=32, choices=TYPES, default="VULNERABILITY")
    challenge = ForeignKey(to=Challenge, on_delete=CASCADE, verbose_name="Problem")
    title = CharField("TestCase Title", max_length=256, null=False, blank=False)
    command = TextField("Command for TestCase check")
    success_text = TextField("Return value on success")

    def __str__(self) -> str:
        return f"Challenge-{self.challenge.id} / TestCase-{self.id}"
challenge/models.py

The container used for building in the above process contains a python file for checking vulnerability and availability. In the command field of the TestCase model, I stored "python3 /test.py", and if "SUCCESS" is printed, the server determined that there is no problem in availability or vulnerability test.


Demo Video 🚀

The video below is the system demo video that I implemented last year. This video shows the process of fixing SQL Injection vulnerabilities in PHP source code, checking SLA, and scoring points.

0:00
/
Demo for Secure Coding Competition System

Finally, I finish this article hoping that my experience has given you a new inspiration. Thank you 😄

* This article was translated and reconstructed based on what I posted on the company's technical blog.

STEALIEN Technical Blog
Secure Coding Training System 개발기