Схема сетевой топологии на тёмном антистатическом коврике с зелёными рукописными пометками. Позади — ноутбук с терминалом и светящиеся янтарные индикаторы сетевого коммутатора.


Восемь часов, 24 команды, пять уязвимых сервисов - и чекер, который на каждом втором тике возвращал CORRUPT из-за race condition в собственном коде проверки. Три человека дебажили Python-скрипт прямо во время соревнований, пока команды в чате писали, что скорборд сломан. Когда организуешь Attack-Defense CTF, именно такие моменты определяют, получится рабочее соревнование или восьмичасовой хаос с багами собственной инфраструктуры.

Дальше - разбор того, что должно работать под капотом: компоненты gameserver, vulnbox, написание чекеров, сетевая изоляция и автоматизация SLA-проверок. Пригодится и тем, кто организует A/D CTF, и тем, кто собирается участвовать впервые и хочет понимать, как всё устроено изнутри.

CTF соревнования архитектура: три компонента Attack-Defense​

Attack-Defense CTF строится на трёх обязательных компонентах: gameserver, vulnbox команд и game network. Ломается любой из них - рассыпается всё.

Gameserver - центральный узел, управляющий ходом игры. Его задачи:
  • размещать флаги на vulnbox каждой команды в начале каждого тика;
  • запускать чекеры для проверки работоспособности сервисов (SLA);
  • принимать захваченные флаги от команд через submission-сервер;
  • считать очки и рисовать скорборд.
Момент, который часто упускают новички (и который подчёркивают в документации FAUST CTF): gameserver не запускает эксплойты. Он работает с сервисом как легитимный пользователь - через штатный интерфейс. У gameserver есть дополнительная информация (токены для доступа к конкретным флагам), которой у атакующих нет. Поэтому команды не могут просто повторить действия gameserver - им нужно найти уязвимость, чтобы добраться до чужих флагов.

Vulnbox - сервер каждой команды с набором уязвимых сервисов. Все команды получают идентичные конфигурации. Vulnbox должен быть доступен из game network всё соревнование - gameserver хранит на нём флаги и через него определяет, жив ли сервис.

Game network - сеть, связывающая vulnbox всех команд и gameserver. Через неё команды атакуют друг друга, а gameserver выполняет SLA-проверки.

CTF gameserver настройка: тики, скоринг, модульная архитектура​

Игра делится на тики (раунды). Один тик - от 1 до 5 минут, зависит от организатора. За тик gameserver размещает новые флаги, проверяет SLA, а команды атакуют и защищаются. Типичный A/D CTF: 8 часов с тиками по 2-3 минуты - порядка 160-240 раундов.

Если копнуть глубже: по данным проекта CTF Gameserver (FAUST CTF, открытый исходный код, активно поддерживается и используется ежегодно), он состоит из независимых модулей, которые общаются через общую PostgreSQL-базу:
  • Controller - координирует прогресс соревнования: текущий тик, генерация флагов.
  • Checker Master - запускает checker-скрипты для каждого сервиса каждой команды в каждом тике. Основная нагрузка ложится именно сюда.
  • Checkerlib - библиотека для написания checker-скриптов. Поддерживаются Python и Go.
  • Submission - принимает захваченные флаги.
  • Web - Django-приложение для регистрации, скорборда и информационных страниц.
Из альтернатив: saarCTF gameserver (использовался для saarCTF 2020), Enowars Framework (open source, полный фреймворк для хостинга A/D). Принципы одинаковые, детали деплоя отличаются.

По данным maplebacon primer, скоринг складывается из трёх компонентов:

Тип очковИсточникВес
Attack PointsУспешная эксплуатация сервиса другой команды + сдача флагаЗависит от CTF
Defense PointsНикто не украл флаг с вашего сервиса за тикЗависит от CTF
SLA PointsСервис работает корректно и проходит проверки gameserverОбычно значительный

Пропорции различаются от CTF к CTF, но SLA-баллы - то, что команды теряют чаще всего. И теряют по собственной вине: криво патчат сервис, чекер перестаёт проходить - и привет, минус очки каждый тик.

Сетевая инфраструктура CTF: VPN, NAT и изоляция команд​

Сетевая топология в Attack-Defense CTF следует стандартному паттерну. По документации Enowars и FAUST CTF, типовая адресация:
  • Game Network: 10.0.0.0/16 (или 10.60.0.0/16)
  • Vulnbox команды N: 10.0.0.N/32 (или 10.60.N.1)
  • Game Router: 10.0.1.1
  • Flag Submission: 10.0.13.37:1337
Каждая команда подключается к game network через VPN. Два основных варианта:
  • WireGuard - быстрее, проще в настройке, меньше накладных расходов. Требует ядро Linux 5.6+ на стороне сервера. CTF Gameserver (FAUST) упоминает поддержку WireGuard для VPN Status.
  • OpenVPN - универсальнее, работает на любой ОС, но тяжелее. Enowars исторически предоставляет OpenVPN-конфиг для подключения.
Критический элемент - NAT masquerading. Game router делает SNAT на весь игровой трафик: все входящие пакеты на vulnbox команды выглядят приходящими от 10.0.1.1, независимо от реального источника. Зачем? Команды не должны различать трафик чекера и трафик атакующих. Без NAT можно тупо заблокировать все пакеты от чужих IP и пропускать только gameserver - и вся защита превращается в одно правило iptables.

VPN-подсеть каждой команды (например, 10.0.240.0/24) полностью изолирована от подсетей других команд - участники одной команды не видят VPN-сегмент другой.

С точки зрения MITRE ATT&CK, в контексте A/D CTF: Network Sniffing (T1040, Discovery / Credential Access) - штатная тактика. Перехват трафика в game network позволяет видеть эксплойты других команд. Network Service Discovery (T1046, Discovery) - стандартная практика на старте: команды определяют открытые порты сервисов на чужих vulnbox.

Требования к окружению для развёртывания​

Минимальный стек для организации Attack-Defense CTF на 20-30 команд:

КомпонентРесурсыПримечание
Gameserver (controller + checker master + web)8 vCPU, 16 GB RAM, SSD 100 GBЧекеры - основная нагрузка: при 5 сервисах и 30 командах - 150 проверок за тик
PostgreSQL4 vCPU, 8 GB RAMОбщая БД для всех модулей gameserver
VPN-сервер (WireGuard/OpenVPN)2 vCPU, 4 GB RAMМаршрутизация + NAT, отдельный от gameserver
Vulnbox каждой команды2-4 vCPU, 4-8 GB RAMDocker Compose с 3-5 сервисами

ОС: Debian 12 или Ubuntu 22.04 LTS - стандарт для CTF Gameserver. Канал: от 1 Гбит/с на стороне gameserver. Режим: облачный (Hetzner, AWS, Selectel) предпочтительнее - проще масштабировать. Для деплоя vulnbox 30 команд хорошо работает Ansible: один playbook поднимает идентичные VM с Docker Compose-конфигом. Мониторинг состояния раундов - Prometheus + Grafana с метриками checker master (процент OK/DOWN/FAULTY по сервисам, latency чекеров).

CTF vulnbox настройка: сервисы, Docker Compose и первый час​

Сервис в Attack-Defense CTF - аналог задачи в Jeopardy, но с двумя отличиями: его нужно не только ломать, но и защищать, и он должен оставаться работоспособным для чекера. По сути это Exploit Public-Facing Application (T1190, Initial Access) - то, что команды делают с сервисами друг друга.

Типичный набор для A/D CTF:
  • 1-2 web-сервиса (Python/Flask, Go, Node.js) - SQL injection, SSTI, IDOR
  • 1-2 pwn-сервиса - бинарные приложения с buffer overflow, format string
  • 1 crypto/misc - ошибки в криптографии или бизнес-логике
По данным maplebacon primer, реальные примеры: piratesay (ENOWARS 8) - тематический форум, pwn-категория, только бинарник; quickr-maps (FAUST CTF 2024) - API для шаринга локаций, web-категория, исходный код на Go/Python. Каждый сервис содержит один или несколько flag store - мест хранения флагов. Это может быть поле в БД, файл на диске, запись в key-value хранилище.

Развёртывание сервисов в подавляющем большинстве случаев - через docker compose up -d. Некоторые CTF (ENOWARS) исторически предоставляют готовый образ VM, другие (FAUST CTF) требуют самостоятельного развёртывания из VM-образа. Реже используются LXC-контейнеры.

Первый час после получения доступа к vulnbox:
  1. Подключиться к vulnbox (VPN-конфиг или SSH-креды).
  2. Скопировать все сервисы на локальную машину - бэкап до любых изменений. Без этого откат сломанного патча невозможен.
  3. Поднять сервисы (docker compose up -d), проверить статус на скорборде.
  4. Открыть папку каждого сервиса в IDE и начать анализ: искать уязвимости, планировать патчи.
Обычно организаторы дают 60 минут между получением доступа и открытием сети между командами. По опыту, команды, забившие на бэкап в этот час, на третьем тике ломают патчем собственный сервис и не могут откатиться. Случается регулярно - я видел это на каждом втором A/D.

Написание CTF чекеров: checkerlib, SLA и типичные ошибки​

Чекер - скрипт, который притворяется обычным пользователем сервиса. Каждый тик Checker Master запускает чекер для каждого сервиса каждой команды. Чекер делает две вещи:
  1. PUT - размещает флаг в сервисе: регистрирует пользователя, отправляет сообщение, загружает файл - зависит от логики конкретного сервиса.
  2. GET - проверяет, что ранее размещённый флаг доступен: логинится по сохранённому токену, запрашивает данные.
Если GET возвращает корректный флаг - SLA OK. Если нет - команда теряет SLA-баллы.

Написание чекеров - одна из самых муторных задач при организации CTF платформы. Чекер должен быть достаточно умным, чтобы проверить реальную функциональность, и достаточно устойчивым, чтобы не падать от сетевых таймаутов. Структура на Python с использованием checkerlib (FAUST CTF Gameserver):
Python:
from checkerlib import BaseChecker, BrokenServiceException
class ServiceChecker(BaseChecker):
    def place_flag(self, tick):
        flag = self.get_flag(tick)
        token = self._register_user(flag)
        self.store_state(f"token_{tick}", token)
    def check_flag(self, tick):
        token = self.load_state(f"token_{tick}")
        if self.get_flag(tick) not in self._get_data(token):
            raise BrokenServiceException("Flag missing")
Ключевые моменты: place_flag и check_flag вызываются в разных тиках - состояние сохраняется через store_state / load_state. Каждый вызов должен иметь таймаут (10-30 секунд). И чекер обязан рандомизировать имена пользователей, user-agent, порядок полей - иначе команды отфильтруют его трафик по паттерну. Если чекер всегда создаёт checker_user_42 - его вычислят за первый тик.

Состояния SLA: что означает каждый статус​

По документации FAUST CTF Gameserver, сервис в каждом тике может находиться в одном из состояний:

СтатусЗначениеЧто делать
OKСервис работает, флаги на местеШтатная ситуация
DOWNНет ответа, таймаут, разрыв соединенияПроверить Docker-контейнеры, логи, сеть
FAULTYСервис отвечает, но ведёт себя не по спецификацииОткатить последний патч
FLAG_NOT_FOUNDСервис работает, но конкретный флаг не найденПроверить, не удалились ли данные
RECOVERINGТекущий флаг OK, но флаги прошлых тиков недоступныПроверить хранилище

Самая частая причина FAULTY - кривой патчинг. Команда закрывает SQL injection через фильтрацию ключевых слов, а заодно режет легитимные запросы чекера. Или отключает эндпоинт, через который чекер сохраняет флаг. Правило простое: патч должен блокировать эксплуатацию уязвимости, не ломая штатную функциональность. На практике это сложнее, чем звучит.

Ограничения техник и типичные ошибки​

Для организаторов:
  • Race conditions в чекере. Если controller запускает place_flag и check_flag для одного тика параллельно (баг или кривая конфигурация), чекер проверяет флаг до его размещения. Лечится нагрузочным тестированием до начала CTF: разверните 5-10 тестовых vulnbox и прогоните 50 тиков. Не поленитесь - на самом CTF будет поздно.
  • Недостаточная рандомизация. Если чекер всегда создаёт пользователя с предсказуемым паттерном, команды его вайтлистят. Генерируйте случайные данные в каждом вызове.
  • Хрупкость к сетевым задержкам. Чекер без обработки ConnectionTimeout массово выдаёт DOWN при любом всплеске латентности в game network. Оборачивайте каждый сетевой вызов в try/except с адекватными таймаутами.
Для участников:
  • Патч, блокирующий ключевое слово SELECT, может заблокировать и легитимные запросы чекера, если сервис хранит данные в SQL. Классический выстрел в ногу.
  • Закрытие порта файрволом вместо патчинга кода гарантирует DOWN - чекер не достучится до сервиса.
  • Удаление endpoint-а из маршрутов web-приложения ломает place_flag - статус переходит в FAULTY.

Автоматизация проверки SLA CTF: фермы флагов и анализ трафика​

Ручная эксплуатация в A/D CTF - путь к поражению. Флаги обновляются каждые 1-3 минуты, команд 20-30. Проэксплуатировать каждую вручную, забрать флаг, отправить на submission - физически невозможно. Здесь работает Automated Collection (T1119, Collection): автоматизированный сбор флагов со всех команд в каждом тике.

Ферма флагов - фреймворк, который запускает ваш эксплойт-скрипт против всех команд параллельно, парсит флаги из stdout и отправляет их на submission-сервер. Два основных инструмента:
  • S4DFarm (команда C4T BuT S4D, активно поддерживается) - веб-интерфейс, статистика по каждому эксплойту, поддержка нескольких протоколов submission (ForcAD, RuCTF, VolgaCTF). Для командной работы - самое то.
  • DestructiveFarm (DestructiveVoice) - проще в настройке, подходит для первого A/D или одиночной игры. Конфигурация через config.py.
Структура эксплойт-скрипта для фермы:
Python:
#!/usr/bin/env python3
import sys, requests
host = sys.argv[1]
r = requests.get(f"http://{host}:8080/api/notes",
    params={"id": "1 UNION SELECT flag FROM secrets"})
for line in r.text.split("\n"):
    if len(line) == 32 and line[-1] == "=":
        print(line, flush=True)
Два обязательных элемента: шебанг #!/usr/bin/env python3 (ферма запускает скрипт как процесс) и print(flag, flush=True) (ферма парсит stdout). Запуск через S4DFarm: python3 start_sploit.py --server-url http://FARM_IP/ --server-pass YOUR_PASS exploit.py.

Attack-Defense флаги сервисы: сниффинг и защита трафика​

Все команды в одной сети - трафик между ними доступен для перехвата. Network Sniffing (T1040) здесь не хак, а штатная тактика. Для новичков это ключевая стратегия: не можешь найти уязвимость сам - посмотри HTTP-запрос другой команды с рабочим эксплойтом и адаптируй.

Tulip (OpenAttackDefenseTools) - инструмент для анализа PCAP в A/D CTF. Веб-интерфейс для фильтрации по сервисам, командам и паттернам. На vulnbox захват трафика запускается через tcpdump -i eth0 -w /tmp/capture.pcap -s 0, но за 8 часов с 30 командами набирается 50+ ГБ - держите место на диске.

Для защиты от известных эксплойтов применяется iptables:
Bash:
iptables -I FORWARD 1 -t filter -p tcp \
  -d $VULNBOX_IP --dport $SERVICE_PORT \
  -m string --string "UNION SELECT" --algo bm -j DROP
Правило блокирует пакеты с подстрокой UNION SELECT на уровне ядра. Ограничения существенные: не работает с TLS-трафиком, не ловит обфусцированные запросы, а ошибка в паттерне (например, *) может заблокировать SSH и оставить вас без доступа к vulnbox. При ошибке - немедленно iptables-restore < /tmp/backup.txt. По данным A/D CTF Cheatsheet, более продвинутая альтернатива - reverse proxy перед каждым сервисом с regex-фильтрацией на вход и выход, но нужно проверять, что proxy не добавляет задержку, из-за которой чекер превысит таймаут.

Распределение ролей в команде на Attack-Defense CTF

Для команды из 5-8 человек оптимальное распределение:

РольЗадачиИнструменты
Инфраструктурщик (1 чел.)VPN, ферма, Tulip, мониторинг SLAS4DFarm, Docker, tcpdump, Tulip
Патчер-дежурный (1 чел.)Отслеживает скорборд, откатывает сломанные патчиdocker compose, git
Web-атака (1-2 чел.)Анализ web-сервисов, эксплуатацияBurp Suite, Python, sqlmap
Pwn/Rev-атака (1-2 чел.)Реверс бинарных сервисов, эксплойтыGhidra, pwntools, GDB
Трафик-аналитик (1 чел.)PCAP-мониторинг, извлечение чужих эксплойтовTulip, Wireshark

Если команда впервые на A/D - три приоритета: (1) поднять и не ронять сервисы; (2) настроить ферму флагов; (3) захватить трафик и переиспользовать чужие эксплойты. Атака с нуля требует опыта, но адаптация увиденного в трафике - рабочая стратегия для первого раза. На HackerLab.pro можно попрактиковаться в отдельных категориях web и pwn, которые составляют основу сервисов на A/D CTF - это российская CTF-платформа экосистемы Codeby с задачами разного уровня сложности, нужна регистрация.

Большинство команд, впервые приезжающих на Attack-Defense, готовятся к нему как к Jeopardy на стероидах: прокачивают навыки поиска уязвимостей, тренируются на HTB, пишут быстрые эксплойты. А потом проигрывают командам, которые хуже ищут баги, но лучше автоматизируют инфраструктуру.

Неудобная правда: на A/D CTF побеждает не тот, кто первым нашёл RCE, а тот, кто первым настроил ферму и раскидал этот RCE на 25 команд за один тик. Я видел, как команда с тремя OSCP-сертификатами занимала последнее место, потому что не умела поднять S4DFarm и сдавала флаги руками через curl. И видел, как второкурсники входили в десятку, потому что в первый час развернули Tulip, настроили ферму и переиспользовали чужие эксплойты из трафика.

Для организатора картина зеркальная: можно написать пять блестящих сервисов с элегантными уязвимостями, но если чекеры не протестированы под нагрузкой, NAT не маскирует source IP, а gameserver не масштабируется - соревнование превращается в шоу багов собственной инфраструктуры. На тестирование чекеров и сетевого стека уходит в три раза больше времени, чем на разработку самих сервисов. Attack-Defense CTF - в первую очередь инженерная дисциплина, и только потом охота на баги. Если хочешь не просто writeup, а пройти всю атаку самому - WAPT с лабой на каждый кейс.
 
Последнее редактирование:
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

Похожие темы

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab