HackTheBox – Spookifier walkthrough (Challenge Web/Very Easy)

En este post estaremos resolviendo el challenge web llamado «Spookifier» de Hack The Box, calificado como Very Easy. Se trata de un challenge ya retirado.

Caja negra

Tras acceder a la web, vemos que se nos presenta un panel muy simple en el cual meter un texto. Probamos con un valor aleatorio y vemos que la web nos devuelve dicho texto «retorcido» en tipografías raras.

Podemos probar múltiples payloads básicos de inyección como XSS, SQLi y demás vulnerabilidades. Sin embargo, en este caso, el que tiene éxito es el siguiente payload de Server-Side Template Injection (SSTI):

${6*6}

Tal como vemos, obtenemos un «36», lo cual implica que el motor de plantillas está interpretando nuestro código. Seguimos los consejos de PortSwigger (https://portswigger.net/web-security/server-side-template-injection) e identificamos el tipo de plantilla como Mako:

Procedemos a explotar la vulnerabilidad con el siguiente payload (https://book.hacktricks.wiki/en/pentesting-web/ssti-server-side-template-injection/index.html#mako-python):

<% import os;x=os.popen('id').read() %> ${x}

Finalmente, extraemos el flag:

<% import os;x=os.popen('cat /flag.txt').read() %> ${x}

Como bonus, podemos ver que Burp Suite en su versión Professional detecta la vulnerabilidad de manera rápida y eficiente:

Caja blanca

Dado que Hack The Box nos proporciona el código fuente, podemos hacer un análisis de caja blanca del mismo reto. Esto es muy útil, dado que nos permite ver dónde reside la vulnerabilidad en el código fuente. Lo descargamos y, tras descomprimirlo, vemos que existe un fichero denominado «routes.py». Este fichero, a su vez, utiliza recursos del fichero «util.py», cuyo código es el siguiente (omitimos definición de fuentes):

from mako.template import Template

(...)

def generate_render(converted_fonts):
	result = '''
		<tr>
			<td>{0}</td>
        </tr>
        
		<tr>
        	<td>{1}</td>
        </tr>
        
		<tr>
        	<td>{2}</td>
        </tr>
        
		<tr>
        	<td>{3}</td>
        </tr>

	'''.format(*converted_fonts)
	
	return Template(result).render()

def change_font(text_list):
	text_list = [*text_list]
	current_font = []
	all_fonts = []
	
	add_font_to_list = lambda text,font_type : (
		[current_font.append(globals()[font_type].get(i, ' ')) for i in text], all_fonts.append(''.join(current_font)), current_font.clear()
		) and None

	add_font_to_list(text_list, 'font1')
	add_font_to_list(text_list, 'font2')
	add_font_to_list(text_list, 'font3')
	add_font_to_list(text_list, 'font4')

	return all_fonts

def spookify(text):
	converted_fonts = change_font(text_list=text)

	return generate_render(converted_fonts=converted_fonts)

Tal como vemos, la línea en negrita es vulnerable a SSTI, porque el usuario controla de manera indirecta el valor de «converted_fonts» y, por tanto, de «result». Esto es así y es que una de las conversiones de caracteres los deja tal como está (ver variable «font4» del código). Así las cosas, se renderizará la plantilla y al incluir el payload, este se ejecutará sin problema.

~km0xu95

Comments are closed.