![]() |
https://forum.antichat.xyz/attachmen...9708675537.png
Эй. Да, тебе. Тот, кто зашёл сюда не по ссылке с очередного инфосек-паблика, а нашёл эту тему через глубинный поиск, через закладку в браузере, через шёпот в IRC. Тот, у кого от бесконечных статей «Top-5 SSTI Payloads для Django» уже сводит скулы. Приветствую. Вытащи из-под стола тот самый пыльный системник, на котором ты когда-то запускал свои первые скрипты. Поставь рядом чашку того, что помогает думать. У нас с тобой будет долгий и честный разговор. Посмотри вокруг цифрового пространства. Что ты видишь? Все говорят об одном и том же. Flask. Django. Spring. «О, я нашел {{config}}!» - кричат на конференциях. «Смотри, {{7*7}} работает!» - пишут в Иксе. Это поверхность океана, под которым скрываются целые континенты забытого, непопулярного, но от того не менее важного кода. А теперь посмотри туда, куда не смотрят другие. Внутренние админки старых компаний. Панели управления облачных провайдеров второго эшелона. Системы мониторинга, которые крутятся на серверах у системного администратора, уверенного, что «раз нет доступа извне, то и нет». Инструменты для DevOps, написанные впопыхах. Кастомные CMS для небольших, но денежных проектов. Что их объединяет? Часто - не раскрученный фреймворк, а его ядро - движок шаблонов. И два имени звучат здесь чаще всего: Jinja2 и Twig. Почему именно они? Потому что они - лучшие в своём классе. Jinja2 - это не только Flask. Это язык шаблонов для Ansible, SaltStack, Superset, и ещё сотен проектов, где нужно генерировать текст (конфиги, отчёты, HTML) с логикой. Это выбор того самого сисадмина, который знает Python и хочет «быстро написать утилитку для отчётов». Twig - это не только Symfony. Это элегантный, строгий и очень мощный движок для PHP, который выбирают те, кто устал от лапши вперемешку с PHP-кодом. Кто хочет красоты и порядка. Они выбирают эти движки за их надёжность, скорость и… за декларируемую безопасность. И вот здесь начинается наша история. Потому что эта самая «безопасность» - часто иллюзия, построенная на непонимании. Разработчик слышит: «В Twig нельзя вставить PHP, значит он безопасен». Или: «Jinja2 работает в песочнице». И он расслабляется. Он начинает передавать в шаблоны всё подряд: объекты конфигурации, глобальный контекст приложения, служебные объекты с методами типа runCommand(). Он думает, что раз нет прямого вызова eval(), то и бояться нечего. Он ошибается. Глубоко и фундаментально. Template Injection в этих движках - это не просто баг. Это критическая ошибка. Это несоответствие между ментальной моделью разработчика («шаблон - это просто вид») и реальной моделью выполнения («шаблон - это программа, компилируемая в байт-код и выполняемая в контексте приложения»). И когда ты, исследователь, понимаешь эту разницу, перед тобой открываются не просто дыры, а целые тоннели в логику приложения. Цель этой статьи - не дать тебе ещё один список полезных нагрузок для копипасты. Цель - научить тебя мыслить как движок шаблонов. Понять, как Jinja2 превращает {{ name }} в Python-байткод. Увидеть, как Twig компилирует {{ user }} в PHP-класс. Узнать, где в их памяти прячутся ссылки на os, sys, subprocess или shell_exec. Научить тебя в условиях полной тишины (blind), когда нет вывода, строить цепочки из доступных кирпичиков, чтобы добраться до RCE. Это ремесло. Это археология. Это инженерия наоборот. Я покажу тебе не только успешные эксплойты, но и те пути, которые ведут в никуда, и объясню - почему. Здесь будут:
Готов? Выдыхай. Отключайся от шума. Мы погружаемся в тишину и детали. Начинаем. JINJA2 - НЕ ТОЛЬКО ЦВЕТОЧКИ ВО FLASK Анатомия Зверя: Как Jinja2 Думает Все начинается с понимания. Jinja2 - это не черный ящик. Это компилятор шаблонов в Python-байткод. Да, именно так. Твой {{ name }} превращается в код Python, который потом выполняется. Это ключ ко всему. Когда ты видишь уязвимость, это почти всегда Context Misalignment. Разработчик дает тебе песочницу, но забывает закрыть калитку. Или думает, что песочница - это железобетонный бункер. На деле же:
Тебе не нужно ничего скачивать. Открой Python консоль: Python: Код:
importДиагностика «на коленке» Ты нашел подозрительный параметр? Вбей классику, но с диагностикой: {{ 7*7 }} → 49? Есть рендеринг. {{ 7*'7' }} → 7777777? Есть (конкатенация строк в Jinja). {{ request }} → Ошибка? Или объект? Смотри на ошибки. Ошибки Jinja2 - твой лучший друг. Они выдают имена переменных контекста, структуру. Классика, которая всё еще работает: Иерархия - наше всё Забудь про {{config}}. В чистом Jinja2 его нет. Начни с основного вектора: достижение корня всех объектов - object. Цель: добраться до подклассов object, найти среди них те, что дают RCE. В Python всё - объект. Даже классы - это объекты класса type. Базовый сценарий (когда в контексте есть хоть что-то, например, строка '' или число): Python: Код:
{Python: Код:
{
Код: Код:
jinja2Обход ограничений: Когда базовые пути отрезаны Сценарий 1: Фильтруются символы [, ], _.
{{ (''|attr('class')|attr('mro')|attr('getitem')(1)|attr('subclasses')()|attr('getitem')(414))('id') }} Сценарий 3: SandboxedEnvironment с переопределенными is_safe_callable.
Код: Код:
jinja2
Код: Код:
jinja2Скрытые жемчужины: Глобальные функции и их globals Это твой секретный ключ. В Environment по умолчанию есть куча функций: range, dict, lipsum, cycler, namespace. У каждой есть атрибут globals - это словарь глобальных переменных модуля, в котором функция определена (обычно jinja2.utils или jinja2.runtime). В этом словаре могут быть ссылки на sys, os, или даже на сам Environment. Практика:
Код: Код:
jinja2Побег из «железной» песочницы: Атака на сам Jinja2 Бывают случаи, когда разработчик кастомно переопределил всё, что можно. Последний рубеж - атака на внутренние структуры Jinja2. Всё в Python - объект. Сам объект Template, объект Context. Если у тебя есть доступ к объекту контекста (часто self, но в Jinja2 его нет по умолчанию), можешь из него вытащить Environment. Где взять self? В макросах (если они доступны). Внутри макроса {{ caller.self }} или {{ varargs.self }} может ссылаться на контекст. Или, если тебе доступны тесты (функции вида callable()), через них можно добраться до глобальных переменных. Это уровень археологических раскопок. Требует чтения исходного кода Jinja2. Но это возможно. TWIG - ЭЛЕГАНТНАЯ ЛОВУШКА ДЛЯ НЕОСТОРОЖНОГО РАЗРАБА Философия Twig: Безопасность через Ограничение Синтаксиса Twig создавался с мыслью о безопасности. Нет прямого доступа к PHP. Синтаксис строгий. Фильтры и функции - всё, что есть у разработчика. Поэтому разработчики расслабляются. Они думают: «Раз нельзя вставить PHP, значит безопасно». Ха. Классическая ошибка. Twig, как и Jinja2, компилируется. В PHP-код. И этот PHP-код потом выполняется. Увидеть скомпилированный шаблон можно в кеше (папка cache/). Посмотри на него когда-нибудь. Это откровение. Twig Console Playground Самый быстрый способ понять Twig - поставить его локально и играть. Bash: Код:
composer requirePHP: Код:
render('Hello {{ name }}!', ['name' => 'alert(1)']);Ключевое отличие от Jinja2: _self и _context В Twig есть две волшебные переменные, которые часто забывают заблокировать или понять:
Если у тебя есть _self, ты можешь получить объект Environment и через него - доступ к глобальным переменным Twig, которые разработчик мог добавить. Код: Код:
twigВектор №2: _self → getTemplateName() → loadTemplate() → RCE? Не так просто. Но _self дает доступ к twig.loader - загрузчику шаблонов. Если это Twig\Loader\FilesystemLoader, можно попробовать путь к файлу, но это редко дает RCE напрямую. https://forum.antichat.xyz/attachmen...9708747873.png Самый сочный вектор: _self и _context в симбиозе с методом {{ _self.env.setCache() }} Это менее известный, но мощный путь. Environment имеет метод setCache(). Что, если мы можем изменить путь к кешу на контролируемую нами директорию? А затем сгенерировать шаблон, который скомпилируется в PHP-код с нашим шелл-кодом? План:
Классика жанра: Поиск функции system() в контексте Часто разработчики добавляют в Twig глобальные функции или фильтры для удобства. Например: PHP: Код:
$twigКак искать? Выведи весь _context: Код: Код:
twigСмотри внимательно. Ищи объекты, которые выглядят как хелперы, утилиты. Исследуй их методы через {{ object.methods() }} (если есть такой метод) или пытайся угадать: exec, run, system, passthru. Фильтр map и filter - твои союзники для рефлексии В Twig нет прямого class, но есть мощные функциональные фильтры.
Код: Код:
twigМожно попробовать вызвать call_user_func или array_map, если они доступны в контексте. Эксплуатация через замыкания (Closure) и call_user_func Если в контекст попал объект Closure (анонимная функция) или доступна функция call_user_func, можно раскрутить цепочку. Допустим, у нас есть объект $obj с методом getCallback(), возвращающий Closure. В шаблоне: Код: Код:
twigАтака на изоляцию песочницы (если используется Sandbox) Twig имеет встроенную песочницу. Разработчик должен явно разрешить теги, фильтры, методы, свойства. Если он это сделал плохо (а так часто бывает), можно вырваться. Проверь, какие фильтры разрешены. Фильтр escape (e) часто вызывает twig_escape_filter. Исследуй, что еще доступно. Иногда разрешают фильтр sort, который может использовать usort и вызывать callable-объект. АРСЕНАЛ ПРАКТИКА: ИНСТРУМЕНТЫ, СКРИПТЫ, ПОДХОДЫ Tplmap - но не для паразитирования, а для изучения Знаю, знаю. tplmap - это почти как sqlmap для шаблонов. Но я призываю не использовать его вслепую. Изучи его код. Посмотри, как он строит цепочки для Jinja2, для Twig. Это кладезь идей. Запусти его с флагом --verbose, смотри, какие полезные нагрузки он подбирает, как он определяет контекст. Это учебное пособие. Не будь скрипт-кидди, будь человеком, который понимает, что делает скрипт. Свой собственный фаззер для контекста (Python + Jinja2) Напиши простой скрипт, который подключается к уязвимому эндпоинту и перебирает не только {{7*7}}, но и пытается вытащить class через различные глобальные объекты: Python: Код:
importИнструмент №6: Генератор цепочек для Jinja2 вслепую (Blind SSTI) Когда вывода нет, но есть задержка (time-based) или внешний отклик (OOB). Нужно строить цепочки, которые приводят к os.system('sleep 5') или requests.get('http://your-collaborator/'). Стратегия:
Найди папку кеша Twig (часто /tmp, var/cache, app/cache). Если есть LFI, читай файлы __TwigTemplate_*.php. Там ты увидишь:
Разработчик, если ты читаешь это (а ты должен), вот тебе прямая речь:
НЕ КОНЕЦ, А ТОЧКА СБОРКИ Давай оглянемся на пройденный путь без иллюзий и пафоса. Мы начали с простой, но радикальной мысли: мейнстрим-слеп к периферии. Пока толпа штурмует Django и Spring, умный исследователь с фонарём и лопатой идёт в тихие, плохо освещённые подвалы веба - туда, где работают Jinja2 и Twig. Не потому, что они «слабее». А потому, что их безопасность - это миф, подкреплённый самоуверенностью разработчика. Мы разобрали этот миф на молекулы. Что, по сути, мы сделали? Мы не изучали «уязвимости». Мы изучали архитектуру и последствия её неверного понимания. Каждая цепочка {{ ''.class.mro[1].subclasses() }} - это не просто трюк. Это демонстрация фундаментального принципа Python: всё есть объект, и если тебе дали доступ к песочнице, но оставили в ней зёрна самого языка, ты можешь вырастить из них всё что угодно. Каждая манипуляция с _self в Twig - это намёк на то, что среда выполнения шаблонов никогда не бывает полностью изолирована от среды хозяина, если только её не построили с параноидальной тщательностью, на что у 99% разработчиков нет ни времени, ни знаний. Не всё так просто в реальном мире. Часто ты наткнёшься на кастомную песочницу, которая ломает все твои цепочки. Чаще всего - на полное отсутствие вывода. Иногда - на WAF, который давит любые попытки. И тогда всё, что мы прошли - это не инструкция, а фонд идей, методология, способ мышления. Ты не будешь помнить наизусть индекс класса subprocess.Popen. Но ты будешь помнить, что нужно искать init.globals у любого подозрительного класса. Ты не будешь тыкать слепо {{ config }}, а сначала посмотришь, что есть в контексте через ошибку или через {{ lipsum.globals.keys()|list }}. Самое важное, что ты должен вынести - это сдвиг парадигмы.
Теперь о нас, о сообществе. Мы сделали это -прошли длинный, детальный материал. Такие знания не должны оставаться в одном месте. Они должны распространяться, но не для вандализма, а для улучшения всей экосистемы. Если ты находишь уязвимость - ответственно сообщай. Если видишь в коде коллеги риск SSTI - мягко объясни, в чём проблема. Мы не вандалы, мы - инженеры обратной связи. Наша ирония и скепсис направлены не на разрушение, а на устранение халтуры. Мы делаем софт крепче, находя его слабые места. Это наша хакерская эмпатия. Что дальше?
Когда ты в следующий раз увидишь в исходниках render_template или $twig->render() с параметром из запроса, ты не просто вставишь {{7*7}}. Ты увидишь перед собой сложную, живую систему, которую можно исследовать, понять и, если надо, указать на её изъян. Ты будешь делать это не как скрипт-кидди, а как специалист. Это и есть главная цель. Удачи, товарищ. Помни: глубина побеждает шум. Знание переживает хайп. А честный, подробный разбор - это наше оружие и наш щит. |
| Время: 12:08 |