[CVE-2023-2113] Vulnerabilidad en el plugin Autoptimize v3.1.6 de WordPress – Stored Cross-Site Scripting

El día de hoy el equipo de WPScan me notificó que se hacía público uno de los últimos reportes que me tocó notificar sobre una vulnerabilidad en un popular plugin de WordPress. Por tanto aprovecho la oportunidad en primer lugar para dar las gracias al equipo de WPScan la asistencia, el asesoramiento y la asignación del CVE. Os dejo con los detalles técnicos de mi reporte sobre esta vulnerabilidad.

Introducción

Autoptimize es un popular plugin de WordPress (cuenta con más de 1 millón de instalaciones activas), que permite la optimización de las aplicaciones web mediante el tratamiento de los estilos (CSS).

Descripción

Entre sus funcionalidades cuenta con un apartado llamado Critical CSS en donde se permite crear reglas para aplicar a las distintas secciones de las aplicaciones web (a continuación un ejemplo extraído de su página web de la versión pro):

Este apartado cuenta con un interesante botón que permite la subida de ficheros de configuración con un formato específico (con estructura de JSON). A continuación, el formato base:

{"ccss":{"rules":"{\"paths\":{},\"types\":{}}","additional":false,"viewport":false,"finclude":false,"rtimelimit":false,"noptimize":false,"debug":false,"key":false,"deferjquery":false,"domain":false,"forcepath":false,"loggedin":false,"rlimit":false,"unloadccss":false},"js":{"root":false,"aggregate":false,"defer_not_aggregate":false,"defer_inline":false,"exclude":false,"forcehead":false,"justhead":false,"trycatch":false,"include_inline":false},"css":{"root":false,"aggregate":false,"datauris":false,"justhead":false,"defer":false,"defer_inline":false,"inline":false,"exclude":false,"include_inline":false},"other":{"autoptimize_imgopt_settings":false,"autoptimize_extra_settings":false,"autoptimize_cache_fallback":false,"autoptimize_cache_nogzip":false,"autoptimize_cdn_url":false,"autoptimize_enable_meta_ao_settings":false,"autoptimize_enable_site_config":false,"autoptimize_html":false,"autoptimize_html_keepcomments":false,"autoptimize_minify_excluded":false,"autoptimize_optimize_checkout":false,"autoptimize_optimize_logged":false}}

Que si bien en el backend es validado y solamente es subido si el fichero cumple con una serie de requisitos de estructura, formato y valores; Se ha logrado identificar un punto de inserción de datos que no es sanitizado y que permite la inserción código HTML y JavaScript arbitrario. En este caso se debe llenar como valor de la variable paths de la siguiente manera:

\"foo\":{\"hash\":0,\"file\":\"INJECTION_HERE\"}

Ejemplo de cómo quedaría formado el fichero JSON:

Prueba de concepto (PoC)

Para reproducir esta vulnerabilidad asegúrese de seguir los siguientes pasos:

  1. Genere un fichero JSON con el contenido y formato base descrito anteriormente. Asegúrese de guardar este fichero con el nombre: settings.json (es necesario).
  2. Asegúrese de incluir la carga útil también mencionada anteriormente: \"foo\":{\"hash\":0,\"file\":\"INJECTION_HERE\"}
  3. Comprima este fichero settings.json en un fichero zip con cualquier nombre. El backend de la aplicación solo espera recibir este tipo de extensión (zip).
  4. Una vez seleccionado su fichero zip para subir, pulse sobre el botón Import Settings.
  5. Si todo ha ido de forma correcta conseguirá subir su fichero JSON con éxito y habrá conseguido insertar su payload de forma deliberada.

El resultado obtenido para esta primera inyección se verá de la siguiente manera:

A fin de poder demostrar un mayor impacto sobre este hallazgo a continuación otras inyecciones posibles:

HTML Injection

En el fichero JSON cambiaremos el valor del campo paths por la siguiente inserción y volveremos a subir el fichero zip.

\"foo\":{\"hash\":0,\"file\":\"<h1>HTML Injection</h1><img src=/wp-content/plugins/autoptimize/classes/static/loading.gif>\"}

Stored Cross-Site Scripting

Para este caso, en el fichero JSON cambiaremos el valor del campo paths por la siguiente inserción y volveremos a subir el fichero zip a la aplicación web.

\"foo\":{\"hash\":0,\"file\":\"<script>alert(`Stored XSS`)</script>\"}

Aquí la vulnerabilidad es persistente, por lo que puede abandonar esta sección y volver más tarde y el payload se seguirá ejecutando.

Timeline

  • 2023/04/13: Toma de contacto y revisión de código.
  • 2023/04/14: Vulnerabilidad descubierta.
  • 2023/04/14: PoC y documentación del hallazgo.
  • 2023/04/15: Notificación de la vulnerabilidad al equipo de WPScan.
  • 2023/04/17: Asignación del CVE por parte del equipo de WPScan.
  • 2023/04/25: Liberación de la versión corregida del plugin (v3.1.7).
  • 2023/05/02: Publicación de la vulnerabilidad.

Referencias: