Привет! Меня зовут Миша Малашин, я продакт‑менеджер маркетплейса игровых предметов CS.MONEY. Сегодня расскажу, как год назад у нас украли почти 1 миллиард рублей — это история о том, что нужно вовремя менять пароли, не давать избыточных доступов кому попало, и внимательно следить за развёрнутыми Open Source‑системами. Поехали. Субботу в августе 2022 года я запомню надолго. Рано утром приходит алерт о том, что наш сервис по обмену скинами CS.MONEY грабят: с ботов воруют игровые предметы на сумму без малого 1 млрд рублей. Slack разрывается, в Telegram один за другим появляются новые рабочие чаты — я, продукт и остальные команды шокированы и расстроены. А ещё мы как никогда собраны. Спустя пару дней после ограбления мы буквально, как в старых мемах, найдём злоумышленника по IP-адресу, узнаем его почту, реальный физический адрес и получим доступ к другой информации: например, обнаружим, что на нашего героя уже заведено несколько дел о мошенничестве. Затем мы пришлём ему напрямую в мессенджер все скриншоты с составом преступления, поговорим по душам и выясним, как именно он нас взломал.  Но обо всём по порядку. Давайте отмотаем назад и попытаемся понять, что произошло в день одной из самых крупных хакерских атак в истории трейдинга игровыми предметами. Дисклеймер: CS.MONEY — это маркетплейс для покупки, продажи и обмена внутриигровых предметов, в основном CS:GO. Все предметы CS:GO принадлежат Steam. Мы зарабатываем на комиссии с прямых сделок между пользователями (p2p), или сами покупаем предметы, чтобы позже продавать их другим игрокам. Во втором случае все выкупленные скины мы храним на «складах» — наших ботах, а логистику предметов обеспечиваем при помощи аккаунтов в Steam. Работает это так: у Steam есть API, при помощи которого можно обменивать скины между Steam-аккаунтами. Если очень упрощённо, то фронт CS.MONEY выступает в качестве витрины магазина, а бэкэнд сервиса — это обёртка поверх Steam, в которой находятся бизнес-правила работы нашего сервиса.  Ночью 13 августа 2022 года неизвестные взломали CS.MONEY. Я узнал о проблеме из Twitter: пользователи писали, что от наших ботов им приходят торговые предложения на скины для Counter-Strike: Global Offensive (CS:GO). Первая мысль: кто-то взломал наш API и обменивает предметы через него. Команда тут же начала переносить базы данных и виртуальные машины из OVH и self-hosted-подсистем в AWS и as Service. Часть self-hosted-баз мы вывели в RDS и закрыли от внешнего мира, ограничив доступ к ней для разработчиков (исторически сложилось, что часть инфраструктуры у нас была общедоступна).  Мы закрыли внешний доступ к основной базе данных и сбросили все доступы, кроме самых необходимых — так вся инфраструктура оказалась во внутреннем контуре. С помощью Hashicorp Vault команда начала шифровать секретные данные, которые до этого хранились в открытом виде, но это не помогло.  Вскоре стало понятно, что злоумышленники каким-то образом получили доступ к учётным данным и второму фактору, — Steam Guard, — торговых ботов. Дело в том, что у Steam хитрая система двухфакторной аутентификации: сам проверочный код генерируется по мере необходимости через мобильное приложение на основе одного статичного кода. А поскольку и учётные данные, и код для второго фактора, и сами боты хранились в основной базе, вывод очевиден: её взломали.В итоге неизвестные захватили управление торговыми ботами CS.MONEY, на которых в тот момент хранилось 394 000 игровых предметов. После этого кто-то провёл сотни транзакций, рассылая украденное на свои и чужие аккаунты, в том числе и на учётки популярных стримеров и трейдеров, не имеющих отношения ко взлому. Наверное, так злоумышленники пытались замести следы, отвлечь наше внимание и втянуть в мошенническую схему невиновных людей.  Скины рассылали до 5 утра — в первую волну хакерской атаки компания потеряла $6 000 000. Весь день мы пытались понять, в чём проблема, пока не сбросили пароли. Казалось, это сработало: переводы скинов прекратились, но только на время. Как выяснилось позже, операции приостановились не из-за наших действий, а оттого, что злоумышленник просто устал и ушёл спать.  Проснувшись, хакер продолжил грабить сайт: последовала вторая многомиллионная волна воровства, во время которой внутриигровые предметы выводили на аккаунты с ироничным именем CS.MONEY Recovery, чтобы эти переводы выглядели как операция по защите скинов и вводили юзеров в ещё большее заблуждение. 15 августа мы попросили помощи у сообщества, объявив награду в $100 000 за подробную информацию о взломе. В первые несколько дней в соцсети CS.MONEY и на почту прилетали десятки сообщений: нам писали и самозванцы, выдававшие себя за хакеров, и просто желающие забрать кеш, сбивая с толку расследование.  Спустя несколько дней наши ребята вычислили IP-адрес злоумышленника и выяснили, где искать украденные у CS.MONEY скины.  Коллеги проверили IP-адрес предполагаемого злоумышленника через наш сервис аналитики посещений Amplitude, и в логах нашли аккаунт и два адреса электронной почты мошенника — оказалось, хакер заходил на сайт CS.MONEY за несколько месяцев до взлома. В том числе при помощи этих данных нам удалось достать всю информацию, которая помогла найти преступника.  Отыскав контакты злоумышленника, пришло время поговорить с ним лично. Коллега из маркетинга написал мошеннику в WhatsApp, прислал скриншоты, доказывающие, что тот раскрыт, и убедил хакера вернуть учётные данные от наших ботов. Вор вернул управление и рассказал, как ему удалось нас взломать. Ответственность с себя не снимаем: мы крупно облажались. У нас была развёрнута Open Source-система для А/Б-тестирования GrowthBook. Когда-то давно мы захотели попробовать её, и просто не поменяли настройки, оставив их по умолчанию. Позже выяснилось, что в GrowthBook был баг: загрузчик изображений GrowthBook вместо картинки позволял загрузить любой файл в любое место. В нашем случае злоумышленник залил Reverse Shell и захватил контроль над машиной: хакер получил доступ к окружению и узнал, какой базой данных мы пользуемся. Так произошло потому, что в GrowthBook в качестве Data Source был добавлен доступ к нашей внутренней базе. Данные о Data Source хранятся в зашифрованном виде; к сожалению, в нашем случае ключ шифрования остался стандартным: dev.  Но и это ещё не всё. GrowthBook позволял в любой момент создавать нового пользователя с любым паролем. Обычно, запуская сервис впервые, пользователь попадает на страницу ввода учётных данных. В GrowthBook обязательная проверка на возможность создания нового пользователя была только во фронтенде. А создать новую учётную запись в бэкэнде можно было когда угодно — благодаря этому багу хакер смог зайти в нашу систему и загрузить вместо картинки скрипт, получив доступ к базе. После инцидента наш CTO сообщил авторам GrowthBook об этих уязвимостях, патч уже выпущен. Правила «цифровой гигиены для самых маленьких» обошлись нам довольно дорого. Вот несколько важных заключений, полученных на горьком опыте. Всё, что вы показываете внешнему миру (базы, сервисы, инфраструктуру и т. п.), нужно закрывать на 7 замков. Обязательно должна быть двухфакторная аутентификация. От взлома это может и не защитить, но усложнит работу злоумышленникам. Чем сложнее пароли — тем лучше. Не нужно их запоминать: генерируйте случайные комбинации длиной, например, 33 символа, и храните их в менеджере паролей.  И железный принцип: для каждого сервиса — уникальный пароль. В современных реалиях есть смысл использовать модель Zero Trust. Её суть описана в названии: никому не доверяйте. Заставляйте всех авторизовываться, аутентифицироваться и периодически валидировать свой доступ. Чем больше компаний будет соблюдать этим принципам, тем меньше будет утечек данных. И тем безопасней будет мир, в котором мы живём. Уязвимость GrowthBook сыграла ключевую роль во взломе CS.MONEY. Ключевую, но не единственную. Вот ещё несколько важных моментов, на которые нужно обратить внимание:  Проверьте избыточность доступов и создавайте отдельные аккаунты для внешних сервисов. Так, у аналитиков нашей компании были избыточные доступы к базам данных продукта: вместо того, чтобы создать отдельный профиль для стороннего сервиса, по ошибке мы передали GrowthBook излишние права. Это произошло после того, как CS.MONEY добавил новый источник для обогащения поступающих в GrowthBook данных — им стала наша база с конфиденциальной информацией и доступами к ней. Всё это создало путаницу при расследовании инцидента, поиск аккаунта с подозрительным поведением занял у нас много времени. Если бы у нас был отдельный аккаунт для внешних сервисов, то обнаружить дыру в безопасности было бы значительно проще.  Перепроверьте абстракции Helm. Если вы используете Helm Charts, то делайте это очень аккуратно. У нас Helm абстрагировал важную настройку ключа, что позволило GrowthBook запуститься с конфигурацией, недопустимой для эксплуатационного окружения. Пусть ваша оборона будет нерушимой, и да обходят вас стороной шибко умные хакеры. Удачи!