Клиент фермы — это утилита, которая регулярно запускает эксплоит, чтобы атаковать чужие команды, и следит за его работой. Запускается участником на своём ноутбуке после написания эксплоита.
Клиент представляет собой однофайловый скрипт start_sploit.py из данного репозитория.
Для работы клиента требуется Python 3 и ОС Linux, macOS или Windows. Клиент не требует установки каких-либо библиотек.
Установить клиент в Linux и macOS можно командой:
wget bit.ly/start_sploit_v2 -O start_sploit.py && chmod +x start_sploit.py
В простейшем случае эксплоит может быть запущен следующим образом:
./start_sploit.py sploit.py --server-url http://10.0.0.1:5000
Здесь sploit.py
— файл с эксплоитом, http://10.0.0.1:5000
— адрес, по которому доступен сервер фермы.
Следить за работой эксплоита можно с помощью вывода клиента фермы или через веб-интерфейс сервера, доступный по адресу из опции --server-url
.
Работа клиента фермы разделена на периоды, каждый из которых называется атакой. Во время каждой атаки клиент сначала запрашивает у сервера фермы (если он доступен) актуальные настройки (список команд, формат флага), после чего атакует все команды из списка с помощью эксплоита. Одна атака не может длиться больше времени, чем количество секунд, указанных в опции --attack-period
(стандартно — 120 секунд). Очевидно, этот период не должен быть больше, чем время жизни флага (период после добавления флага в сервис, в течение которого проверяющая система считает его корректным).
Количество процессов с эксплоитом, работающих одновременно, не может превышать значение опции --pool-size
(стандартно — 50 процессов). Это ограничение позволяет избежать заполнения всей доступной оперативной памяти (и последующего зависания компьютера) на соревнованиях с большим количеством команд (например, в RuCTFE может участвовать более 400 команд) или в случае ресурсоёмких эксплоитов.
В соответствии с описанными параметрами, максимальное время работы (time limit) для одного процесса с эксплоитом рассчитывается как attack_period / ceil(len(teams) / pool_size)
(и выводится в начале каждой атаки). По истечении этого времени клиент фермы убивает процесс.
Во время работы эксплоита клиент следит за его выводом и, как только в выводе появляется подстрока, удовлетворяющая формату флага, добавляет её в очередь на отправку на сервер. Одни и те же флаги не добавляются в очередь дважды. Содержимое очереди отправляется на сервер фермы каждые 5 секунд.
Перед запуском клиент фермы проверяет часть требований к формату эксплоита.
В редких случаях эксплоит не требуется запускать отдельно для каждой команды. Тогда можно применить опцию клиента --not-per-team
, при которой каждая атака будет состоять из одного запуска эксплоита без аргументов командной строки.
-
Увеличьте
--attack-period
. Например, время жизни флага на RuCTF обычно составляет 5 минут, поэтому--attack-period
можно увеличить более, чем в 2 раза.В таком случае небольшая часть флагов может быть потеряна (если сервис противника упал на небольшой период, совпавший с запуском эксплоита, часть флагов этой команды уже умрёт к следующей атаке).
-
Увеличьте
--pool-size
. Это грозит исчерпанием свободной памяти и зависанием компьютера. -
Используйте опцию
--distribute=K/N
. Тогда список команд будет детерминированным образом поделён на N частей, после чего клиент будет запускать эксплоит только на K-й части списка. Таким образом, запуск эксплоита можно будет распределить между N компьютерами.
Первые несколько атак (опция --verbose-attacks
) клиент фермы будет показывать содержимое stdout и stderr эксплоита для каждой из команд, а также список флагов, извлечённых из этого вывода. Это позволяет увидеть, какие ошибки возникают при запуске эксплоита.
В конце каждой атаки клиент показывает, какой процент процессов с эксплоитом (за всё время работы клиента) превысил отведённый им time limit.
Чтобы каждый раз не указывать опцию --server-url URL
, вы можете изменить стандартный домен сервера в файле start_sploit.py
на домен, A-записи которого может контролировать ваш админ, и попросить членов команды использовать обновлённый скрипт.
В начале каждого соревнования админ может изменять A-запись, соответствующую домену, так, чтобы она указывала на IP, соответствующий серверу фермы в локальной сети. Благодаря этому другим участникам команды не нужно будет заботиться об установке правильного IP сервера. Обратите внимание, что соответствующие A-записи должны иметь маленький TTL (иначе ваши изменения будут применяться с задержкой).
Изменение A-записи на DigitalOcean
- Эксплоиты запускаются с переменной окружения
PYTHONUNBUFFERED=1
, благодаря которой в эксплоитах на Python процедураflush(stdout)
выполняется автоматически после вывода каждого перевода строки (это дополнительно страхует от потери флагов, см. пункт 4 в формате эксплоита).