Сервер выполняет ровно тот код, который ему передали. Если шаблонизатор или функция включения файлов не различает данные и инструкции, приложение добровольно отдает управление своей логикой любому, кто умеет манипулировать путями.
Как возникает Server Side Template Injection
Уязвимость SSTI появляется в момент, когда приложение передает пользовательский ввод напрямую в движок рендеринга шаблонов. Разработчики иногда используют шаблонизаторы для генерации динамического контента, забывая, что эти движки умеют выполнять код. Python фреймворки на базе Jinja2 или PHP приложения с Twig становятся частыми мишенями в реальных инфраструктурах.
Первичная проверка наличия уязвимости всегда начинается с математических выражений. Внедрение конструкции {{7*7}} в параметр имени или сообщения должно вернуть 49 вместо буквального текста. Такой результат подтверждает, что движок интерпретирует ввод как исполняемую инструкцию, а не как строку.
Эксплуатация редко ограничивается простыми вычислениями. Злоумышленник стремится получить удаленное выполнение кода. В Python достижение этой цели происходит через обход песочницы шаблонизатора. Цепочка вызовов __class__.__mro__[1].__subclasses__() позволяет получить доступ к базовым классам системы. Среди них всегда найдется класс, способный читать файлы или запускать процессы. Например, класс os.popen или subprocess.Popen открывает прямой путь к выполнению системных команд. Поиск нужного класса требует перебора индексов в массиве подклассов, что легко автоматизируется кастомным скриптом, так как индекс нужного класса меняется в зависимости от версии интерпретатора.
Иногда получение полноценного удаленного выполнения кода невозможно из-за строгих фильтров. В таких ситуациях атакующий переключается на чтение конфигурационных файлов. Фреймворки вроде Flask хранят критически важные данные в объекте app.config. Извлечение переменной SECRET_KEY позволяет сгенерировать поддельные сессионные куки и получить доступ к панели администратора без взлома паролей.

Механизм локального и удаленного включения файлов
Локальное включение файлов остается классической проблемой, особенно в устаревших PHP приложениях. Функции include, require или file_get_contents принимают путь к файлу в качестве аргумента. Если этот аргумент формируется из пользовательского ввода без строгой валидации, возникает уязвимость LFI.
Злоумышленник использует последовательность символов ../ для выхода за пределы разрешенной директории. Запрос к параметру ?page=../../../etc/passwd заставляет сервер прочитать системный файл с перечнем пользователей. Современные веб-серверы и фреймворки часто блокируют такие попытки, но обходные пути существуют.
Исторически популярным методом обхода был нулевой байт %00. В старых версиях PHP этот символ трактовался как конец строки в стиле языка C. Внедрение ../../../etc/passwd%00 позволяло игнорировать жестко заданное расширение .php, которое разработчик мог добавить в коде приложения. Современные интерпретаторы исправили эту особенность, однако понимание механики помогает анализировать устаревшие системы, которые до сих пор работают в корпоративных сетях.
Удаленное включение файлов встречается реже. Для успешной атаки RFI сервер должен разрешать загрузку внешних ресурсов, что контролируется директивой allow_url_include. По умолчанию эта настройка отключена в большинстве современных окружений. Тем не менее проверка возможности загрузки файлов по внешним URL всегда входит в базовый чек-лист тестирования.
Получение выполнения кода через отравление логов
Когда прямое выполнение команд через SSTI заблокировано, а RFI недоступен, атакующие обращаются к отравлению логов. Этот метод превращает безобидный файл журнала в полезную нагрузку. Веб-серверы, такие как Nginx или Apache, записывают каждый запрос в файл доступа.
Злоумышленник отправляет специальный HTTP-запрос, где в поле User-Agent или URI размещается PHP-код. Сервер сохраняет этот запрос в лог-файл. Затем через уязвимость LFI атакующий включает этот самый лог-файл. Веб-сервер интерпретирует содержимое лога как PHP-скрипт и выполняет внедренный код. Этот метод требует точного знания пути к лог-файлу и прав на его чтение, но в стандартных конфигурациях Linux эти пути хорошо известны.
Повышение привилегий через чтение конфигураций
Чтение файлов редко является конечной целью. Полученная информация служит трамплином для дальнейшего проникновения. Файл /etc/passwd раскрывает имена пользователей и пути к их домашним директориям. Файл /etc/shadow содержит хеши паролей, доступные только суперпользователю.
Успешное извлечение хешей из /etc/shadow переводит атаку в офлайн-режим. Инструменты вроде John the Ripper или Hashcat позволяют проводить атаки по словарю или методом перебора без взаимодействия с целевой системой. Скорость взлома зависит от сложности паролей и вычислительной мощности атакующего. Слабые пароли администраторов вскрываются за считанные минуты.
Не менее ценной целью становятся приватные SSH ключи. Файл id_rsa в директории .ssh домашнего каталога пользователя позволяет установить зашифрованное соединение с сервером без знания пароля. Если ключ не защищен парольной фразой, атакующий получает полноценный интерактивный доступ к системе от имени скомпрометированного пользователя.
Практические методы защиты файловых операций
Защита от файловых уязвимостей требует архитектурных решений, а не просто фильтрации символов. Черные списки запрещенных строк всегда проигрывают креативности атакующих. Надежная защита строится на принципе белого списка.
При необходимости динамического включения файлов приложение должно сопоставлять пользовательский ввод с заранее определенным списком разрешенных имен. Вместо передачи пути ../../../config.ini клиент отправляет идентификатор config_1. Серверная логика преобразует этот идентификатор в жестко заданный абсолютный путь, исключая возможность манипуляции директориями.
Шаблоны должны рендериться с включенным автоматическим экранированием. Современные движки предоставляют безопасные методы рендеринга, которые обрабатывают переменные как текст, а не как код. Передача пользовательского ввода напрямую в функции компиляции шаблонов категорически запрещена.
Ограничение прав веб-сервера снижает потенциальный ущерб. Процесс веб-сервера должен работать под непривилегированным пользователем. Механизмы вроде open_basedir в PHP или chroot в Linux изолируют приложение, не позволяя ему читать файлы за пределами выделенной директории. Даже при успешной эксплуатации уязвимости атакующий останется заперт в песочнице.
Инструменты и методики тестирования
Автоматизированные сканеры часто пропускают сложные цепочки SSTI или нестандартные векторы LFI. Ручное тестирование остается золотым стандартом. Burp Suite предоставляет гибкие возможности для фаззинга параметров. Модуль Intruder позволяет быстро перебирать списки путей и полезных нагрузок, анализируя изменения в длине ответа или кодах состояния HTTP.
[√] Проверка математических выражений в параметрах шаблона
[√] Перебор стандартных путей к логам и конфигурационным файлам
[ ] Попытка обхода фильтров через кодирование URL или двойное кодирование
[x] Анализ исходного кода на наличие жестко заданных путей
Для SSTI полезно использовать кастомные скрипты, генерирующие полезные нагрузки под конкретный шаблонизатор. Понимание внутренней структуры движка позволяет создавать минималистичные пейлоады, обходящие примитивные фильтры. Анализ исходного кода приложения, если он доступен, дает точное понимание того, как обрабатывается ввод, и помогает найти уязвимые места, недоступные для черного ящика.