Каждый патч порождал новые способы взлома, а индустрия продолжала игнорировать системные изъяны.
С тех пор как в языке программирования Ruby появилась возможность сериализации через модуль Marshal, разработчики и специалисты по безопасности оказались втянутыми в затяжную игру в «обход и заплатка». История этих уязвимостей стала наглядным примером того, как косметические меры по борьбе с отдельными ошибками не работают в корне, если основная архитектура остаётся неизменной. Эволюция эксплойтов в Marshal — это десятилетняя хроника бессилия временных решений перед системной уязвимостью.
Первое документированное предупреждение о рисках использования Marshal.load появилось в январе 2013 года, когда Чарли Сомервилль завела тикет на баг-трекере Ruby. С этого момента началась череда исследований, публикаций и CVE, которые показывали всё новые и новые пути к удалённому выполнению произвольного кода через десериализацию Marshal-объектов.
Одним из поворотных моментов стал декабрь 2024 года. В версии Ruby 3.4.0-rc1 оставался код, не тронутый последние 16 лет, и в нём скрывалась брешь. В это же время исследователь Люк Янке опубликовал новый метод эксплуатации Marshal. Хотя баг был устранён до релиза финальной версии, сама ситуация подчеркнула: даже устаревшие, давно не менявшиеся участки кода могут стать вратами для атаки.
Классический пример уязвимого кода — контроллер в Ruby on Rails, который загружает входящий параметр с использованием Marshal.load. Подобный подход считается равнозначным удалённому выполнению кода, если входные данные не проходят строгую фильтрацию. Отправка правильно сформированного бинарного объекта могла бы вызвать выполнение команд на сервере, в том числе чтение файлов или исполнение shell-скриптов.
С ростом интереса к теме появляются более изощрённые методы поиска и построения гаджетов — элементов Ruby-библиотек, которые можно использовать в десериализуемом объекте для создания цепочек исполнения. В 2018 году Люк Янке публикует универсальный RCE-гаджет для Ruby 2.x. Вслед за ним выходят статьи и отчёты от других исследователей, включая Etienne Stalmans, Уильяма Боуллинга и проект Zero Day Initiative.
В 2021–2022 годах появляются обновлённые эксплойты, нацеленные уже на Ruby 3.x. Тогда же выходит новая версия YAML-библиотеки Psych, где безопасная загрузка объектов становится поведением по умолчанию. Казалось бы, прогресс очевиден. Но настоящая автоматизация поиска эксплойтов начинается позже.
С 2024 года начинается «современная эра» Ruby-десериализации. Исследователи вроде Алекса Леаху (Include Security) и Питера Штёкли (GitHub Security Lab) применяют программный анализ и interprocedural CodeQL-запросы для выявления уязвимостей. Исследования выходят за рамки Marshal, включая XML, JSON и YAML. Появляются публичные PoC, инструкции по эксплуатации, инструменты анализа и рекомендации для защиты. Само использование Marshal рассматривается как недопустимая практика.
На момент публикации этого материала, несмотря на все предупреждения и меры, в популярной инфраструктуре RubyGems.org всё ещё остаются участки кода с риском Marshal-десериализации. Эти случаи классифицированы как «информационные» уязвимости, однако примеры предыдущих обходов показывают: даже малозаметная дыра может перерасти в критический инцидент.
Для улучшения ситуации предлагаются шаги как для отдельных разработчиков, так и для сообщества Ruby в целом. В краткосрочной перспективе — аудит кода на использование Marshal, внедрение правил Semgrep и переход к более безопасным форматам (например, JSON с ручной реконструкцией объектов или MessagePack). В долгосрочной — постепенное удаление самого Marshal из языка.
Также предлагается ввести Marshal.safe_load с ограничениями по разрешённым классам, добавить предупреждения при вызове обычного Marshal.load, а затем заменить его поведение на безопасное по умолчанию. И только после нескольких версий полностью отказаться от небезопасной загрузки объектов.
История Ruby и Marshal показывает: удобство часто оказывается врагом безопасности. Если инструмент позволяет создать RCE с минимальными усилиями, то он будет эксплуатироваться снова и снова. До тех пор, пока не будет вырезан из экосистемы полностью.