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

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

Web2Doc2

Datos del reto

Campo Valor
CTF Nullcon CTF 2026
Reto Web2Doc2
Categoría Web
Flag ENO{weasy_pr1nt_can_h4v3_f1l3s_1n_PDF_att4chments!}

Descripción del reto

El servicio convertía una URL en PDF usando Flask y WeasyPrint. A diferencia de la versión anterior, ya no había un endpoint directo para leer la flag, así que había que conseguir que el propio generador de PDF leyera /flag.txt.


Reconocimiento

Pasar file:///flag.txt como URL principal no funcionaba porque el backend descargaba la página antes de enviársela a WeasyPrint. Revisando cómo trabaja WeasyPrint aparecía una opción que servía para esto: los adjuntos en HTML.

Se podían declarar así.

<link rel="attachment" href="URL" title="flag">

Si WeasyPrint resolvía ese href, el contenido terminaba incrustado dentro del PDF final.


Análisis

La clave aquí estaba en separar dos contextos.

  • El backend sí necesitaba una URL pública para descargar el HTML.
  • Pero una vez descargado ese HTML, WeasyPrint resolvía recursos adicionales desde el propio servidor.

Eso permitía alojar una página pública e incluir dentro de ella un adjunto con file:///flag.txt. Aunque la URL principal tuviera que ser HTTP, el archivo adjunto se resolvía localmente durante la generación del PDF.

No había que hacer que el backend abriera file:///flag.txt como página principal. Era suficiente con hacer que WeasyPrint lo tratara como un adjunto durante la fase de renderizado.


Resolución

La página maliciosa podía ser tan simple como esta.

<link rel="attachment" href="file:///flag.txt" title="flag">

El flujo fue este.

  1. Subir ese HTML a una URL pública.
  2. Enviar esa URL al servicio de conversión.
  3. Dejar que WeasyPrint generara el PDF.
  4. Descargar el PDF resultante.
  5. Extraer el adjunto o revisar el stream hasta encontrar la cadena ENO{...}.

En el PDF final, el contenido de /flag.txt quedaba incrustado como adjunto, así que se podía sacar sin necesidad de leer el archivo directamente desde la web.


Flag

ENO{weasy_pr1nt_can_h4v3_f1l3s_1n_PDF_att4chments!}