Usa el árbol para saltar entre colecciones sin salir del lector.

archivo Seleccionar un writeup Abrir árbol
NullconCTF2026/WriteupPasty.md READ_ONLY

Pasty

Datos del reto

Campo Valor
CTF Nullcon CTF 2026
Reto Pasty
Categoría Web / Crypto
Flag ENO{cr3at1v3_cr7pt0_c0nstruct5_cr4sh_c4rd5}

Descripción del reto

El servicio era un pastebin que protegía cada paste con una firma "casera". La interfaz solo dejaba ver un paste si id y sig coincidían, así que todo dependía de entender cómo funcionaba esa firma y por qué se podía falsificar.


Reconocimiento

Al crear un paste, el servidor devolvía una URL de este estilo.

view.php?id=<HEX_ID>&sig=<HEX_SIG>

Eso daba justo lo que hacía falta para analizar el esquema, porque entregaba muchos pares válidos (id, sig). La lógica estaba en sig.php, y ahí se veía que la firma no usaba algo estándar como HMAC, sino una construcción propia a partir de SHA256.

En ese punto había que reconstruir suficiente material de la clave a partir de firmas legítimas.


Análisis

El algoritmo derivaba solo 24 bytes efectivos de la clave.

  • m0, m1 y m2
  • tres bloques de 8 bytes sacados de SHA256(k)

Luego, para cada bloque de la firma, elegía uno de esos subbloques según h[8*i] % 3 y lo mezclaba con el hash del mensaje usando XOR y encadenamiento.

El problema era que, si se conocía el mensaje firmado y la firma resultante, se podía despejar cuál era el subbloque usado en cada posición.

  • c0 = b0 XOR o0
  • ci = bi XOR oi XOR o(i-1) para i > 0

Como al crear pastes el mensaje firmado id era conocido, también lo era SHA256(id). Reuniendo suficientes firmas válidas, se terminaban recuperando m0, m1 y m2 completos.

La parte importante aquí fue darse cuenta de que la firma "casera" no estaba ocultando bien el material secreto. Cada nueva firma filtraba un poco más.


Resolución

La estrategia fue esta.

  1. Crear muchos pastes y guardar cada par (id, sig).
  2. Calcular SHA256(id) para cada uno.
  3. Separar sig en cuatro bloques de 8 bytes.
  4. Despejar qué bloque secreto se usó en cada posición.
  5. Rellenar m0, m1 y m2 hasta tenerlos completos.
  6. Recalcular una firma válida para id = "flag".
  7. Pedir view.php?id=flag&sig=<firma_falsificada>.

Una vez recuperados los tres subbloques de clave, el resto consistía en reproducir el algoritmo del servidor con un id nuevo. No hacía falta romper SHA256. El problema estaba en la construcción alrededor del hash.


Flag

ENO{cr3at1v3_cr7pt0_c0nstruct5_cr4sh_c4rd5}