Flask + Jinaj2 Server-Side Template Injection

Iniciado por Dedalo, Julio 07, 2018, 01:31:49 AM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Por estos días tuve la oportunidad de trabajar con No tienes permitido ver los links. Registrarse o Entrar a mi cuenta, un micro-framework que te permite hacer webs con Python y sintaxis de Jinja2. La aplicación que llegó a mis manos tenía un login, un panel que trabaja con una base de datos y hasta con algunos temas de criptografía. Me llamó mucho la atención como funcionaba y esto es un poco de lo que pude concluir.

Server-Side Template Injection

Por la forma en la que está diseñado Flask, podemos explotar Server Side Template Injection. Es interesante tomarlo en cuenta para el momento de hacer pentest porque ya le han reportado No tienes permitido ver los links. Registrarse o Entrar a mi cuenta explotando este tipo de vulnerabilidades.

El primer ejemplo es un XSS mediante Template Injection. Por defecto flask no filtra las variables cuando se usa request.args.get('var'). El código a continuación es vulnerable a XSS.

Código: python


from flask import Flask, request, render_template_string

app = Flask(__name__)

@app.route('/XSS')
def hello_xss():
template = '''<h2>Hola %s!</h2>''' % request.args.get('nombre')
return render_template_string(template, person=request.args.get('nombre'))

if __name__ == "__main__":
app.run(debug=True)



El cual se puede explotar fácilmente de la siguiente forma:



Otro vector de ataque que encontré fue LFI a través del popular open(), como se puede ver en el siguiente ejemplo:

Código: python


from flask import Flask, request, render_template_string

app = Flask(__name__)

@app.route('/LFI')
def hello_lfi():
template = '''<h2>Hola %s!</h2>''' % request.args.get('name')
return render_template_string(template, person=request.args.get('name'), get_user_file=get_user_file)

def get_user_file(f_name):
with open(f_name) as f:
return f.readlines()


if __name__ == "__main__":
app.run(debug=True)



El cual se puede explotar de la siguiente forma:



El código que usé en el anterior ejemplo en la variable name fue:

Código: php
<pre> {% for a in get_user_file("/etc/passwd") %} {{a}} {%endfor%} </pre>


También pude haber sacado el archivo completo de la siguiente forma:

Código: php
{{get_user_file("/etc/passwd")}}


Pero le puse el FOR para hacer que se vea mucho mejor, si quieren entender la diferencia entre {{}} y {%%} les recomiendo leer la info sobre FLASK en el link del principio de este post y la verdad 100% recomendable, un framework bien interesante.

Como se pueden imaginar, también se puede explotar Inyección SQL pero he pensado también en otros tipos de explotación bastante interesantes. Si se les ocurren otros métodos de explotación coméntenmelos y no olviden seguirme en TW como @SeguridadBlanca
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Julio 10, 2018, 03:11:18 PM #1 Ultima modificación: Julio 10, 2018, 05:56:55 PM por TheWAV.s
Hola Dedalo, tu publicación y el código que empleaste está bastante minificado para servir como ejemplo básico, aunque yo entienda... otros aún se van a seguir cuestionando.

No explicas los pasos básicos y citas... un writeup en chino, donde peor aún no se puede interpretar nada.

Código: python


from flask import Flask, request, render_template_string

app = Flask(__name__)

@app.route('/XSS')
def hello_xss():
template = '''<h2>Hola %s!</h2>''' % request.args.get('nombre')
return render_template_string(template, person=request.args.get('nombre'))

if __name__ == "__main__":
app.run(debug=True)




Si bien la subclase: request.args.get('nombre') no es correctamente escapado (with escape y la variable person que no sigue las buenas prácticas de programación...) y a su vez permite manipular cualquier entrada de un usuario malintencionado, no es la unica subclase "vulnerable" o mal declarada dentro de ese código, también está render_template_string, que permite renderizar el primer parametro templatecomo una cadena, existen endpoints que renderizan 2 veces o formateen una URL como una cadena.

Código: python


from flask import Flask, request, render_template_string

app = Flask(__name__)

@app.route('/LFI')
def hello_lfi():
template = '''<h2>Hola %s!</h2>''' % request.args.get('name')
return render_template_string(template, person=request.args.get('name'), get_user_file=get_user_file)

def get_user_file(f_name):
with open(f_name) as f:
return f.readlines()


if __name__ == "__main__":
app.run(debug=True)



Esto difiere bastante y no solo depende de open(), también puede darse el mal uso de request.args.get para servir o guardar archivos conduciendo a un directory traversal o LFI.

En algún momento pretendía hacer una publicacion de Server-Side Template Injection, pero...

#Saludos.

Hola TheWAV.s antes que nada agradecerte, por un minuto pensé que nadie comentaría nada.

Primero, si, el tutorial no está hecho para gente que nunca ha visto flask sino más bien para alguien que alguna vez lo vio o vio frameworks similares en python.

Segundo, la verdad creo que estás redundando un poco sobre todo en:
CitarEsto difiere bastante y no solo depende de open(), también puede darse el mal uso de request.args.get para servir o guardar archivos conduciendo a un directory traversal o LFI.

Porque es exactamente lo que hago en el tutorial, a través de la variable que se espicifíca en request.args.get, hace un LFI.

Pero en todo caso agradezco que desees complementar mi post. Después de todo de eso se trata un foro. Igual sería bueno que saques un post para nutrir más la comunidad y para que brindes más información de como funciona flask para las personas que este tutorial les pueda parecer avanzado.

Una vez más vale aclarar que efectivamente este post no es para gente que recién ha visto python o flask, es para personas que ya lo vieron y para que me den más feedback de otros vectores a explotar y nutrirme yo también

Saludos!
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta