# Что пошло не так на M*CTF 2021 Finals
Осенью 2021 года состоялся ежегодный финал M\*CTF, в котором приняли участие 11 команд. К сожалению, не всё прошло так, как мы задумывали. В этой статье мы расскажем, какие проблемы возникли при проведении M\*CTF 2021 Finals, и в чем причина этих проблем.
## Идея
В этом году мы решили попробовать кое-что новое, что-то, чего ещё никогда не было в России. Мы решили избавиться от элемента анализа трафика, вместо которого сделали упор на исследование кода и логов. Мы ожидали, что не всем этот формат понравится больше привычного, но не хотели делать то, что уже было тысячу раз.
Как это работает:
1. Код проектов хранится и собирается в Gitlab с помощью [kaniko](https://github.com/GoogleContainerTools/kaniko) (он используется, чтобы не требовать root для сборки).
2. После сборки в отдельном сервисе можно выбрать нужную версию и задеплоить в Kubernetes-кластер.
3. nginx в этом кластере принимает запросы и направляет на нужные сервисы в зависимости от поля Host. Например, по ссылке `service0.team3.services.mctf.online` откроется первый сервис команды с id = 3.
4. Логи всех сервисов сохраняются для анализа в Graylog.
5. Чекеры и сдача флагов работают привычным образом.
### Схемы
Обновление сервиса:

Атака и просмотр логов:

## Проблемы
### Поздний старт
Мы на M\*CTF уже давно привыкли дописывать сервисы или чекеры в ночь перед соревнованием, но на этот раз проблемы были серьезнее, чем обычно. Из-за того, что мы не успели развернуть инфраструктуру в проде перед стартом, пришлось отодвинуть начало на больше чем на час, пока не поднимутся все сервисы.
### Сервис ломался под нагрузкой
Через какое-то время после начала соревнования у команд пожелтел сервис Sluck. Мы подумали, что проблема в чекерах, но с ними оказалось всё нормально, сервисы действительно лежали. Оказалось, что под нагрузкой в БД скопилось слишком много данных, из-за чего сервис не мог с ней взаимодействовать. На такой случай в сервисе было предусмотрено удаление старых данных по таймеру, но оказалось, что оно не работает в некоторых сценариях, которые не были отловлены при тестировании.
Ситацию мог бы спасти патч для правильного очищения БД, но из-за большого количества других проблем добраться до этого так и не получилось.
### Плохо собирались/лагали логи
Мы не расчитали нагрузку на Graylog, из-за чего логи не успевали обрабатываться, и часть сообщений отбрасывалась. Заметнее всего это было на сервисе Epic Tanks, который сам по себе выводит очень мало сообщений, и поэтому сохранялось хоть что-то только в редких случаях, из-за чего его было очень сложно отлаживать. Кроме этого, сам веб-интерфейс Graylog часто лагал при заходе, из-за чего даже обработанные сообщения в некоторые моменты было трудно посмотреть.
Мы добавили реплик Graylog, чтобы справиться с этим, но, судя по всему, они как-то неправильно подключились к главной реплике, из-за чего они были почти не нагружены обработкой логов и не решили проблему пропадающих логов.
### Упал docker regitry
После начала соревнований оказалось, что почти все сборки на этапе загрузки образа в docker registry падают с неинформативной ошибкой. На тестах у нас такого не было, поэтому мы подумали, что проблема может быть в каких-то данных, которые остались с тестов. Поэтому мы сбросили данные гитлаба и пересоздали проекты, но это помогло ненадолго. Через какое-то время проблема снова появилась.
При более тщательном исследовании оказалось, что в хранилище образов закончилось место, ведь по умолчанию выделяется всего 10 гб. Но с первого раза исправить это не удалось, и потребовалось ещё 2 сброса гитлаба, чтобы окончательно побороть проблему.
### Сервис с танками плохо адаптирован под формат
Многие игроки заметили, что с сервисом Epic Tanks очень сложно работать, не имея возможности самому подключиться к серверу. На самом деле изначально задумка была совсем другой - уязвимости в клиентах и возможность подключиться к серверу самому. Но всего за несколько дней до соревнования мы обсуждали сервис и поняли, что с учетом особенностей архитектуры сделать такое не получится. В итоге мы сделали реверс+ppc сервис, что тоже интересно, но не так подходит под формат.
### Проблемы с подсчетом SLA в танках
Из-за того, что клиенты танков запускаются в облаке, стандартную схему с выдачей флагов нельзя было использовать. Мы сделали, что сервер танков сам отправляет информацию об убитых танках в журейку для начисления очков командам. Информация о подключенных клиентах для расчета SLA поступает таким же образом. Но где-то в этой схеме оказалась проблема, и сервисы начали моргать в скорборде, из-за чего у команд оказался рандомный SLA, даже если они были подключены к серверу.
Мы сделали голосование, сбрасывать ли SLA за этот сервис. Сброс бы изменил позиции некоторых команд в таблице результатов. Результаты оказались такие: около 67% за сброс и 33% против (на самом деле ближе к 50/50, но у нас не сохранился скриншот с того момента). Но мы решили не делать сброс по следующим причинам:
1. В голосовании участвовали не только финалисты, так как оно проходило в общей с квалами группе. Из-за этого достоверно определить результаты нельзя было.
2. Разрыв между результатами был слишком маленьким, чтобы можно было говорить о том, что подавляющее большинство за определенный вариант. А без подавляющего большинства мы не хотели менять позиции команд.

В итоге какой бы вариант мы не выбрали, остались недовольными бы слишком много команд. Поэтому мы решили не делать ничего, что могло бы усугубить ситуацию, и оставить всё как есть.
### Баг сборщика образов
Даже после исправления проблемы с registry некоторые команды обнаружили, что сборка в гитлабе может упасть.

Мы видели эту ошибку несколько раз при тестировании, но она появлялась редко, так что мы записали это в список TODO и оставили на потом, ведь на тот момент у нас были гораздо более серьезные проблемы. На самом деле это [известный баг](https://github.com/GoogleContainerTools/kaniko/issues/769) самого kaniko (сборщика образов). Там описан костыль, которым может решить эту конкретную проблему, так что если бы было достаточно времени, вероятно мы бы могли исправить и этот баг.
## Причины
### Не хватило времени
Главная причина всех проблем - нам не хватило времени на подготовку, а самое главное - на финальную симуляцию игры. На глобальном тесте мы бы сразу обнаружили главные проблемы и смогли их исправить. Но вместо этого вплоть до утра перед соревнованием мы занимались доработкой системы и сервисов.
В этот раз мы взяли на разработку финала на две недели больше, чем в прошлом году, но и работы оказалось намного больше, чем раньше. Ещё сильнее отодвигать финал было нельзя, так как в декабре начинается сессия, и многие команды не смогли бы участвовать. Возможно, правильным решением было перенести финал на начало 2022.
### Проблемы с коммуникацией
При разработке мы не всегда обсуждали вещи, которые нужно было обсуждать. Главным образом это проявилось в танках - у сервиса были проблемы с архитектурой, которые нужно было выявить гораздо раньше. Одна из причин этого - та же нехватка времени, в том числе на созвоны.
### Много новых задач
В этом году нам нужно было сделать гораздо больше, чем обычно, причем задач, которыми раньше в CTF в России никто не занимался. Это относится не только к разработке инфраструктуры, что заняло большую часть времени, но и к интеграции сервисов в облако. В этом плане мы были первопроходцами, и нам первыми пришлось столкнуться с проблемами, специфичными для формата.
Особенно много времени затратил концептуально новый сервис танков - его подготовкой занималось несколько человек, а на обсуждение концепции уходили часы.
## Заключение
Несмотря на неудачную реализацию, мы всё ещё видим потенциал в новом формате. Пока мы не можем сказать, будем ли мы заниматься M\*CTF в следующем году, но надеемся, что ещё увидим что-то похожее в CTF.