Есть такой вид атак, как Template Injection (Внедрение шаблона). Данный вид атак делится на два вида: Server Side Template Injection (SSTI) и Client Side Template Injection(CSTI). В данной статье мы рассмотрим SSTI, а в следующей — CSTI.
Введение
Для разделения бизнес-логики (логика, которая получает и обрабатывает данные) и представления данных (логика, которая показывает данные пользователю), в современных веб-приложениях часто используются шаблонизаторы. То есть шаблонизаторы (в вебе) используются для того, чтобы отделить HTML код(представление данных) от кода языка, ответственного за бизнес-логику (PHP, Java, Python, Ruby/Rails, Perl, JavaScript). Что же такое шаблон? Шаблон – это файл, содержащий HTML и некоторые маркеры, позволяющий этот шаблон обработать и сформировать на его основе конечный HTML код.
Из-за чего возникают уязвимость SSTI? Конечно же, из-за неверной обработки пользовательских данных. В отличии от XSS (с которой SSTI очень легко спутать), Template Injection можно использовать для получения удаленного выполнения команд (RCE).
Но об этом ниже.
Простой маленький пример: предположим, что у нас есть приложение, которое на основе пользовательского ввода, отправляет email с определенным содержанием. Например, представим, что пользователь должен ввести своё имя и в ответ ему придёт email, с его именем:
$output = $twig->render($_GET['custom_email'], array("first_name" => $user.first_name) );
В данном примере пользователь контролирует содержимое шаблона вручную через GET-параметр «custom_email».
Смотрим далее:
custom_email={{7*7}}
49
custom_email={{self}}
Object of class __TwigTemplate_7ae62e582f8a35e5ea6cc639800ecf15b96c0d6f78db3538221c1145580ca4a5 could not be converted to string
Что мы здесь видим? Явное исполнение кода(на стороне сервера) внутри песочницы. В зависимости от используемого шаблонизатора, может стать возможным побег из песочницы и выполнение произвольного кода.
Уязвимость часто возникает из-за того, что разработчики дают возможность пользователю изменять шаблон (некоторые шаблонизаторы предлагают безопасный режим для этих целей).
Все функции, которые используют данные введенные пользователем, могут быть уязвимы, в том числе вики-страницы, ревью и комментарии. Также, причиной уязвимости может быть то, что пользовательские данные вставляются непосредственно в шаблон.
Обнаружение SSTI
Данная методика была представлена на конференции Black Hat USA 2015.
Итак, есть два способа использования введённых пользователем данных.
Первый способ: пользовательский ввод помещается в шаблонное выражение.
$output = $twig->render($_GET['smarty'], array("first_name" => $user.first_name) );
И предположим, что пользователь передаёт следующий параметр:
smarty=Hello
Ответ:
Hello
Для обнаружения SSTI нам нужно внедрить какое-нибудь выражение. Да, шаблонизаторов много, но почти все из них имеют одинаковый базовый синтаксис. Так что если мы передадим в качестве параметра:
smarty=Hello ${7*7}
то получим в ответ:
Hello 49
Второй способ: пользовательский ввод может быть помещён внутри шаблонного выражения, как правило, в качестве имени переменной.
personal_greeting=username
Hello user01
Изменение имени переменной (username) вернёт либо пустой результат, либо сообщение об ошибке. Обнаружить это немного сложней: сначала отправляем серверу имя переменной вместе с каким-нибудь тегом, а потом пытаемся выйти за пределы кода.
personal_greeting=username<tag>
Hello
personal_greeting=username}}<tag>
Hello user01 <tag>
Идентификация
После обнаружения SSTI, мы должны выяснить, какой шаблонизатор используется. Сделать это очень просто, так как есть готовая схема для этой цели. Этот процесс выглядит так:
Нам всего-то нужно подставлять конкретные выражения и следить за ответом сервера. В некоторых случаях одно выражаение может приводить к разным ответам сервера (в зависимость от того, какой шаблонизатор используется). Например, {{7*’7′}} вернёт 49, если используется Twig, 7777777, если используется Jinja2 и не вернёт ничего, если шаблонизатор не используется.
Эксплуатация
После того, как мы выяснили какой шаблонизатор используется, следующий наш шаг — чтение документации. Вот ключевые области на которые стоит обратить внимание:
- раздел «For Template Authors» описывает базовый синтаксис;
- «Security Considerations» — есть огромный шанс, что разработчики не читали данный раздел;
- список встроеных функций, методов, переменных;
- список дополнений/расширений — некоторый из них могут быть включены по умолчанию.
В том случае, если в документации не будет говориться о встроенных переменных, то нам придётся их брутить. Нужные словари находятся в Burp Intruder и FuzzDB.
Практика
Давайте теперь рассмотрим один пример на практике. В качестве подопытного мы возьмём Twig.
Twig — это популярный шаблонизатор PHP. Итак, для демонстрации атаки, я использовал php файл со следующим содержанием (обратите внимание на то, что вам нужно установить и подключить Twig):
<html> <head> <title>Server Side Template injection - TWIG</title> </head> <body> <?php if (isset($_GET['name'])) { $name=$_GET['name']; include 'vendor/twig/twig/lib/Twig/Autoloader.php'; Twig_Autoloader::register(); try { $loader = new Twig_Loader_String(); $twig = new Twig_Environment($loader); $result= $twig->render($name); echo "Hello $result"; } catch (Exception $e) { die ('ERROR: ' . $e->getMessage()); } } ?> </body> </html>
Параметр name отображается в браузере. Присвоим параметру name значение DEFCON:
Ага, всё работает, но давайте передадим {{9*9}} в качестве значения:
А вот и SSTI :) Пришла очередь документации.
Через 30 секунд поиска находим список глобальных переменных, которые всегда доступны в шаблоне, и среди них есть обьект _self:
Документация говорит, что Twig имеет обьект _self, который имеет атрибут env (является ссылкой на Twig_Evironment).В процессе чтения документации, мы приходим к рабочей полезной нагрузке {{_self.env.registerUndefinedFilterCallback(«exec»)}}{{_self.env.getFilter(«id»)}}
Сначала мы регистрируем exec, а потом вызываем системную комманду id:
Вот мы и получили RCE :) Для автоматического обнаружения SSTI существует инструмент TPLMap.
А вот отчёт на HackerOne, где иследователю удалось найти SSTI в Uber.
Выводы
Уязвимость SSTI действительно очень опасная, так как с её помощью мы можем добиться RCE. Обнаружить уязвимость очень просто (хотя часто её можно перепутать с XSS), а вот поиск/разработка полезной нагрузки — очень трудоёмкий процесс (правда, не во всех случаях). Кстати, для этой цели, на Github есть отличная шпаргалка.
И немного доп. https://github.com/epinna/tplmap
Ошибка уровня «$pdo->query(‘SELECT * FROM user WHERE name = ‘ . $_GET[‘name’])»