#Waiting an eternity
Author: voxal

Como en mucho retos web, inicialmente solamente tenemos un texto en la web (just wait an eternity). Como de costumbre, abro las herramientas de desarrollador del navegador y empiezo inspeccionando el código, no encuentro nada, así que paso a mirar el storage, tampoco. Cambio a la pestaña de network para ver las peticiones que se están realizando y… BINGO!
En la request del recurso principal de la web encontramos en las cabeceras algo interesante…

Pues directo a probar esa URL que viene, pero de momento poco… no iba a ser tan evidente. Nos encontramos un mensaje:
welcome. please wait another eternity.
Pero esta vez si tenemos una cookie:

Si actualizo para ver el comportamiento de la cookie, no cambia, pero en la web aparece otro mensaje…
you have not waited an eternity. you have only waited 145.76487016677856 seconds
Vaya… Parece que está calculando el tiempo que pasa desde que se creó la cookie…mi primera prueba con esta cookie fué ponerala a 0… ya que el nombre del reto es esperando una eternidad… es como si la cookie se hubiese creado en el segundo 0 del universo 🤣 (en mi cabeza sonaba mejor…)
Nada… simplemente obtengo otra cantidad de segundos…Después de probar varias cosas, poner números aleatorios…se me ocurrió que podría probar el número que venia en la pagina principal donde encontré esta url…NADA!
you have not waited an eternity. you have only waited -1e+87 seconds
Fruto de la desesperación… y que según estos mensajes no habia “esperado” lo suficiente… me puse a agregarle ceros a la cookie como si no hubiese un mañana… después de un rato probando… pensé… bueno… si la cookie es un timestamp y el tiempo calculado es desde la cookie… si lo pongo en positivo es como si no hubiese llegado a ese momento en el tiempo…
Le agregué el simbolo negativo a la cookie para “retroceder en el tiempo”… BOOM! Obtengo la flag!
#Funny factorials
Autor: stuxf

Mismos pasos que siempre… inspector, almacenamiento, peticiones… 😴
Primeras cosas que se observan… los enlaces para obtener los estilos… Hostia! Se está obteniendo un recurso? Todo parece que va enfocado a path traversal attack no?
Bueno como en el reto nos dan el código pues lo analizamos un poco para verificar si es correcta nuestra corazonada…
from flask import Flask, render_template, request
import sys
app = Flask(__name__)
def factorial(n):
if n == 0:
return 1
else:
try:
return n * factorial(n - 1)
except RecursionError:
return 1
def filter_path(path):
# print(path)
path = path.replace("../", "")
try:
return filter_path(path)
except RecursionError:
# remove root / from path if it exists
if path[0] == "/":
path = path[1:]
print(path)
return path
@app.route('/')
def index():
safe_theme = filter_path(request.args.get("theme", "themes/theme1.css"))
f = open(safe_theme, "r")
theme = f.read()
f.close()
return render_template('index.html', css=theme)
@app.route('/', methods=['POST'])
def calculate_factorial():
safe_theme = filter_path(request.args.get("theme", "themes/theme1.css"))
f = open(safe_theme, "r")
theme = f.read()
f.close()
try:
num = int(request.form['number'])
if num < 0:
error = "Invalid input: Please enter a non-negative integer."
return render_template('index.html', error=error, css=theme)
result = factorial(num)
return render_template('index.html', result=result, css=theme)
except ValueError:
error = "Invalid input: Please enter a non-negative integer."
return render_template('index.html', error=error, css=theme)
if __name__ == '__main__':
sys.setrecursionlimit(100)
app.run(host='0.0.0.0')
Lineas interesantes y porque… Vamos a analizar dos lineas que son practicamente iguales y son una de las claves:
return render_template('index.html', css=theme)
return render_template('index.html', error=error, css=theme)
Estas dos lineas van a renderizar el index pero inyectándole una etiqueta <style>, que es la que usaremos nosotros para intentar obtener la flag.
La siguiente función es la encargada de filtrar el path para evitar el tipo de ataque que vamos a utilizar en el reto:
def filter_path(path):
# print(path)
path = path.replace("../", "")
try:
return filter_path(path)
except RecursionError:
# remove root / from path if it exists
if path[0] == "/":
path = path[1:]
print(path)
return path
Esta linea se encuentra en una funcion que valida el path que estamos solicitando y nos “limpia” el path para intentar evitar que accedamos a directorios superiores…
Si por ejemplo solicitamos: ../../flag.txt
Este código nos dejaría el path: flag.txt
El bypass típico en estos casos es ..//..//flag.txt quedando el path //flag.txt
Una vez “limpio” el path le pasa un segundo filtro… para eliminar la barra por si intentamos acceder al directorio raíz… y lo que hace es hacernos un favor porque elimina la primera barra, devolviendo el path que he ido buscando… /flag.txt
Vamos a probar…
https://funny-factorials.amt.rs/?theme=..//..//flag.txt
Nada mas probar se observa algo muy claro… hemos perdido todos los estilos… con lo que parece que algo ha funcionado, hemos inyectado un fichero dentro de las etiquetas <style>, inspecionamos el código… VOILÀ!

#Latek
Autor: smashmaster
Este tipo de reto es la primera vez que me lo encuentro, normalmente son SQLI, Path traversal, XSS… Pero bueno vamos a comenzar… entramos en la URL proporcionada por los organizadores y nos encontramos con lo siguiente:

Está claro que hay que buscar una vulnerabilidad para la libreria usada… This is pdfTeX, Version 3.141592653-2.6-1.40.25
En una primera búsqueda (google: pdftex vuln), en los primeros resultados vemos un enlace a… PayloadsAllTheThings!
Dentro del repositorio, vemos que lo primero que nos indica es como leer ficheros, probamos ese payload:
\input{/flag.txt}

En las primeras pruebas no conseguía ver la flag al completo… así que tocaba investigar algo más… Leer documentación, buscar los errores que aparecen en el log… al final encontré esto: Error Emergency Stop
Así que… porque no probar a poner el batchmode? Supuestamente debería ir recibiendo mensaje por lotes no?
\batchmode
\input{/flag.txt}
Efectivamente vamos recibiendo varios mensajes y obtenemos la flag… partida por la mitad pero bueno… la tenemos no?

Estuve probando otros retos pero no pude dedicarle tiempo, ya que ando liado con otro personal relacionado con el mundo CTF…así que… nos vemos en el próximo.