~/investigacion $ cat caso-003.md
PaperCut NG/MF: de un bypass de autenticación a cargar la clase que tú quieras
Reconstrucción de la cadena que publica PaperCut el 27 de agosto de 2026: un acceso indebido a la interfaz de administración permite reescribir la configuración de la base de datos, y la carga dinámica de clases del conector ejecuta la clase que esa configuración nombre. El caso mide cuándo dispara y cuándo muere en cada versión del fabricante.
Qué se publicó y cómo se registró
PaperCut emitió el 27 de agosto de 2026 un boletín urgente con dos CVE publicadas en NVD el 28 de agosto: CVE-2026-81578, un control de acceso indebido en la interfaz web de administración, y CVE-2026-82078, una carga dinámica de clases insegura en el conector de base de datos. Las clasificaciones se registran literales y sin mezclar: el CNA da CVSS 4.0 8.8 (Alto) a la primera y 9.4 (Crítico) a la segunda, y NVD da CVSS 3.1 9.8 y 9.1. El CWE también contradice dentro del material del fabricante (CWE-305 frente a CWE-306) y queda anotado tal cual, sin inventarse un ganador.
Los arreglos de mantenimiento son 24.1.10, 25.0.13 y 26.0.5, publicados el 10 de septiembre de 2026 para sustituir los parches de emergencia EPR1 a EPR3. Como el commit de arreglo no es público (código cerrado), el caso trabaja por A/B conductual y sin decompiladores.
Ambas CVE entraron en el catálogo CISA KEV el 2026-08-31 con vencimiento 2026-09-14.
La cadena en tres movimientos
CVE-2026-81578 deja que una petición remota sin autenticar llegue a una ruta de servicio de Tapestry «complex direct» antes de que termine la validación de acceso: un POST forjado reescribe configuración del sistema. CVE-2026-82078 hace que el conector de base de datos instancie lo que nombre el parámetro user-lookup.db-driver con Class.forName antes de conectar, sin lista permitida.
El resultado encadenado: apuntar ese parámetro a una clase ya residente en el classpath de la aplicación hace correr su inicializador estático como el usuario del servicio de PaperCut. Hace falta una sola sesión HTTP sin credenciales: sin subida de ficheros, sin robo de cuentas. La clase usada como prueba de ejecución son 977 bytes ya presentes en el producto.
La paternidad del kill-shot está medida, no afirmada: el sh del shell reporta como padre el proceso JVM de pc-app.
Qué hizo el agente y qué midió
El laboratorio son tres ramas (25.0.11 stock, EPR3 25.0.12-PO-4560.76533 y 25.0.13) en una red Docker --internal sin salida a internet, con restauración a fábrica entre corridas y probada por lecturas en frío de la base de datos.
La matriz de cierre se corrió el mismo día con las mismas bytes del exploit: dispara en 25.0.11 y se apaga en el paso 3 de 11 en las dos ramas arregladas, con el gate de cinco pilares VALID 5/5. Y dentro del build arreglado, las mismas bytes de la clase PoC siguen ejecutando si se fuerzan a cargar: el arreglo cierra el camino de autorización, no el artefacto ejecutable.
El arreglo se localizó sin decompiladores, comparando el override de servicio papercut.application de la rama stock con las dos parcheadas (byte idénticas entre sí) y los hashes de los jars del motor Tapestry (idénticos en las tres ramas). El paquete se autoaudita con un claim gate: claims=32 checks=32 pass=32 fail=0, con las 12 páginas del paper auditadas una por una.
Dónde se detuvo el agente
Este caso publica sus fallos en un attempt log de 49 entradas. La gate de checksum de intake dio MISMATCH contra la fila equivocada del boletín del fabricante (#1), una ubicación del sink confabulada la pilló la autoauditoría antes de que nadie la consumiera (#2), un rebuild destructivo mató un contenedor verde a mitad de corrida (#5) y las lecturas de la base de datos con la base abierta quedaron invalidadas (#8).
Lo más instructivo es #12: en dos de tres corridas del kill-shot la cadena funcionó las tres veces, pero la captura estaba defectuosa por lado del arnés y hubo que ganarla de nuevo. El ciclo de producción del vídeo, incluido el re-shoot, está publicado en las entradas #18 a #43.
En detección también hubo recortes honestos: una regla de red que disparaba también en las ramas parcheadas se rebautizó a nivel de intento, y las reglas YARA que buscan rastro del laboratorio se etiquetan LAB-TRACE y se excluyen del conjunto de hallazgos. Queda sin establecer la prevalencia de la explotación real, la auditoría completa del código cerrado y si alguna revisión de parche de emergencia intermedia sigue siendo sorteable.
Detección y remediación
El primer paso recomendado es pasivo y no toca el servicio: comprobar la banda de versión (todo PaperCut NG y MF 24.1 antes de 24.1.10, 25.0 antes de 25.0.13 y 26.0 antes de 26.0.5) y pasar la auditoría de solo lectura detect_papercut_82078.py --audit. Actualizar a 24.1.10, 25.0.13 o 26.0.5 cierra la cadena; los EPR intermedios no son el destino final.
El paquete de detección sale con Suricata (7 reglas CVE más una de salud del sensor, para que un cero no sea vacío), Sigma de linaje de proceso y forma de log con su registro de disparo o recorte, YARA de remanentes de artefacto y un mapeo de IoC del fabricante cruzado con la forma de laboratorio. Las reglas se rejuegan contra los pcaps publicados con run_suricata.sh, nunca contra una interfaz viva.
Las firmas que valen son de forma, no de nombres de fichero del laboratorio: la línea de DatabaseUtils llevando un valor de tarjeta del atacante al sink, el arranque de la memoria-DB de Derby, el churn de la tabla de configuración y el JVM de PaperCut engendrando una shell interactiva.
Resultado
- Cadena completa sobre 25.0.11.75758 stock: una petición forjada sin autenticar reescribe la configuración del driver de base de datos, carga una clase de prueba de ejecución de 977 bytes ya residente en el classpath y ejecuta como
uid=1000(papercut), con restauración a fábrica probada por lecturas en frío de la base de datos. - Matriz de cierre medida: 25.0.11 dispara; EPR3 25.0.12-PO-4560.76533 muere en el paso 3 de 11 (rebote 302 de la petición forjada); 25.0.13 muere en el mismo paso. Corridas el mismo día, bytes del exploit intactos y gate de cinco pilares VALID 5/5.
- El arreglo se localizó sin decompiladores: diff del override de servicio
papercut.applicationentre la rama stock y las dos parcheadas (byte idénticas entre sí) y hashes idénticos de los jars del motor Tapestry en las tres ramas. - Corroboración dentro del build arreglado: las mismas bytes de la clase PoC siguen ejecutando si se fuerzan a cargar en la rama EPR3, o sea que el arreglo cierra el camino de autorización, no el artefacto ejecutable.
- Claim gate del caso:
claims=32 checks=32 pass=32 fail=0, con las 12 páginas del paper auditadas página por página.
tú@nullsector:~$ mail miguel
Colaboraciones, charlas, prensa o investigación: escríbeme.
¿Necesitas un pentest o un análisis de vulnerabilidades? Pídelo en Xpectra.ai ↗