Investigación de seguridad sobre Liferay CE 7.0.3 GA4: RCE pre-autenticación como root (clase CVE-2020-7961) reproducido de extremo a extremo, más 16 hallazgos adicionales — 8+ sin CVE conocido. Caza en bucle con agentes: 25 generadores, 22 jueces, 9 validadores en vivo en Docker. Rastro de evidencia + verificador de un solo paso incluido.
Una auditoría de seguridad de Liferay Portal CE 7.0.3 GA4 (git tag 7.0.3-ga4, commit
b2d7cc68a) realizada con la metodología RAPTOR loop-hunt:
reconocimiento determinista → 25 agentes generadores aislados leyendo el código fuente crudo → 22 agentes jueces
independientes refutando desde el código crudo → 9 validadores en vivo atacando una instancia GA4 real en Docker.
Titular: RCE no autenticado como
rootreproducido de extremo a extremo (clase CVE-2020-7961), más otras 8 vulnerabilidades verificadas en vivo — varias de ellas sin CVE conocido.
⚠️ Legal/ético: todo esto apunta a una instancia de prueba autoalojada. Liferay CE 7.0 está al final de su vida útil (última versión 7.0.6 GA7, 2018); estos problemas no tienen parche aguas arriba. Usa este material solo contra sistemas que poseas o para los que tengas autorización explícita de prueba.
Estado: ✅ verificado en vivo contra la instancia GA4 en Docker · 🔬 confirmado por código (un juez independiente re-derivó el rastro completo desde el código fuente crudo) · 🧪 requiere config/condicionado por configuración.
| ID | Hallazgo | Severidad | Auth | Estado | Evidencia |
|---|---|---|---|---|---|
| F-1 | Sobrescritura de tipo JSONWS → instanciación arbitraria de clases + setters → RCE como root (c3p0 HexAsciiSerializedMap → ObjectInputStream → escritura de archivo AspectJWeaver → JSP) | Crítica | ninguna | ✅ | verified/f1-jsonws-deser-rce.md |
| F-2 | Pista javaClass de jabsorb en /poller/* → instanciación arbitraria de clases + inyección de campos, antes de la validación de userId | Alta (potencial) | cualquier cuenta (auto-registro activado por defecto) | ✅ sumidero / brazo RCE abierto | verified/F-2-poller.md |
| F-4 | XML-RPC pingback.ping busca antes de validar → SSRF ciego + oráculo de puertos interno (alcanzó la shell Gogo en 127.0.0.1:11311) | Media | ninguna | ✅ | verified/f4-xmlrpc-pingback-ssrf.md |
| F-5 | IDOR de versionId en SyncDownloadServlet → leer cualquier versión de archivo de DL (cross-site, sin comprobación de VIEW sobre el objeto transmitido) | Alta | ninguna (vía "tramo" visible para invitados) | ✅ | verified/F-5.md |
| F-6 | El motor de plantillas XSL ignora el sandboxing (secureProcessing=false, restricted descartado) → SSRF con document() y ejecución de comandos rt:exec de XSLTC | Crítica | autor de plantillas del sitio | ✅ | verified/F-6-F-7-template-engines.md |
| F-7 | Las plantillas restringidas de Velocity y FreeMarker exponen propsUtil / saxReaderUtil sin procesar → divulgación de propiedades del portal + file:// a invitados | Alta | autor de plantillas | ✅ | verified/F-6-F-7-template-engines.md |
| F-8 | IDOR de la tabla Image_ vía /image/*?img_id=N — sin token, comprobaciones limitadas por prefijo eludidas al intercambiar el prefijo, ids secuenciales enumerables | Media | ninguna | ✅ | verified/f-8-image-idor.md |
| F-11 | SimpleCaptcha = PIN de 4 dígitos, nunca se invalida con intentos fallidos, el contador de invitados nunca se incrementa → ruptura en ~5k peticiones | Media | ninguna | ✅ | verified/f11-f12-captcha-reminder.md |
| F-12 | Olvido de contraseña: enumeración de usuarios + oráculo de respuesta del recordatorio sin captcha (bypass con sesión nueva); una respuesta vacía genera un ticket de reseteo real para cuentas sin pregunta de seguridad | Media-Alta | ninguna | ✅ | verified/f11-f12-captcha-reminder.md |
| F-13 | Anulación de parámetros de petición en Web Content Display (groupId/articleId/ddmTemplateKey) → lectura cross-site de artículos no destinados a invitados (journal.article.view.permission.check.enabled=false por defecto) | Alta | ninguna (se necesita un WCD en una página de invitados) | ✅ | verified/F-13-wcd-param-override.md |
| F-3 | El axis-extender de OSGi se salta ServiceAccessPolicy / el marcado de acceso remoto en los servicios SOAP de módulos | Media (Alta con módulo WSDD) | ninguna | 🔬 | judge/axis-spring-remoting.md |
| F-9 | OpenID vincula la cuenta de la víctima al OpenID del atacante antes de la verificación de la aserción → toma de control de la cuenta | Alta | ninguna (OpenID activado, no por defecto) | 🔬 🧪 | judge/sso-autologin.md |
| F-10 | readObject de TunnelServlet protegido solo por una lista negra de clases; gadgets ROME/JdbcRowSetImpl/c3p0/AspectJWeaver en el classpath | Potencial crítico | peer de confianza (secreto compartido + host permitido) | ✅ las barreras se mantienen pre-autenticación | verified/f10-f20-tunnel-auth-pipeline.md |
| F-14 | TokenAutoLogin confía en una cabecera SM_USER sin más (sin verificación, sin lista blanca de IPs) | Media | ninguna (token SSO activado, no por defecto) | 🔬 🧪 | judge/sso-autologin.md |
| F-15 | La importación LAR de un administrador del sitio cuela RolesAdminPortletDataHandler → eliminación masiva de roles de empresa / borrado de permisos | Media | administrador del sitio | 🔬 | judge/export-import-lar.md |
| F-16 | OpenSocial (no está en el bundle por defecto): SSRF makeRequest pre-autenticación, JS de origen /gadgets/ifr, tokens de seguridad falsificables → suplantación, XSS almacenado | Alta ×4 | ninguna / miembro del sitio | 🔬 (condicional al despliegue) | judge/opensocial-shindig.md |
| F-17 | WSRP (no está en el bundle por defecto): SSRF ProxyServlet pre-autenticación; endpoint de markup → renderizado arbitrario de portlets + persistencia de typeSettings de layout | Media | ninguna | 🔬 (condicional al despliegue) | judge/wsrp.md |
Lista completa curada, incluidos los rechazos: FINDINGS.md · informe narrativo: REPORT.md