Vulnerabilidad de Inyección de Contenido en WordPress

Como parte de un proyecto de investigación de vulnerabilidad para de Firewall Sucuri (WAF), Sucuri ha auditado múltiples proyectos de código abierto buscando problemas de seguridad. Mientras trabajábamos en WordPress, descubrimos una vulnerabilidad grave de inyección de contenido (escalamiento de privilegios) que afecta a la API REST. Esta vulnerabilidad permite a un usuario no autenticado modificar el contenido de cualquier post o página de un sitio web de WordPress.

Desvelamos la vulnerabilidad al equipo de seguridad de WordPress que lo manejó muy bien. Ellos trabajaron estrechamente con nosotros para coordinar la cronología de la divulgación y decirlo a muchos hosts y proveedores de seguridad para que parcheasen antes de la divulgación de la vulnerabilidad.

Una solución para esto se incluyó silenciosamente en la versión 4.7.2 junto con otros parches para problemas menos graves. Esto fue hecho intencionalmente para dar a todos el tiempo de parchear. Ahora estamos revelando los detalles porque creemos que ha habido suficiente tiempo para que la mayoría de los usuarios de WordPress actualizasen sus sitios web.

¿Está en Riesgo?

Esta vulnerabilidad de escalado de privilegios afecta al WordPress REST API que se agregó recientemente y se habilitó por defecto en WordPress 4.7.0.

Uno de estos endpoints del REST permite el acceso (a través de la API) para ver, editar, eliminar y crear posts. Dentro de este endpoint, un error sutil permite a los visitantes editar cualquier post en el sitio web.

La REST API está habilitada de forma predeterminada en todos los sitios web que utilizan el WordPress 4.7.0 or 4.7.1. Si su sitio web está en estas versiones de WordPress entonces está actualmente vulnerable a este bug.

Detalles Técnicos

Todo empieza con el ./wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

Hay que notar que la ruta registrada está diseñada para rellenar el parámetro de solicitud ID con dígitos. Por ejemplo, si envía una solicitud a /wp-json/wp/v2/posts/1234 el parámetro ID se establecerá en 1234.

Este comportamiento por sí solo podría ser una buena manera de evitar que los atacantes creen valores ID maliciosos, pero al ver cómo la API REST gestiona el acceso, descubrimos rápidamente que prioriza los valores $_GET y $_POST sobre los generados por la expresión regular de la ruta. Esto hace posible que un atacante envíe una solicitud como /wp-json/wp/v2/posts/1234?id=12345helloworld que asignaría 12345helloworld al parámetro id – que ahora contiene más que sólo dígitos.

Al investigar más a fondo, hemos visto las diferentes callbacks (en la captura de pantalla) y una de ellas nos llamó la atención: el update_item y su método de verificación de permisos update_item_permissions_check.

En resumen, transmite nuestro valor alfanumérico ID directamente a la función get_post() . Esta función valida la solicitud comprobando si el post realmente existesi nuestro usuario tiene permiso para editar este post. Hemos descubierto que ello es una manera curiosa de sanear la petición. Si enviamos una ID que no tiene una publicación correspondiente, podemos pasar la comprobación de permisos y permitirle continuar las solicitudes de ejecución al método update_item!

Curioso acerca de lo que podría provocar el fallo del get_post() para encontrar un post (aparte de una ID inexistente), nos dimos cuenta de que utilizaba el método estático en get_instance() para obtener posts en wp_posts .

Como se puede ver en el código, eso básicamente fallaría en cualquier input que no sea de caracteres numéricos, de modo que 123ABC iba a fallar.

Para un atacante esto significa que WordPress, pensando que se trata un usuario con suficientes privilegios para editar este post, podría ejecutar el método update_item.

Vale comprobar lo que hace este método.

Hay un detalle muy sutil, pero muy importante en la última captura de pantalla: WordPress lanza el parámetro ID a un integer antes de pasarlo get_post.

Este es un problema debido a la forma en que PHP escribe comparaciones y conversiones. Por ejemplo, se puede ver que el siguiente fragmento tendría como resultado 123:

Esto conduce a una situación muy peligrosa donde un atacante podría presentar una solicitud como /wp-json/wp/v2/posts/123?id=456ABC para cambiar un post cuya ID sea 456.

Debido a este tipo de malabares, es posible que un atacante cambie el contenido de cualquier post o página en el sitio web de la víctima. A partir de ahí, pueden agregar shortcodes específicos de plugins para explotar vulnerabilidades (que de otro modo estarían restringidas a roles de contribuyentes), infectar el contenido del sitio web con una campaña de spam de SEO, inyectar anuncios, etc.

Dependiendo de los plugins habilitados en el sitio web, incluso el código PHP se podría ejecutar muy fácilmente.

Conclusión

Si no ha activado las actualizaciones automáticas en su sitio web, actualice lo antes posible.

Esta es una vulnerabilidad seria que puede ser utilizada con fines maliciosos de diferentes maneras para comprometer un sitio web vulnerable. Actualice pronto.