Fin de semana jugando TUCTF-2025 writeup

1v0t
8 min readJan 28, 2025

--

El pasado fin de semana tuvimos la oportunidad de jugar dos CTFs, sin embargo le dimos mayor prioridad a desarrollar los retos de TUCTF 2025 el cual es organizado por Ascii Overflow en su octava edición.

De 485 equipos que jugaron el CTF en esta ocasión ocupamos el puesto 52

y logramos resolver diferentes categorías que antes no jugábamos y que ahora disfrutamos mucho , en esta ocasión logramos resolver todas las web, forense y casi todas las de reversing.

A continuación compartimos la solución y forma en que abordamos diferentes retos de varias categorías por el equipo de Bugs B0unt3r.

Web: My First Secret

Para este reto nos daban un panel de login web, el cual era vulnerable a un SQLi, después de logearme me redirigía al sitio /secret el cual contenía una imagen, al inicio pensé que era cambiar las cookies o quizá cambiar de directorio

Hasta que hice un reverse image de la imagen y usando el navegador Bing uno de los resultado contenía los símbolos muy similares y era una pregunta en Reddit

En la pagina de Reddit confirmaban que pertenecía al alfabeto de mistborn , este alfabeto es un sistema de escritura inspirado en la obra de Brandon Sanderson. Cada símbolo representa una letra del alfabeto inglés, y es utilizado en los libros y en material promocional relacionado con la saga Mistborn. Es un diseño muy estilizado y temático que captura el tono mágico y místico de la serie.

En este punto lo que hice fue buscar el alfabeto y traducirlo manualmente símbolo a símbolo en PowerPoint

Sin embargo me daba la frase thiri is always anothir sicrit

Ya lo que hice fue entender que quizá el creador del reto se equivoco y la E ,la puso como una I, y finalmente arme la frase y la pegue en el formato de flag esperado TUCTF{}

Forense Packet Detective

Nos daban un archivo pcap para analizar, después de analizar paquetes comunes como tcp, http y ver que solo mostraba que eran paquetes de prueba

Opte por buscar en los frames, paquetes que contuvieran el formato de la flag

contains “TUCTF{“

Forense Mystery Presentation

Nos daban un archivo de powerpoint que al abrirlo parecía dañado, sin embargo lo abrí con Notepad ++ y vi que iniciaba con las letras PK , en este momento no recuerdo muy bien si son ZIPs o 7zp

Aun así, procedí a usar 7zip para descomprimirlo y me dio una carpeta con archivos, la cual contenía otro 7z , que al descomprimir contenía un archivo de texto con la flag y recomendaciones de ir a https://github.com/angea/pocorgtfo

Cryptography My First Encryption

Para este reto nos dan un archivo jpeg, sin embargo al abrir la imagen salia que el formato no era compatible.

Usé xdd para inspeccionar los primeros bytes xxd -l 64 flag.jpeg, lo cual muestra los primeros bytes del archivo, que no coinciden con la cabecera estándar de un archivo JPEG (\xFF\xD8)

Dado que según el enunciado decía era xor el cifrado, use GPT para que me ayudara a crear un script para calcular la clave XOR

# Leer el archivo cifrado
with open("flag.jpeg", "rb") as file:
encrypted_data = file.read(64) # Leer los primeros 64 bytes

# Cabecera estándar de un archivo JPEG
jpeg_header = b'\xFF\xD8'

# Calcular la clave XOR
key = bytes([encrypted_data[0] ^ jpeg_header[0], encrypted_data[1] ^ jpeg_header[1]])
print(f"Clave XOR estimada: {key}"

Esto devuelve que la clave podría ser 0

Nuevamente use GPT para que me ayudara a a desencriptar la imagen

 # Descifrar el archivo
with open("flag.jpeg", "rb") as file:
encrypted_data = file.read()

# Usar la clave XOR
key = b'0'
decrypted_data = bytes([byte ^ key[0] for byte in encrypted_data])

# Guardar el archivo descifrado
with open("decrypted_flag.jpeg", "wb") as output_file:
output_file.write(decrypted_data)

print("Archivo descifrado guardado como decrypted_flag.jpeg")

Al final da una imagen de un gatico que en la parte inferior contiene la flag

Los siguientes retos fueron solucionados por N0R37urn, sin embargo su documentación es rápida, así que intentare plasmarla de la mejor manera posible y le seguiré el ritmo 😾

Reto: securityrocks

Es un pcap con información de 801.11 relacionado a wifi

Este reto finalmente se soluciono mirando el TCP follow en donde se observo la cadena:

1KZTi2ZV7tO6yNxslvQbjRGL54BsPVyskwv4QaR29UMKj

La cual estaba en base 62, que al decodificar daba TUCTF{w1f1_15_d3f1n173ly_53cure3}

El siguiente reto fue el Bunker

este parecía tener relación con el CVE-2023-32784, el cual empezamos a realizar el ataque con un script que encontramos para identificar la posible contraseña

Posible credencial identificada gL0Ry_2_M4nk1Nd!_Y0RH4

La cual nos permitió abrir el vault de keepass

Revisando en el historial de una entrada de keepass, había un historial donde estaba la flag

Para este punto ya teníamos todos los retos forenses solucionados

Reto Techno Oracle

Este reto era de la categoría Misc, sin embargo ya teníamos un poco de experiencia en este tipo de retos con LLMs pues las enfrentamos en el CTF de la Ekoparty del 2024

Otro reto que personalmente 1v0t disfruto mucho durante el evento de TUCTF 2025 fue el reto web final Shopping Time

Para este reto nos daban un archivo app.py y un sitio web para analizar, después de analizar el archivo entendimos que la aplicación lo que hace es buscar los items: pantalón, camisa y sombrero mediante una petición get a la ruta /review?item=Hat

Pero si item es igual a “Flag”, devuelve “Blacklisted term detected”.

Si no, calcula el hash MD5 del valor de item, toma los primeros 6 caracteres, y los usa como parámetro para consultar la base de datos SQLite. y si el item no esta lo redirige al sitio inicial

Aunque se usa una consulta parametrizada para evitar SQLi clásico, el valor hash[0:6] es derivado del MD5 del input.

Pero si se lograba identificar colisiones de hash (dos valores distintos que generen el mismo hash truncado), podrías extraer otros datos de la base de datoshttps://blog.toadsec.io/2022/06/12/colisiones-md5-sha1.html, es decir otro valor que me de el mismo hash que Flag, para eso me ayude de GPTpara generar un script que permita obtener el valor truncado del hash de la flag:

import hashlib

item = "Flag"
hash_value = hashlib.md5(item.encode()).hexdigest()[:6]
print(f"Hash truncado de 'Flag': {hash_value}")

Y con este script conocer las colisiones

import hashlib
import itertools
import string

target_hash = "C58360"
charset = string.ascii_letters + string.digits

for combo in itertools.product(charset, repeat=5):
test_str = "".join(combo)
hash_value = hashlib.md5(test_str.encode()).hexdigest()[:6]
if hash_value == target_hash:
print(f"Colisión encontrada: {test_str}")
break

Una vez identificada la colisión fue proceder a enviarla en la petición get al servidor del reto, así permitirá la consulta a la DB del producto restringido Flag

Es increíble ver el progreso del equipo en categorías diferentes a las que son nuestras mas favoritas como OSINT, considero que todo esto puede ser resultado de el continuo entrenamiento que tenemos en nuestro Canal de Discord , en el cual constantemente generamos retos las 24 horas del día los 7 dias de la semana , permitiendo obtener conocimientos muy rápidos de diferentes categorías.

O resolviendo retos realistas como operación hades, la cual incluso recientemente desarrollamos en nuestro primer meetup.

Esperamos poder seguir jugando y aprendiendo en conjunto en diferentes Eventos de este año, y seguramente alguno del grupo generara el debido writeup.

Hasta pronto!

--

--

1v0t
1v0t

Written by 1v0t

OSINT, threat hunting, CTF, forensic analysis, hunting down bad guys to complete the puzzle.

No responses yet