-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from SamuraiWTF/cors-2.0
Cors 2.0
- Loading branch information
Showing
32 changed files
with
437 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
exports.getData = (req, res) => { | ||
res.json({ | ||
theData: [{ name: 'osborn', class: 'monk'}, { name: 'dookie', class: 'barbarian'}, { name: 'fix', class: 'bard' }, { name: 'dugros', class: 'fighter'}], | ||
result: 'critical success' | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
const express = require('express') | ||
|
||
const router = express.Router(); | ||
|
||
const dummyController = require('../controllers/dummy') | ||
|
||
const cors = require('cors') | ||
|
||
function escapeRegex(string) { | ||
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); | ||
} | ||
|
||
// ex1 - missing start anchor | ||
const ex1router = express.Router({ mergeParams: true }) | ||
|
||
const ex1Policy = { | ||
origin: new RegExp(escapeRegex(process.env.CORS_CLIENT_HOST) + '$'), | ||
methods: 'GET,POST', | ||
credentials: true | ||
} | ||
|
||
ex1router.use(cors(ex1Policy)) | ||
ex1router.options('*', cors(ex1Policy)) | ||
|
||
ex1router.get('/1', dummyController.getData) | ||
|
||
// ex2 - missing end anchor | ||
const ex2router = express.Router({ mergeParams: true }) | ||
|
||
const ex2Policy = { | ||
origin: new RegExp('^https?:\\/\\/(www\\.|blog\\.)?professionallyevil.com'), | ||
methods: 'GET,POST', | ||
credentials: true | ||
} | ||
|
||
ex2router.use(cors(ex2Policy)) | ||
ex2router.options('*', cors(ex2Policy)) | ||
|
||
ex2router.get('/2', dummyController.getData) | ||
|
||
router.use(ex1router) | ||
router.use(ex2router) | ||
|
||
module.exports = router |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,48 @@ | ||
const express = require('express') | ||
const client = express() | ||
const nunjucks = require('nunjucks') | ||
|
||
client.use(express.static('client.cors.demo/static')) | ||
const app = express() | ||
const jucksEnv = new nunjucks.Environment(new nunjucks.FileSystemLoader('client.cors.demo/views')) | ||
|
||
module.exports = client | ||
const apiHost = process.env.CORS_API_HOST || 'api.cors.dem'; | ||
const protocol = stringToBool(process.env.USE_TLS) ? 'https' : 'http'; | ||
|
||
// Escape backticks - for dumping variables into template literals on the front-end. | ||
jucksEnv.addFilter("escbt", (str) => { | ||
return str.replace(/`/g, '\\`'); | ||
}); | ||
|
||
jucksEnv.express(app) | ||
app.set('view engine', 'njk') | ||
|
||
app.use(express.static('client.cors.demo/static')) | ||
|
||
app.get('/', (req, res) => { | ||
res.render('index', { apiHost: apiHost, protocol: protocol }) | ||
}) | ||
|
||
app.get('/settings', (req, res) => { | ||
res.render('settings', { apiHost: apiHost, protocol: protocol }) | ||
}) | ||
|
||
app.get('/ex/:exnum', (req, res) => { | ||
res.render(`exercises/ex${req.params.exnum}`, { apiHost: apiHost, protocol: protocol, exnum: req.params.exnum, showSolution: false }) | ||
}) | ||
|
||
app.post('/ex/:exnum', (req, res) => { | ||
res.render(`exercises/ex${req.params.exnum}`, { apiHost: apiHost, protocol: protocol, exnum: req.params.exnum, corsClientHost: process.env.CORS_CLIENT_HOST, showSolution: true }) | ||
}) | ||
|
||
module.exports = app | ||
|
||
function stringToBool(str) { | ||
let test = str.toUpperCase().trim(); | ||
if(["TRUE","Y","YES","1"].indexOf(test) > -1) { | ||
return true | ||
} else if (["FALSE","N","NO","0"].indexOf(test) > -1) { | ||
return false | ||
} else { | ||
console.error(`Invalid value in stringToBool: ${str}`) | ||
return undefined | ||
} | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>CORS Demonstrator{% block pageTitle %}{% endblock %}</title> | ||
<link rel="stylesheet" href="/css/bulma.min.css" /> | ||
</head> | ||
<body> | ||
<nav class="navbar is-dark" role="navigation" aria-label="main navigation"> | ||
<div class="navbar-brand is-primary"> | ||
<div class="navbar-item"> | ||
CORS Demo | ||
</div> | ||
</div> | ||
<div class="navbar-start"> | ||
<a href="/" class="navbar-item">Home</a> | ||
<div class="navbar-item has-dropdown is-hoverable"> | ||
<a class="navbar-link">Exercises</a> | ||
<div class="navbar-dropdown"> | ||
<a class="navbar-item" href="/ex/1"> | ||
Exercise 1 | ||
</a> | ||
<a class="navbar-item" href="/ex/2"> | ||
Exercise 2 | ||
</a> | ||
</div> | ||
</div> | ||
<div class="navbar-end"> | ||
<a href="/settings" class="navbar-item">Settings</a> | ||
</div> | ||
</nav> | ||
{% block body %}{% endblock %} | ||
<script defer src="/js/fa.all.min.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
{% extends "_base.njk" %} | ||
|
||
{% block pageTitle %} - Ex{{ exnum }}{% endblock %} | ||
|
||
{% block body %} | ||
|
||
<section class="hero is-link is-bold"> | ||
<div class="hero-body"> | ||
<div class="container"> | ||
<h1 class="title"> | ||
Musashi.js - CORS | ||
</h1> | ||
<h2 class="subtitle"> | ||
Exercise {{ exnum }} | ||
</h2> | ||
</div> | ||
</div> | ||
</section> | ||
|
||
<section class="section has-background-light"> | ||
<div class="container"> | ||
{% block instructions %} | ||
These exercises are performed by tampering with the request in your interception proxy (e.g. Burp or ZAP). Be sure to read the scenario description before for critical | ||
details, including the setup information for your starting point - including which Origins are known to be allowed, as well as possible hints. Also, make note of the goal, as not every exercise has the same success criteria. | ||
{% endblock %} | ||
</div> | ||
</section> | ||
|
||
<section class="section"> | ||
<div class="container"> | ||
<h2 class="subtitle"> | ||
Scenario | ||
</h2> | ||
<p>{% block scenario %}{% endblock %}</p> | ||
</div> | ||
</section> | ||
|
||
<section class="section"> | ||
<div class="container"> | ||
<h2 class="subtitle"> | ||
Goal | ||
</h2> | ||
<p>{% block goal %}{% endblock %}</p> | ||
<div class="field"> | ||
<div class="control"> | ||
<button class="button is-info is-rounded" onclick="sendSampleRequest(`{{ protocol | escbt }}://{{ apiHost | escbt }}/ex/{{ exnum | escbt }}`);alert('Sample request has been sent.');">Send Request</button> | ||
</div> | ||
</div> | ||
</div> | ||
</section> | ||
|
||
|
||
{% if showSolution %} | ||
<section class="hero is-warning"> | ||
<div class="container"> | ||
<h2 class="subtitle">Solution</h2> | ||
<p>{% block solution %}{% endblock %}</p> | ||
</div> | ||
</section> | ||
{% else %} | ||
<section class="section"> | ||
<form class="container" method="POST" action="/ex/{{ exnum }}"> | ||
<div class="field"> | ||
<div class="control"> | ||
<button class="button is-danger is-rounded" type="submit">Show Solution</button> | ||
</div> | ||
</div> | ||
</form> | ||
</section> | ||
{% endif %} | ||
</section> | ||
|
||
{% block sampleFunction %} | ||
<script> | ||
function sendSampleRequest(targetUrl) { | ||
fetch(targetUrl); | ||
} | ||
</script> | ||
{% endblock %} | ||
|
||
|
||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{% extends "exercises/_ex.njk" %} | ||
|
||
{% block scenario %} | ||
This API endpoint is using a regular expression to limit the calls to only those from the origin of <i>{{ corsClientHost }}</i>, and subdomains such as <i>staging.{{ corsClientHost }}</i>. | ||
However, there's a flaw in the implementation of this pattern. | ||
{% endblock %} | ||
|
||
{% block goal %} | ||
Find an origin is allowed by the <code>Access-Control-Allow-Origin</code> response header, even though it doesn't belong to this domain. | ||
{% endblock %} | ||
|
||
{% block solution %} | ||
Any origin ending in <i>{{ corsClientHost }}</i> is allowed, even <b>https://evil{{ corsClientHost }}</b>. | ||
To fix this, the pattern should require a dot or period <code>.</code> character before the domain or hostname, unless it is immediately preceded by the protocol. | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{% extends "exercises/_ex.njk" %} | ||
|
||
{% block scenario %} | ||
A regular expression is used to limit the allowed origins to just <i>professionallyevil.com</i>, <i>www.professionallyevil.com</i>, and <i>blog.professionallyevil.com</i>. | ||
There is a flaw in this regular expression. | ||
{% endblock %} | ||
|
||
{% block goal %} | ||
Find an origin is allowed by the <code>Access-Control-Allow-Origin</code> response header, even though it doesn't belong to this domain. | ||
{% endblock %} | ||
|
||
{% block solution %} | ||
This regular expression is missing the end anchor <code>$</code>, so any origin <u>starting</u> with an allowed domain will work, including <b>https://professionallyevil.com.{{ corsClientHost }}</b>. | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{% extends "exercises/_ex.njk" %} | ||
|
||
{% block scenario %} | ||
Describe the scenario | ||
{% endblock %} | ||
|
||
{% block goal %} | ||
Indicate the success condition | ||
{% endblock %} | ||
|
||
{% block solution %} | ||
This is the solution | ||
{% endblock %} | ||
|
||
{% block sampleFunction %} | ||
<script> | ||
function sendSampleRequest(targetUrl) { | ||
// write this for a custom request. Delete the whole block if you just want a fetch to the /ex/:num endpoint. | ||
} | ||
</script> | ||
{% endblock %} |
Oops, something went wrong.