Skip to content
On this page

Technická specifikace požadavků na úlohu spustitelnou v platformě Haxagon

Základní principy fungování platformy

Systém Haxagon zprostředkovává soutěžícím přístup k soutěžním úlohám. Automatizovaně tyto úlohy spouští a vytváří vzdálené připojení pro soutěžící. Aby byla úloha nasaditelná v systému, je nutné, aby splňovala určité technické specifikace.

Technická specifikace úloh

Virtualizace infrastruktury

V systému Haxagon jsou úlohy spouštěny virtualizací v Dockeru.
Docker-compose je nástroj pro spouštění a správu aplikací pomocí Dockeru. Umožňuje spouštět více kontejnerů jako jeden celek a řídit je pomocí jednoho konfiguračního souboru.

Struktura repozitáře s úlohou

Formát úlohy je velice jednoduchý – stačí systému poskytnout následující soubory v gitovém repozitáři:

  • challenge.yaml - Soubor ve formátu YAML, který definuje základní parametry úlohy.
  • docker-compose.yaml / docker-compose.yml - Instrukce pro sestavení kontejneru(ů) úlohy, viz Docker dokumentace.
  • THEORY.md - Markdown soubor s teoretickou částí úlohy, kde jsou řešiteli předávány teoretické znalosti bez vazby na obsah úlohy.
  • HANDBOOK.md - Markdown soubor obsahující obsah, který slouží jako příručka pro učitele.
  • DESCRIPTION.md - Krátký popis k zadání úlohy.

Tyto soubory jsou detailněji rozebrány v následujících sekcích.

challenge.yaml

název parametrupopis parametrutyppovinný parametr
titlePojmenování úlohystringANO
shortDescriptionKrátký popisek shrnující obsah úlohystringNE
difficultyUrčení obtížnosti úlohy. Více o obtížnosti dále.difficultyNE
imageUrl adresa obrázku, který slouží jako thumbnailstringNE
theoryRelativní cesta k Markdown souboru s teorií k úlozestringNE
descriptionRelativní cesta k Markdown souboru s popisem k vlajkámstringNE
handbookRelativní cesta k Markdown souboru s příručkou pro učitelestringNE
typeTyp úlohy. Více o typu úlohy dále.typeNE
tagsPole definující kategorizaci úlohystring[]NE
googleSpreadSheetIdGoogle sheets document ID zdrojového dokumentu.googleSpreadSheetIdNE
accessPole objektů definující možnosti připojení k úloze. Více o přístupu dále.accessNE
flagsPole objektů definující vlajky, které budou součástí úlohy. Více o vlajkách dále.flagsANO

difficulty

Vabírat můžete z těchto možností:

  • beginner
  • average
  • skilled
  • expert
  • master
  • unselected

type

Typ úlohy. Tento údaj říká HAXAGONu jakým způsobem má k úloze přístupovat. Výchozí hodnotou je docker. Pokud tvoříte úlohu virtualizovanou pomocí dockeru, tak tento parametr nemusítě vůbec uvádět.

Vabírat můžete z těchto možností:

  • docker: Úloha virtualizovaná pomocí dockeru
  • quiz: Nevirtualizovaná úloha
  • sheets: Úloha v prostředí Google Sheets

googleSpreadSheetId

Google sheets document ID zdrojového dokumentu. Zdrojový dokument musí mít nastavené oprávnění čtení pro kohokoli s odkazem. Samotné ID pak lze získat z URL dokumentu.

Pokud by url vypadala následnovně:

https://docs.google.com/spreadsheets/d/16yi2Nc9gwddlPhFxJBhHSm2_wo4U9lI-D6Okt0Xw_iI/edit?gid=0#gid=0

Pak je ID: 16yi2Nc9gwddlPhFxJBhHSm2_wo4U9lI-D6Okt0Xw_iI.

Tento paramert zadávejte jen v případě, že úloha je typu sheets

access

Základní formát objektů přístupu je tento:

název parametrupopis parametrutyppříkladpovinný parametr
typeTyp připojení, viz dále.string"ssh"ANO
portPort, na který se mají řešitelé připojit.number22NE
usernameUživatelské jméno použité pro připojení.stringstudentNE
passwordHeslo použité v páru s uživatelským jménem.stringheslo1234NE
textNepovinný text s dodatečnými informacemi.string"Formátovaný *text*"NE

V parametru type je možné použít jednu z těchto hodnot:

  • ssh
  • http
  • vnc
  • rdp
  • tcp
  • udp
  • other

U typu připojení other není povinné uvádět parametry port, username a password, většinou je ale naopak velmi využíván parametr text k vysvětlení nestandardního připojení.

Parametr text umožňuje využití Markdownu k formátování. Fungování víceřádkových textů v YAML je hezky vysvětleno na stránce YAML-multiline.info.

flags

Vlajky se dělí do celkem 6 typů.

Všechny typy vlajek mají společné tyto parametry:

název parametrupopis parametrutyppříkladpovinný parametr
namePojmenování vlajkystringOprávnění souboru file-1ANO
descriptionBližší informace o úkolu. Podporuje Markdown formátování.stringZměň oprávnění souboru file-1 na 742.NE
pointsBodové ohodnocení vlajkynumber20ANO
identifierUnikátní (v rámci této úlohy) identifikátor vlajkystringfile-perms-check1ANO
typeČíslo označující druh vlajky
Je nutné uvést type jako string v uvozovkách!
string"4"ANO

V souboru pro teorii lze vložit placeholder pro zobrazení konkrétní vlajky pomocí elementu <haxagonflag>. Tento element umožňuje dynamicky vkládat vlajku přímo do textu. Pro správné zobrazení je potřeba nastavit atribut identifier na odpovídající identifikátor vlajky.

<haxagonflag identifier="flag-1"></haxagonflag>

Vloží vlajku, která má parametr identifier flag-1, na místo této definice.

Dynamická vlajka

Každá instance úlohy má unikátně vygenerované vlajky tak, aby se zamezilo podvádění. Jejich unikátnost je zaručena vygenerováním náhodného řetězce, kterým jsou nahrazeny všechny výskyty placeholderu ve všech souborech v repozitáři scénáře. Aby nedošlo k nechtěné záměně, jsou všechna místa určená k nahrazení ohraničena znaky #@{{ a }}@#. Právě placeholder slouží autorovi úlohy k označení a odlišení jednotlivých míst.

Při zpuštění se tedy z #@{{vlajka1}}@# stane např. haxagon{897316929176464ebc9ad085f31e7284} a v jiné instanci úlohy s úplně stejným scénářem zase haxagon{99bd2e29f6b569bb880f601815cd77ef}.

POZOR

K nahrazení řetězců dochází až v runtime instance. To znamená, že nahrazení probíhá těsně před tím, než systém zavolá docker compose up.

Je potřeba rozdělit build fázi kontejnerů a jejich runtime fázi. Například tento kód v souboru Dockerfile některého z kontejnerů úlohy (RUN echo #@{{vlajka1}}@# > /tmp/test) nesplní očekávání, protože příkaz RUN v Dockerfile je spouštěn při sestavování (build) obrazů kontejnerů.

Pro zpřístupnění dynamické vlajky v runtime fázi kontejneru je potřeba vytvořit složku, v ní vytvořit soubor s placeholderem a tu složkou připojit (mount) pomocí volumes definice v docker compose.

Specifika pro vlajky tohoto typu:

název parametrupopis parametrutyppříkladpovinný parametr
type"1", označuje tento typ vlajkystring"1"ANO
placeholderZástupný řetězec znaků sloužící pro označení místa, do kterého se vloží unikátní vlajkastringflag2ANO
maximumTriesMaximální možný počet pokusů pro odpověďnumber3ANO

Statická vlajka

Tento druh vlajky mám pro všechny uživatele a ve všech instancích stejnou hodnotu.

Specifika pro vlajky tohoto typu:

název parametrupopis parametrutyppříkladpovinný parametr
type"2", označuje tento typ vlajkystring"2"ANO
answerOdpověď na úkolstringflag{1234}ANO
maximumTriesMaximální možný počet pokusů pro odpověďnumber3ANO

Vlajka s možností výběru odpovědi

Specifika pro vlajky tohoto typu:

název parametrupopis parametrutyppříkladpovinný parametr
type"3", označuje tento typ vlajkystring"3"ANO
maximumTriesMaximální možný počet pokusů pro odpověďnumber3ANO
optionsPole objektů možných odpovědíviz níževiz nížeANO

Objekty odpovědí mají tuto strukturu:

yaml
- value: "chybná odpověď"
  correct: false # nebo true pro správnou odpověď

Automaticky vyhodnocující se vlajka

Pomocí docker compose exec se v definovaném intervalu spouští definovaný příkaz command a podle návratové hodnoty exitCode procesu se určí, zda byla vlajka splněna. Možnost container určuje, ve kterém z možných kontejnerů se proces spustí.

název parametrupopis parametrutyppříkladpovinný parametr
type"4", označuje tento typ vlajkystring"4"ANO
commandPříkaz, který se spustí pro ověření splnění úkolustringbash -c '[ "$(cat /tmp/test.txt)" == "ahoj" ]'ANO
containerCílový kontejner, ve kterém se příkaz bude spouštětstringserverANO
shellShell, ve kterém je příkaz spouštěnstringshNE
userUživatel, pod kterým se příkaz spouštístringrootNE
intervalInterval, ve kterém dochází ke spuštění příkazunumber2000ANO
exitCodeNávratový kód commandu, který bude považován za úspěch pro splnění vlajkynumber0ANO
requiredFlagsVolitelné pole identifierů vlajek, které musí být splněny, než se vyhodnotí příkaz této vlajky.string | string[]file-perms-check1NE

Parametr interval je měřen v milisekundách.

Pokud bude jako hodnota interval uvedena 0, command nebude prováděn automaticky, ale v zadání úlohy se objeví tlačítko, kterým si ho řešitelé mohou spustit manuálně. Toto je vhodné pro náročné příkazy, jejichž vyhodnocení trvá dlouho nebo vyžaduje hodně prostředků.

Pokud pole requiredFlags obsahuje pouze jeden prvek, zapisuje se jako requiredFlags: "file-perms-check1". Pokud obsahuje více prvků, je třeba hodnoty zapsat jako YAML sekvenci. Pokud není třeba splnění vlajky podmiňovat jinou vlajkou, requiredFlags se neuvádí vůbec.

Vlajka automatické kontroly tabulek

Skrze Google API se získají data z dokumentu tabulek. Ty jsou následně předány do izolovaného sandboxu, kde se provede kontrola úkolu.

název parametrupopis parametrutyppříkladpovinný parametr
type"5", označuje tento typ vlajkystring"5"ANO
letObjekt proměnných, do kterých jsou uloženy hodnoty z odpovědi z Google APIobjecta: sheets.0.data.0.rowData.5.values.5.userEnteredValue.formulaValueANO
conditionJS kod, který v sandboxu vyhodnotí splnění úkolu. Úkol je vyhodnocen jako splněný v případě, že návratová hodnota bude true.string"a == 1"ANO
requiredFlagsVolitelné pole identifierů vlajek, které musí být splněny, než se vyhodnotí příkaz této vlajky.string | string[]file-perms-check1NE

Vlajka kontroly kódu

Specifikace pro vlajky tohoto typu:

název parametrupopis parametrutyppříkladpovinný parametr
type"6", označuje tento typ vlajkystring"6"ANO
defaultCodeRelativní cesta k výchozímu kódustring./Defaults/code.pyANO
checkerRelativní cesta ke kódu, který zkontroluje napsaný programstring./Checkers/code.pyANO
testCasesPole objektů definující jména jednotlivých testůobject[]viz nížeANO
testCases:
  - name: "test 1"
  - name: "test 2"
  - name: "test 3"

Ukázkový soubor challenge.yaml

yaml
# název úlohy
title: Ukázková úloha

# krátký popisek shrnující obsah úlohy
shortDescription: Ukázková úloha

# obtížnost úlohy
difficulty: beginner

# relativní cesta k souboru obsahující teorii k látce v úloze
theory: './THEORY.md'

# relativní cesta k souboru obsahující popis k řešení vlajek
description: ./DESCRIPTION.md

# relativní cesta k souboru obsahující učitelskou příručku k úloze
handbook: ./HANDBOOK.md

# informace o možnostech připojení na úlohu
access:
  - type: "ssh"
    port: 22
    username: student
    password: heslo1234

  - type: "http"
    port: 80
    username: student
    password: heslo1234

# vlajky, ktere jsou s ulohou spojeny
flags:
  - name: Obsah souboru /tmp/file1
    description: 
    points: 10
    type: "1"
    identifier: "file-content-1"
    placeholder: flag1
    maximumTries: 3
  - name: Heslo uživatele adam
    description: Najdi způsob, jak získat heslo uživatele `adam` v plaintextu.
    points: 20
    type: "2"
    identifier: "password-dump1"
    answer: flag{adamisbest}
    maximumTries: 2
  - name: Vyber správnou odpověď
    description: 
    points: 30
    type: "3"
    identifier: "choice-flag1"
    maximumTries: 2
    options:
      - value: správná odpověď
        correct: true
      - value: chybná odpověď
        correct: false
  - name: /tmp/test.txt
    description: Do souboru /tmp/test.txt zapiš text "ahoj".
    points: 30
    type: "4"
    identifier: "file-content-check1"
    command: "sh -c '[ \"$(cat /tmp/test.txt)\" == \"ahoj\" ]'"
    interval: 1000
    container: "server"
    exitCode: 0


docker-compose.yaml

Tímto souborem jsme schopni definovat, jaká infrastruktura se pro úlohu spustí. Dokumentace formátu je dostupná na https://docs.docker.com/compose/.

Preferované verze Docker image

Pro snížení duplikací a stahování více verzí stejného Docker image byly vybrány následující verze, které by měly být v úlohách upřednostňovány:

haxagon/workstation:27022025
haxagon/challenge-workstation:27022025
haxagon/workstation-sysbox:27022025
mongo:7.0.17
wordpress:6.7.2-php8.1-apache
httpd:2.4.63-alpine
phpmyadmin:5.2.2-apache
adminer:4.17.1
postgres:17.4-alpine3.21
php:8.3.17
mysql:9.2.0
python:3.13.0-alpine3.20
busybox:1.37.0
mariadb:11.7.2
nginx:1.27.3
ubuntu:noble-20250127
alpine:3.20.3
node:23.7.0-alpine3.20

Limity

V souboru docker-compose není možné

  • Eskalovat práva kontejneru
    • Vytvářet privilegované kontejnery
    • Přidávat kontejnerům systémové schopnosti (system capabilities)
  • Mountovat adresáře a soubory (vše potřebné by mělo být do kontejneru přidáno v build fázi)

Signalizace úspěšného nastartování scénáře

Je nutné systém informovat o tom, že je scénář spuštěný a vše je připraveno. Tuto informaci je možné systému sdělit tím, že do stdout entrypointu/commandu libovolného commandu definovaného v docker-compose souboru vypíšete řetězec SCENARIO_IS_READY.

Ukázkový docker-compose.yml

yaml
services:
    webserver:
        image: nonbusybox
        container_name: webserver
        command: sh -c '/setup.sh && echo SCENARIO_IS_READY && sleep infinity'
        ports:
            - "80:80"


THEORY.md

Zde jsou předávány teoretické znalosti bez vazby na obsah úlohy.

Je důrazně doporučeno používat správné Markdown formátování pro zvýšení přehlednosti.

DESCRIPTION.md

Úvod k řešení vlajek. Často zde bývá zopakování příběhu úlohy (pokud nějaký je), nebo poznámka o speciálních nestandardních nástrojích, které je možné při řešení využít.

HANDBOOK.md

Do Příručky patří návod k vyřešení celé úlohy, je viditelná pouze pro učitele.

Také je možné uvést poznámky pro učitele, jak dobře vysvětlit danou látku či na co poukázat.


Další konvence pro tvorbu zadání

Technické informace a formátování

Části textu obsahující nějakou technickou informaci, např.:

  • definici subnetu - 192.168.40.0/24
  • příkazy - find --name file
  • parametr - --sevice-scan a podobné zaobalíme do code highlight bloku pomocí znaku `

Další tipy k formátování naleznete na dedikované stránce.