У коммерческих решений есть очевидные плюсы: профессиональная поддержка, регулярные аудиты, соответствие стандартам и сертификация. Open source — бесплатен, гибок, позволяет глубоко кастомизировать систему под свои нужды и, как правило, поддерживается активным сообществом.

Но независимо от выбранного подхода нужно полагаться только на себя и самостоятельно проверять безопасность всех компонентов, которые вы внедряете в инфраструктуру. Даже если речь идет о популярном проекте с тысячами звезд на GitHub…

Привет, Хабр! Меня зовут Наташа Баранова, я специалист по анализу защищенности веб-приложений в Selectel. Сейчас расскажу, как мы нашли критическую уязвимость в одном из open source-проектов с 10 000 звезд.

С чего все начиналось

Есть такой классный и довольно популярный open source-почтовый сервер — Mailcow. Он заслуженно пользуется спросом: в сети есть подробные гайды о работе с решением, да и в целом документация хорошо описана.

Интерфейс Mailcow.
Интерфейс Mailcow.

В один из дней мы в отделе информационной безопасности решили провести пентест этой самой «почтовой коровы» — и результат оказался неожиданно интересным. Но перед продолжением истории нужно вспомнить, что такое SSTI.

Security Center

Рассказываем о лучших практиках и средствах ИБ, требованиях и изменениях в законодательстве.

Исследовать →

Немного про SSTI

Сам по себе фреймворк — это набор библиотек, инструментов и готовых решений, которые упрощают и ускоряют разработку программного обеспечения. Одним из таких инструментов является шаблонизатор — он автоматически подставляет данные в заранее определенные места и формирует итоговую страницу. Работает шаблонизатор с шаблонами — файлами, где задается общая структура страницы и отмечаются области, в которые будет подставляться динамический контент.

SSTI (Server-Side Template Injection) — это уязвимость, которая возникает именно в контексте, когда формирование шаблона происходит из небезопасного пользовательского ввода. Если данные от пользователя попадают в шаблон без должной фильтрации, злоумышленник может внедрить специальные конструкции шаблонизатора и добиться выполнения произвольного кода.

Такую уязвимость мы как раз и обнаружили в компонентах Mailcow — шаблоне уведомления о переполнении квоты почтового ящика и попадании в карантин.

Как мы обнаружили уязвимость

Во время аудита Mailcow мы обратили внимание, что в админке (/admin) можно было редактировать шаблон email-уведомлений о переполнении квоты почтового ящика. Для этого нужно было перейти в раздел System → Configuration → Settings → Quota.

Место в панели администратора, где редактируется шаблон уведомления о достижении квоты.
Место в панели администратора, где редактируется шаблон уведомления о достижении квоты.

Так как проект open source, было легко увидеть, что для рендеринга используется Jinja2. И сразу возникла мысль, можно ли здесь внедрить SSTI…

Для проверки гипотезы была использована полезная нагрузка {{7*'7'}}, которая позволила удостовериться, что данные в шаблон встраиваются как есть. При достижении квоты на указанную почту было отправлено письмо, в котором содержался результат нашей полезной нагрузки (777777), что подтвердило уязвимость. 

А дальше все пошло по знакомому сценарию. Шаблон редактируется без какой-либо фильтрации — и это дает возможность провести SSTI-атаку, и в результате — выполнение произвольного кода на сервере.

Шаги воспроизведения SSTI

Шаг 1. Войдите в систему под администратором и настройте пользовательский шаблон уведомления о переполнении квоты в разделе System → Configuration → Options → Quota notifications.

Шаг 2. Создайте тестовый почтовый ящик в Email → Configuration → Mailboxes и установите для него низкое значение квоты (например, 1 МБ), чтобы было легче тестировать.

Шаг 3. Укажите адрес отправителя для уведомлений о квоте.

Шаг 4. С тестового почтового ящика отправьте несколько писем самому себе, чтобы достичь порога загрузки почтового ящика более 80% от установленной квоты.

Шаг 5. После достижения порога система отправит предупреждающее письмо, используя уязвимый шаблон.

Proof of Concept (PoC)

Сперва мы вывели доступные классы:

{{ ''.__class__.__mro__[1].__subclasses__() }}

А затем обнаружили имеющийся Popen и использовали его для вставки своего shell-кода:

{% set subclasses = ''.__class__.__mro__[1].__subclasses__() %}
{% for c in subclasses %}
	{% if c.__name__ == 'Popen' %}
    	{{ c('cat /etc/passwd', shell=True, stdout=-1).communicate()[0] }}
	{% endif %}
{% endfor %}

Результат

Вывод команды cat /etc/passwd возвращался в теле email-сообщении.

Подтверждение RCE: чтение /etc/passwd.
Подтверждение RCE: чтение /etc/passwd.

Если содержимое письма было обрезано, то можно было получить его полный текст, просмотрев исходный код сообщения и декодировав base64.

Полный текст письма в base64.
Полный текст письма в base64.

Критичность уязвимости

Уязвимость позволяет выполнять произвольный код на сервере (RCE) с правами пользователя vmail, который является критически важным системным пользователем, обеспечивающим функционирование всей почтовой системы.

Для почтовой системы риск является высоким. Уязвимость предоставляет полный доступ ко всем почтовым данным пользователей, возможность чтения/изменения/удаления всех писем и нарушения работы почтовых сервисов, а также — доступ к sieve-фильтрам (возможность перехвата почты).

Но риск ограничен для хоста, поскольку есть изоляция в Docker-контейнере, отсутствует привилегированные права и невозможна эскалация до root без дополнительных уязвимостей.

Для эксплуатации уязвимости понадобится доступ к веб-панели администратора приложения. Это означает, что атакующий должен обладать действующими учётными данными администратора или получить их иным образом (например, через социальную инженерию или перехват). 

Подводим итоги

Никогда не вставляйте непроверенные пользовательские данные напрямую в шаблон.

Затронуты были все версии до 2025-07, а уязвимости присвоен номер CVE-2025-53909. Разработчики быстро отреагировали на репорт — и теперь Mailcow стал немного безопаснее. Сейчас используется Jinja2 SandboxedEnvironment для блокировки доступа к небезопасным методам. Внутри этой песочницы шаблоны могут работать с данными и строить HTML, но не имеют доступа к опасным методам Python вроде subprocess.Popen или обращения к файловой системе напрямую.

Open source — это круто, но не стоит забывать, что его сила не только в открытом коде, а в сообществе, которое его активно поддерживает, развивает и аудирует. Если проект «живой» — это плюс, но даже у популярных решений могут быть серьезные уязвимости.

Проверяйте даже то, что «вроде бы надежно» — и особенно то, что напрямую взаимодействует с пользователями. Email-шаблоны, уведомления, отчеты — частые точки входа и возникновения уязвимостей. Ну и, конечно же, не забывайте обновляться.

Комментарии (7)