1. 문제 생성하기
드림핵에 워게임 문제를 생성하는 방법을 알아보겠습니다.
워게임 문제 업로드 페이지에 접속하면 아래 사진과 같은 화면이 나옵니다.

워게임 문제는 내부적으로 Git 리포지토리 형태로 관리됩니다. 문제를 만들기 위해 가장 먼저 해야 할 일은 문제에 사용할 Git 리포지토리 이름을 지정하는 것입니다. 위 사진에서 아래쪽 빨간 네모로 표시된 부분에 워게임 문제가 사용할 Git 리포지토리 이름을 입력해주세요.
리포지토리 이름에는 Hyphen(-), Underscore(_), a-z0-9 문자만 사용해주세요.
한편 위 사진에서 위쪽 빨간 네모로 표시된 부분의 문제 이름 입력란은 Git 리포지토리 이름을 자동으로 추천하기 위한 도우미입니다. 실제로 이용자들에게 표시될 최종적인 문제 이름은 이후 업로드하는 버전에 따라 자유롭게 변경할 수 있습니다.
약관에 동의한 후 문제 생성하기 버튼을 눌러서 문제를 생성하고 나면 아래 사진과 같은 화면이 나오게 됩니다.

2. SSH 키 생성하기
워게임 문제에 사용될 파일은 Git을 이용해 업로드할 수 있습니다. 앞서 생성한 문제의 Git 리포지토리에 접근하려면 먼저 SSH 키를 드림핵 서버에 추가해야 합니다.
🔑 SSH 키를 생성한 적이 없다면 본 링크를 통해 자세히 알아보시기를 바랍니다.
SSH 키는 내 계정의 SSH 키 설정 페이지에서 추가하거나 삭제할 수 있습니다. SSH 키 추가를 정상적으로 마쳤다면 다음의 셸 명령어를 통해 SSH 키가 드림핵 서버에 잘 등록되었는지 확인할 수 있습니다.
ssh -T git@git.dreamhack.io
위 명령어를 실행하면 아래 결과와 같이 Welcome to DreamHack, @userid! 형태로 출력되어야 합니다.
$ ssh -T git@git.dreamhack.io
Welcome to DreamHack, @userid!
3. Git 리포지토리 복사하기
앞서 생성한 문제의 Git 리포지토리를 로컬에 복사해보도록 하겠습니다. 아래 사진에서 빨간 네모로 표시된 부분을 클릭하면 Git 리포지토리를 복사하는 명령어(git clone)를 클립보드에 복사할 수 있습니다.

복사한 명령어를 셸에 붙여넣고 실행하면 아래와 같이 출력됩니다.
user@machine:~/$ git clone git@git.dreamhack.io:[repository-name].git
Cloning into '[repository-name]'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), done.
user@machine:~/$
현재
git init명령어를 통해 직접 생성한 리포지토리를 워게임 시스템에 복사해 넣는 행위는 지원되지 않습니다.
4. 문제 파일 구성하기
하나의 워게임 문제의 리포지토리에는 다음과 같은 파일과 디렉토리를 필수적으로 구성해야 합니다.
Specfile- 문제에 대한 자세한 설정을 기술한 파일입니다.
- 아래의 예제 파일을 복사하여 문제에 필요한 형태로 설정을 작성합니다.
Description.md- 문제에 대한 설명을 작성하는 파일입니다. Markdown 포맷으로 작성합니다.
- 문제에 대한 정보나 문제를 해결하기 위해 필요한 단서를 기술하는 등의 문제와 관련된 내용을 적을 수 있습니다.
public/- 문제를 푸는데 필요한 파일들을 포함하는 폴더입니다.
- 이 폴더의 파일들은 문제에 접근하는 모든 사용자가 자유롭게 다운로드할 수 있습니다.
만약 VM을 필요로 하는 문제라면 추가적으로 다음과 같은 파일을 필수적으로 업로드해야 합니다.
-
Dockerfile-
Docker 컨테이너를 만들기 위한 설정을 기술한 파일입니다.
-
자세한 내용은 Dockerfile Reference를 참조해 주세요.
-
Docker version을 명시할 때는,
FROM ubuntu:22.04보다는FROM ubuntu:22.04@sha256:b6b83d3c331794420340093eb706a6f152d9c1fa51b262d9bf34594887c2c7ac와 같이 베이스 이미지의 SHA256 해시값을 함께 명시해주는 것을 권장합니다.
-
베이스 이미지의 SHA256 해시값은
docker inspect [Image Name]이후RepoDigests값을 사용하면 됩니다.
e.g)docker inspect ubuntu:22.04 -
libc file은 익스플로잇 과정에서 필요하다면
public/에 넣어주는 것을 권장합니다.
-
Specfile
모든 Specfile에는 [wargame] section이 필수적으로 포함되어야 하고, VM을 필요로 하는 문제라면 [vm] section이 추가적으로 포함되어야 합니다.
[wargame] section
[wargame] section에는 다음과 같은 속성들이 필수적으로 작성되어야 합니다.
- title
- 문제를 대표하는 제목입니다.
- 정해진 서식이 없으며 자유롭게 설정할 수 있습니다.
- flag
- 문제를 해결한 뒤 획득할 수 있는 Flag입니다.
- 정해진 형식은 없지만 유추하기 어렵게 작성하는 것이 이상적입니다.
- tags
- 문제에 해당하는 분야를 태그합니다. 모든 문제는 하나 이상의 태그가 지정되어야 합니다.
- 다음과 같은 태그들을 사용할 수 있으며, 이외에도 적절한 태그를 사용할 수 있습니다.
pwnablereversingwebcryptoforensicscloudmisc
[vm] section
[vm] section에는 다음과 같은 속성들이 필수적으로 작성되어야 합니다.
- os
- VM에서 사용하는 운영체제의 종류를 지정합니다.
- 다음과 같은 운영체제를 사용할 수 있습니다.
linux
- memory
- VM 인스턴스가 사용하는 최대 메모리 크기를 MB 단위로 지정합니다.
- disk
- VM 인스턴스가 사용하는 최대 디스크 크기를 MB 단위로 지정합니다.
- ports
- 외부에서 VM으로 접근할 수 있는 포트를 지정합니다.
- comma(
,)로 구분된[port]/[protocol]형태의 쌍 목록을 사용하여야 합니다.- protocol로는
tcp와udp를 사용할 수 있습니다.
- protocol로는
- allow_outgoing
- VM이 외부 네트워크에 접근할 수 있는지 여부를 지정합니다.
true또는false의 값을 사용할 수 있습니다.
- docker_compose
docker-compose를 활용하여 이미지를 빌드합니다.- 해당 옵션을 지정하는 경우
Dockerfile이 아닌docker-compose.yml파일을 요구합니다.
필요한 메모리 및 디스크 크기는 실제로 Docker를 사용해 image를 생성하고 container를 실행하는 것으로 필요한 크기를 확인할 수 있습니다.
Image의 크기는docker image명령어를, 메모리의 크기는docker stats명령어를 통해 확인할 수 있습니다.
필요한 공간의 최소화를 위해 Base image는
slim혹은alpine버전을 사용하는 것을 권장합니다. 빌드하는 시간을 단축시킬 수 있으며, 디스크 크기 문제로 인한 에러를 크게 줄일 수 있습니다.
예제
Docker Version
[wargame]
title = My challenge
flag = flag{my_challenge}
tags = web
[vm]
os = linux
memory = 128
disk = 256
ports = 80/tcp, 443/tcp
allow_outgoing = false
docker_compose = false
Docker Compose Version
[wargame]
title = Compose challenge
flag = flag{compose_challenge}
tags = misc
[vm]
os = linux
memory = 128
disk = 1024
ports = 5000/tcp
allow_outgoing = false
docker_compose = true
5. Add, Commit, Tag, Push 하기
문제에 필요한 파일들을 리포지토리에 모두 구성한 뒤 그대로 드림핵 서버에 업로드하기 위해서는, 먼저 현재 상태를 커밋(Commit) 해야 합니다. 아래와 같이 커밋을 진행할 수 있습니다.
$ git add -A
$ git commit -m "commit message"
[master f2b6efd] commit message
(...)
커밋이 만들어진 후, 아래와 같은 명령어로 해당 커밋에 태그(Tag) 를 추가해야 합니다. 이 태그가 해당 워게임 문제의 버전 구분에 해당합니다.
$ git tag [tag-name]
태그한 결과물을 아래와 같이 푸쉬(Push) 하여 서버에 해당하는 버전을 업로드할 수 있습니다.
$ git push origin master --tags
Total 8 (delta 1), reused 0 (delta 0)
(...)
* [new tag] [tag-name] -> [tag-name]
레퍼런스: Git의 기초 - 수정하고 저장소에 저장하기
https://git-scm.com/book/ko/v2/Git의-기초-수정하고-저장소에-저장하기
6. 문제 검증하기
문제 파일 업로드에 성공한 경우 업로드된 파일이 정상적인 구성인지 검증해야 합니다. 검증에 성공한 버전에 한해서 문제를 배포할 수 있으므로 검증에 성공해야 합니다. 검증은 아래 사진과 같이 Deploy 탭에서 앞서 업로드한 태그(v0.1)를 클릭한 후 검증 버튼을 누르면 됩니다.

검증 여부는 아래 사진과 같이 Tasks 탭에서 확인할 수 있습니다. 만약 검증에 실패하는 경우 실패 사유가 표시되며, 우측의 Detail 버튼을 눌러서 자세한 로그를 확인할 수 있습니다.

7. 문제 배포하기&테스트하기
검증에 성공하였으면 아래 사진과 같이 다시 Deploy 탭으로 돌아와서 해당하는 태그를 누른 후 배포 버튼을 눌러 문제를 배포할 수 있습니다.

배포를 하고 나면 설정된 버전의 문제 설명 및 공개 첨부 파일 등이 이용자에게 공개됩니다.
VM을 사용하는 문제의 경우 의도한 대로 작동하는지 아래 사진과 같이 Manage 탭의 서버 생성하기 버튼을 눌러 테스트해볼 수 있습니다.

모든 것이 원하는 대로 작동하여 이 문제를 공개해도 좋은 상태라면, 아래 사진과 같이 문제 공개하기 버튼을 클릭하여 모든 드림핵 이용자들이 문제에 접근하여 문제를 풀 수 있도록 공개할 수 있습니다.
한 번 공개한 문제는 다시 비공개로 전환할 수 없습니다.

워게임 구조
Dreamhack 워게임은 만약 문제를 동작시키기 위해 별도의 서버를 필요로 하는 경우(예: 리모트 서버, 웹 서버) 해당 문제를 해결하기 위해 각 유저를 대상으로 별도의 가상 환경을 제공합니다. 해당 가상 환경을 공격하여 사용자는 Flag를 획득하고, 문제에 따른 점수를 획득합니다.
- 사용자가 VM을 필요로 하는 문제를 도전하려고 할 때 새로운 VM 인스턴스가 생성되며 각 유저에게 독자적으로 제공됩니다.
- 이를 통해 문제를 도전 중인 여러 사용자의 상태가 간섭되는 것을 방지합니다.
- 워게임 서버의 임의의 포트가 배정되며,
Specfile에 정의된 포트로 포워딩됩니다.- 포트는 TCP와 UDP를 지원합니다.
- 각 문제는 여러 개의 포트를 Expose 할 수 있지만, 워게임 서버에서 순차적인 포트를 배정하지 않을 수 있습니다.
예를 들어,Specfile에서 Expose 하기로 지정한 포트가8080/tcp,8081/tcp과 같은 연속된 포트여도, 시스템에서 배정하는 포트는10254/tcp,10532/tcp와 같이 연속적이지 않을 수 있습니다.
서버 설정
Dreamhack 문제가 제공하는 서버는 아래의 설정을 기반으로 동작하며, 문제는 해당 환경 아래에서 반드시 호환성을 테스트해야 합니다.
- 모든 문제 VM은 Firecracker microVM 아래에서 동작합니다.
- 문제를 만든 사람이 제공한 image를 빌드한 container가 문제의 VM으로 사용됩니다.
- Container는 문제를 만든 사람이 명시한
Dockerfile를 기반으로 생성됩니다. - 문제의 리포지토리 내
Specfile에 문제 VM이 필요로 하는 최소의 CPU, 메모리, 디스크 크기가 설정되어야 합니다.- 문제를 만드는 사람의 별도 요청에 따라 변경될 수 있습니다.
- 문제 VM은 CPU 사용량 제한이 걸려 있습니다. (전체 서버의 CPU 사용량 중 약 10% 규모)
- 부팅 과정은 예외로 CPU 사용량 제한이 해제됩니다.
- VM 자체의 메모리 사용량에 의해 최소 메모리 필요 용량은 128MB입니다.
- 디스크 크기는 image를 빌드하기 위한 공간을 포함해야합니다.
- 문제를 만드는 사람이 직접
Dockerfile을 테스트하여 필요한 공간의 크기를 알고 있어야 합니다. docker images명령어를 통해 Docker image의 크기를 알 수 있습니다.
- 문제를 만드는 사람이 직접
문제 구성 관리
Dreamhack은 문제의 버전 관리의 용이함을 위해 Git을 내부적으로 사용하고 있습니다.
- 문제가 생성됨과 동시에 실제 Git 리포지토리가 서버에 생성되며 관리됩니다.
- 문제 출제자가 문제를 개발하는 과정 중 원하는 상태의 커밋을 tag하고 웹페이지를 통해 Deploy할 수 있습니다.
- 이 과정을 통해 문제 출제자와 Dreamhack 스탭들이 쉽게 기록을 통해 발생한 서버 문제를 해결할 수 있습니다.
- Git 리포지토리는 현재 128MB의 크기 제한이 있습니다.
- Deploy를 요청하기 전에 반드시 설정된 값이 정상적인지 검사해야 하며, 웹페이지에서 검사를 요청할 수 있습니다.
- Test 과정이 완료되면
Dockerfile을 포함한 문제인 경우 image를 빌드합니다. - 만약 image를 재생성 및 재배포해야 하는 경우 새로운 Tag를 부여하여 빌드해야 합니다.
- Test 과정과 image 빌드 과정이 모두 끝나면 "Live" 버전으로 배포할 수 있게 됩니다.
- 유저가 문제의 정보를 요청하는 경우 문제를 만든 사람이 기술한 문제의 "Live" 버전의 정보를 받게 됩니다.