How to run docker for CTF

How to run docker for CTF

Created
2/28/2021, 8:28:00 AM
Last edited
3/1/2021, 6:26:00 AM
Tags

Intro

얼마 전 열렸던 2021 TRSUT CTF에서 문제 출제, 문제 서버 구축 및 대회 운영을 하게 되었었습니다.
대회를 준비하면서 일반적으로 Docker를 사용해 문제 서버 구축을 하게 되는데,
Docker를 평소 많이 접해보지 않았던 분들은 이런 과정에 어려운 점이 다소 있으리라 생각했습니다.
그래서 누구나 쉽게 문제 서버 구축을 할 수 있도록 정리해봤습니다.
이 문서가 조금이나마 도움이 될 수 있었으면 좋겠습니다 ;)
혹시 이해가 안 가는 부분이나, 질문 사항이 생기신다면 편하게 개인적으로 연락해 주시면 되겠습니다!

Docker

What is Docker?

Docker란, 경량화된 Container 기반의 오픈소스 가상화 플랫폼을 말합니다.
Docker를 사용하면 각 Docker Image들을 Container라는 형태로 독립적으로 운영할 수 있습니다.
Docker Image란 원하는 서비스나 프로세스들을 Docker에서 Container로 실행할 수 있도록 설정한 것을 말합니다.
이런 Docker Image를 제작하는 것을 Docker Image를 Build한다고 합니다.

Why Docker?

왜 CTF 문제 서버 구축을 하는 데 Docker를 사용하는지 의아해하시는 분들이 계실 수 있습니다.
가장 큰 이유는 일반적으로 CTF 문제라 하면 문제 의도 상, 시스템 혹은 서비스의 취약한 부분을 공격하여 FLAG를 탈취하는 것인데,
각 문제를 같은 서버에서 서비스하게 되면 이 과정에서 다른 문제에 간섭하거나 시스템에 악영향을 끼치는 등 의도치 못한 상황이 발생할 수 있습니다.
그렇다고 각 문제를 모두 다른 서버에서 서비스하게 되면 비용이 많이 발생할 수 있습니다.
그래서 Docker를 사용하여 각각의 문제들을 하나의 서버에서 Host나 다른 Container와는 격리된 상태로 운영하는 것입니다.

Installation

Docker는 다음과 같은 방법으로 설치 및 실행할 수 있습니다
$ curl -fsSL https://get.docker.com/ | sh $ service docker start
Bash
또한, 여러 개의 Docker Container들을 한꺼번에 관리할 수 있게 해주는 Docker Compose는 다음과 같은 방법으로 설치할 수 있습니다.
$ apt install docker-compose
Bash

Configuration

아래 구성 방식은 제가 Pwnable 문제 Docker를 구축할 때 일반적으로 사용하는 구성 방식입니다.
그러므로 일부 문제에 대해서는 아래 방식이 부적합할 수 있습니다.

File Tree

우선, 폴더 및 파일들은 다음과 같이 구성합니다.
. ㄴ example | ㄴ share | | ㄴ example | | ㄴ flag | ㄴ Dockerfile ㄴ docker-compose.yml
Plain Text
여기서 share 폴더의 파일들은 Build된 Docker Image의 /home/$USER 폴더에 복사되게 됩니다.

Dockerfile

Dockerfile 은 Docker Image를 Build 할 때 참조하는 파일이며, 다음과 같이 작성합니다.
ARG IMAGE FROM $IMAGE ARG APT_OLD RUN /bin/bash -c \ 'if [ $APT_OLD -eq 1 ] ; then sed -i -re "s/([a-z]{2}.)?archive.ubuntu.com|security.ubuntu.com/old-releases.ubuntu.com/g" /etc/apt/sources.list ; fi' ENV DEBIAN_FRONTEND noninteractive RUN apt-get update -y > /dev/null RUN apt-get upgrade -y > /dev/null RUN apt-get install xinetd -y > /dev/null # custom installation # RUN dpkg ~ # RUN apt install ~ # RUN pip install ~ ARG USER ARG TIMEOUT ARG EXEC RUN useradd -ms /bin/bash $USER ADD ./share /home/$USER RUN echo "#!/bin/bash\ntimeout $TIMEOUT /home/$USER/$EXEC" \ > /home/$USER/run.sh RUN chown -R root:$USER /home/$USER RUN chmod -R 750 /home/$USER ARG SERVICE RUN echo "service $SERVICE\n{\n\tdisable = no\n\tflags = REUSE\n\tsocket_type = stream\n\tprotocol = tcp\n\tuser = $USER\n\twait = no\n\tserver = /home/$USER/run.sh\n\ttype = UNLISTED\n\tport = 8080\n}" \ > /etc/xinetd.d/$SERVICE CMD ["/usr/sbin/xinetd", "-dontfork"]
Docker
여기서 패키지 설치가 추가로 필요한 경우, custom installation 부분에 추가하시면 됩니다.

docker-compose.yml

docker-compose.yml 은 다음과 같이 작성합니다.
version: '3' services: example: container_name: example build: context: example args: IMAGE: ubuntu:16.04 USER: example TIMEOUT: 60 EXEC: example SERVICE: example APT_OLD: 0 ports: - "8080:8080" restart: always
YAML
여기서 각 field에 대한 설명은 아래를 참고하여 설정해주시기 바랍니다.
services : 실행될 서비스명을 지정합니다.
container_name : 실행될 Container명을 지정합니다.
context : Build할 폴더를 지정합니다.
IMAGE : Build에 사용할 Docker Image를 지정합니다.
USER : Build된 Docker Image에서 사용할 User명을 지정합니다.
TIMEOUT : 서비스할 파일의 timeout을 지정합니다.
EXEC : 서비스할 파일을 지정합니다. (/home/$USER 폴더 기준)
SERVICE : xinetd 서비스명을 지정합니다.
APT_OLD : 1로 지정할 시 apt 설치 시 old repository에서 설치합니다.
ports : 서비스 할 때 사용할 port를 지정합니다.

Run Docker

구성된 Docker는 docker-compose.yml이 있는 폴더에서 아래와 같은 방법으로 실행합니다.
$ docker-compose up -d --build --remove-orphans --quiet-pull
Bash
또한, 아래와 같은 방법으로 중지할 수 있습니다.
$ docker-compose down
Bash