Server-Side Template Injection (SSTI)
Эта техника впервые была задокументирована PortSwigger Research в докладе на конференции Server-Side Template Injection: RCE (удаленное выполнение кода) for the Modern Web App.
В этом разделе мы узнаем, что такое Server-Side Template Injection (SSTI), и изложим базовую методологию эксплуатации уязвимостей Server-Side Template Injection (SSTI). Мы также рассмотрим способы обезопасить собственное приложение при использовании шаблонов.
Лабораторные работы
Если вы уже знакомы с основными концепциями уязвимостей инъекции серверных шаблонов и просто хотите попрактиковаться в их эксплуатации на реалистичных, намеренно уязвимых целях, вы можете получить доступ ко всем лабораторным работам по этой теме по ссылке ниже.
Эта техника впервые была задокументирована PortSwigger в исследовательском докладе 2015 года на эту тему. Если вам интересно, как им удалось эксплуатировать некоторые из этих уязвимостей на живых сайтах, полный отчёт доступен на странице исследований.
Что такое Server-Side Template Injection (SSTI)?
Server-Side Template Injection (SSTI) — это когда атакующий может использовать нативный синтаксис шаблона, чтобы внедрить вредоносную полезную нагрузку в шаблон, который затем выполняется на стороне сервера.
Движки шаблонов предназначены для генерации веб-страниц путём объединения фиксированных шаблонов с изменяемыми данными. Server-Side Template Injection (SSTI) могут возникать, когда пользовательский ввод конкатенируется напрямую в шаблон, а не передается как данные. Это позволяет атакующим внедрять произвольные директивы шаблонов, чтобы манипулировать движком шаблонов, зачастую позволяя им полностью захватывать контроль над сервером. Как следует из названия, полезная нагрузка Server-Side Template Injection (SSTI) доставляется и выполняется на стороне сервера, что потенциально делает их гораздо опаснее чем Client-Side Template Injection (CSTI).
Какие последствия Server-Side Template Injection (SSTI)?
Server-Side Template Injection (SSTI) могут подвергать сайты различным атакам в зависимости от конкретного движка шаблонов и того, как именно приложение его использует. В некоторых редких случаях эти уязвимости не представляют реального риска для безопасности. Однако в большинстве случаев воздействие Server-Side Template Injection (SSTI) может быть катастрофическим.
Наиболее серьезный импакт потенциально позволяет добиться RCE (Remote Code Execution), полностью захватив контроль над сервером бэкенда и используя его для проведения других атак на внутреннюю инфраструктуру.
Даже в случаях, когда полное удалённое выполнение кода невозможно, атакующий часто всё равно может использовать Server-Side Template Injection (SSTI) как основу для множества других атак, потенциально получая доступ на чтение к конфиденциальным данным и произвольным файлам на сервере.
Как возникают уязвимости Server-Side Template Injection (SSTI)?
Server-Side Template Injection (SSTI) возникают, когда пользовательский ввод конкатенируется в шаблоны, а не передается как данные.
Статические шаблоны, которые просто предоставляют плейсхолдеры, в которые подставляется динамический контент, как правило, не уязвимы для Server-Side Template Injection (SSTI). Классический пример — электронное письмо, приветствующее каждого пользователя по имени, например следующий фрагмент шаблона Twig:
Это не уязвимо для Server-Side Template Injection (SSTI), потому что имя пользователя просто передаётся в шаблон как данные.
Однако поскольку шаблоны — это просто строки, веб-разработчики иногда напрямую конкатенируют пользовательский ввод в шаблоны перед рендерингом. Возьмём похожий пример, что и выше, но на этот раз пользователи могут настраивать части письма перед отправкой. Например, они могут выбрать используемое имя:
В этом примере вместо того, чтобы статическое значение передавалось в шаблон, часть самого шаблона динамически формируется с использованием параметра GET name. Поскольку синтаксис шаблона оценивается на стороне сервера, это потенциально позволяет атакующему поместить полезную нагрузку Server-Side Template Injection (SSTI) в параметр name следующим образом:
Подобные уязвимости иногда возникают случайно из-за неудачного дизайна шаблонов. Как в примере выше, вы можете увидеть разные компоненты, некоторые из которых содержат пользовательский ввод, конкатенированные и встроенные в шаблон. В некотором смысле это похоже на уязвимости SQL Injection, возникающие в плохо написанных подготовленных выражениях.
Однако иногда такое поведение реализуется намеренно. Например, некоторые сайты преднамеренно позволяют определённым привилегированным пользователям, таким как контент-редакторы, редактировать или отправлять пользовательские шаблоны по замыслу. Это явно представляет огромный риск для безопасности, если атакующий сможет скомпрометировать учётную запись с такими привилегиями.
Построение атаки инъекции серверных шаблонов
Выявление уязвимостей Server-Side Template Injection (SSTI) и создание подходящей полезной нагрузки обычно включает следующий процесс:

Detect
Уязвимости Server-Side Template Injection (SSTI) часто остаются незамеченными не потому, что они сложны, а потому, что они очевидны лишь аудиторам, которые специально их ищут. Если вы сможете обнаружить наличие уязвимости, её эксплуатация может оказаться удивительно простой. Это особенно верно в несандбоксовых средах.
Как и с любой уязвимостью, первый шаг к эксплуатации — уметь её найти. Возможно, самый простой начальный подход — попытаться перебрать шаблон, внедрив последовательность специальных символов, обычно используемых в выражениях шаблонов, таких как
Если возникает ошибка, это указывает на то, что внедрённый синтаксис шаблона потенциально интерпретируется сервером каким-то образом. Это один из признаков того, что может существовать уязвимость Server-Side Template Injection (SSTI).
Уязвимости Server-Side Template Injection (SSTI) возникают в двух различных контекстах, каждый из которых требует собственного метода обнаружения. Независимо от результатов ваших попыток фаззинга, важно также попробовать следующие подходы, специфичные для контекста. Если фаззинг оказался неудачным, уязвимость всё ещё может проявить себя с использованием одного из этих подходов. Даже если фаззинг и указывал на уязвимость Server-Side Template Injection (SSTI), вам всё равно нужно определить её контекст, чтобы эксплуатировать её.
Plaintext context
Большинство языков шаблонов позволяют свободно вводить контент либо напрямую с помощью HTML-тегов, либо с помощью нативного синтаксиса шаблона, который будет отрендерен в HTML на бэкенде до отправки HTTP-ответа. Например, в Freemarker строка render('Hello ' + username) будет отрендерена в нечто вроде Hello Carlos.
Иногда это может быть использовано для XSS и фактически часто принимается за простую уязвимость XSS. Однако, задав математические операции в качестве значения параметра, мы можем проверить, является ли это также потенциальной точкой входа для атаки инъекции серверных шаблонов.
Например, рассмотрим шаблон, содержащий следующий уязвимый код:
Во время аудита мы можем протестировать Server-Side Template Injection (SSTI), запросив URL вида:
Если результат содержит Hello 49, это показывает, что математическая операция вычисляется на стороне сервера. Это хорошее доказательство концепции уязвимости Server-Side Template Injection (SSTI).
Обратите внимание, что конкретный синтаксис, необходимый для успешного вычисления математической операции, будет варьироваться в зависимости от используемого движка шаблонов. Мы обсудим это подробнее на шаге Identify.
Code context
В других случаях уязвимость проявляется тем, что пользовательский ввод помещается внутрь выражения шаблона, как мы видели ранее в нашем примере с письмом. Это может принимать форму имени переменной, контролируемой пользователем, помещённой внутрь параметра, например:
На сайте результирующий URL будет выглядеть примерно так:
Это будет отрендерено в выводе как Hello Carlos, например.
Этот контекст легко упустить во время оценки, потому что он не приводит к очевидной XSS и практически неотличим от простого поиска по hashmap. Один из методов тестирования Server-Side Template Injection (SSTI) в этом контексте — сначала убедиться, что параметр не содержит прямой уязвимости XSS, внедрив произвольный HTML в значение:
При отсутствии XSS это обычно приведёт к пустой записи в выводе (просто Hello без имени пользователя), экранированным тегам или сообщению об ошибке. Следующий шаг — попытаться выйти из выражения, используя распространённый синтаксис шаблонов, и попытаться внедрить произвольный HTML после него:
Если это снова приводит к ошибке или пустому выводу, вы либо использовали синтаксис неправильного языка шаблонов, либо, если никакой «шаблонный» синтаксис не оказывается валидным, Server-Side Template Injection (SSTI) невозможна. В качестве альтернативы, если вывод рендерится корректно вместе с произвольным HTML, это ключевой признак наличия уязвимости Server-Side Template Injection (SSTI):
Identify
После обнаружения потенциальной точки для Server-Side Template Injection (SSTI) следующий шаг — определить шаблонизатор.
Несмотря на огромное количество языков шаблонов, многие из них используют очень схожий синтаксис, специально подобранный так, чтобы не конфликтовать с HTML-символами. В результате относительно просто создать полезные нагрузки позволяющие проверить какой движок шаблонов используется.
Часто достаточно отправить некорректный синтаксис, потому что в результате сообщение об ошибке скажет вам, какой именно движок шаблонов используется, а иногда даже какую версию. Например, некорректное выражение <%=foobar%> вызывает следующий ответ от движка ERB на Ruby:
В противном случае вам нужно будет вручную тестировать различные специфичные для языка полезные нагрузки и изучать, как движок шаблонов их интерпретирует. Используя процесс изучения ошибок на основе того, какой синтаксис кажется валидным или невалидным, вы сможете сузить круг быстрее, чем можно ожидать. Распространённый способ сделать это — внедрить произвольные математические операции, используя синтаксис из разных движков шаблонов. Затем вы можете наблюдать, были ли они успешно вычислены. Чтобы помочь в этом процессе, вы можете использовать дерево решений, подобное следующему:

Следует учитывать, что одна и та же полезная нагрузка иногда может вернуть успешный ответ более чем в одном языке шаблонов. Например, нагрузка {{7*'7'}} возвращает 49 в Twig и 7777777 в Jinja2. Поэтому важно не делать выводов на основе единственного успешного ответа.
Exploit
После обнаружения потенциальной уязвимости и успешного определения движка шаблонов вы можете начать пытаться найти способы её эксплуатации.
Как предотвратить уязвимости Server-Side Template Injection (SSTI)
Лучший способ предотвратить Server-Side Template Injection (SSTI) — не позволять пользователям модифицировать или отправлять новые шаблоны. Однако иногда это неизбежно из-за бизнес-требований.
Один из самых простых способов избежать уязвимостей Server-Side Template Injection (SSTI) — всегда использовать «лишённый логики» движок шаблонов, такой как Mustache.
Ещё одна мера — выполнять пользовательский код только в изолированной среде (Sandbox), где потенциально опасные модули и функции полностью удалены. К сожалению, изоляция недоверенного кода по своей природе сложна и подвержена обходам.
Наконец, другой дополнительный подход — принять тот факт, что RCE практически неизбежно, и применить собственную изоляцию, развернув вашу функцию с шаблонами в жёстко ограниченном Docker-контейнере.
Last updated