Skip to content

Commit

Permalink
challenge testability
Browse files Browse the repository at this point in the history
 - added 'name' column
 - added spec for shared expectations
 - added test for reflected XSS
  • Loading branch information
bkimminich committed Oct 27, 2014
1 parent 70f414c commit c009505
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 4 deletions.
4 changes: 2 additions & 2 deletions app/views/ScoreBoard.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ <h3 class="page-header page-header-sm">Score Board</h3>
<tr data-ng-repeat="challenge in challenges">
<td><div ng-bind-html="challenge.description"></div></td>
<td>
<svg ng-show="!challenge.solved" xmlns="http:https://www.w3.org/2000/svg" width="102" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="102" height="18" fill="#555"/><rect rx="4" x="64" width="38" height="18" fill="#e05d44"/><path fill="#e05d44" d="M64 0h4v18h-4z"/><rect rx="4" width="102" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="33" y="14" fill="#010101" fill-opacity=".3">challenge</text><text x="33" y="13">challenge</text><text x="82" y="14" fill="#010101" fill-opacity=".3">open</text><text x="82" y="13">open</text></g></svg>
<svg ng-show="challenge.solved" xmlns="http:https://www.w3.org/2000/svg" width="111" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="111" height="18" fill="#555"/><rect rx="4" x="64" width="47" height="18" fill="#4c1"/><path fill="#4c1" d="M64 0h4v18h-4z"/><rect rx="4" width="111" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="33" y="14" fill="#010101" fill-opacity=".3">challenge</text><text x="33" y="13">challenge</text><text x="86.5" y="14" fill="#010101" fill-opacity=".3">solved</text><text x="86.5" y="13">solved</text></g></svg>
<svg id="{{challenge.name}}.notSolved" ng-show="!challenge.solved" xmlns="http:https://www.w3.org/2000/svg" width="102" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="102" height="18" fill="#555"/><rect rx="4" x="64" width="38" height="18" fill="#e05d44"/><path fill="#e05d44" d="M64 0h4v18h-4z"/><rect rx="4" width="102" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="33" y="14" fill="#010101" fill-opacity=".3">challenge</text><text x="33" y="13">challenge</text><text x="82" y="14" fill="#010101" fill-opacity=".3">open</text><text x="82" y="13">open</text></g></svg>
<svg id="{{challenge.name}}.solved" ng-show="challenge.solved" xmlns="http:https://www.w3.org/2000/svg" width="111" height="18"><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-opacity=".3"/><stop offset="1" stop-opacity=".5"/></linearGradient><rect rx="4" width="111" height="18" fill="#555"/><rect rx="4" x="64" width="47" height="18" fill="#4c1"/><path fill="#4c1" d="M64 0h4v18h-4z"/><rect rx="4" width="111" height="18" fill="url(#a)"/><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"><text x="33" y="14" fill="#010101" fill-opacity=".3">challenge</text><text x="33" y="13">challenge</text><text x="86.5" y="14" fill="#010101" fill-opacity=".3">solved</text><text x="86.5" y="13">solved</text></g></svg>
</td>
</tr>
</table>
Expand Down
23 changes: 23 additions & 0 deletions lib/datacreator.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,138 +17,161 @@ module.exports = function() {

function createChallenges() {
models.Challenge.create({
name: 'scoreBoard',
description: 'Find the carefully hidden \'Score Board\' page.',
solved: false
}).success(function (challenge) {
challenges.scoreBoardChallenge = challenge;
});
models.Challenge.create({
name: 'errorHandling',
description: 'Provoke an error that is not very gracefully handled.',
solved: false
}).success(function (challenge) {
challenges.errorHandlingChallenge = challenge;
});
models.Challenge.create({
name: 'loginAdmin',
description: 'Log in with the administrator\'s user account.',
solved: false
}).success(function (challenge) {
challenges.loginAdminChallenge = challenge;
});
models.Challenge.create({
name: 'loginJim',
description: 'Log in with Jim\'s user account.',
solved: false
}).success(function (challenge) {
challenges.loginJimChallenge = challenge;
});
models.Challenge.create({
name: 'loginBender',
description: 'Log in with Bender\'s user account.',
solved: false
}).success(function (challenge) {
challenges.loginBenderChallenge = challenge;
});
models.Challenge.create({
name: 'xss1',
description: 'XSS Tier 1: Perform a <i>reflected</i> XSS attack with &lt;script&gt;alert("XSS1")&lt;/script&gt;.',
solved: false
}).success(function (challenge) {
challenges.localXssChallenge = challenge;
});
models.Challenge.create({
name: 'xss2',
description: 'XSS Tier 2: Perform a <i>persisted</i> XSS attack with &lt;script&gt;alert("XSS2")&lt;/script&gt; bypassing a <i>client-side</i> security mechanism.',
solved: false
}).success(function (challenge) {
challenges.persistedXssChallengeUser = challenge;
});
models.Challenge.create({
name: 'xss3',
description: 'XSS Tier 3: Perform a <i>persisted</i> XSS attack with &lt;script&gt;alert("XSS3")&lt;/script&gt; bypassing a <i>server-side</i> security mechanism.',
solved: false
}).success(function (challenge) {
challenges.persistedXssChallengeFeedback = challenge;
});
models.Challenge.create({
name: 'xss4',
description: 'XSS Tier 4: Perform a <i>persisted</i> XSS attack with &lt;script&gt;alert("XSS4")&lt;/script&gt; without using the frontend application at all.',
solved: false
}).success(function (challenge) {
challenges.restfulXssChallenge = challenge;
});
models.Challenge.create({
name: 'unionSqlI',
description: 'Retrieve a list of all user credentials via SQL Injection',
solved: false
}).success(function (challenge) {
challenges.unionSqlInjectionChallenge = challenge;
});
models.Challenge.create({
name: 'adminCredentials',
description: 'Log in with the administrator\'s user credentials without previously changing them or applying SQL Injection.',
solved: false
}).success(function (challenge) {
challenges.weakPasswordChallenge = challenge;
});
models.Challenge.create({
name: 'fiveStarFeedback',
description: 'Get rid of all 5-star customer feedback.',
solved: false
}).success(function (challenge) {
challenges.feedbackChallenge = challenge;
});
models.Challenge.create({
name: 'forgedFeedback',
description: 'Post some feedback in another users name.',
solved: false
}).success(function (challenge) {
challenges.forgedFeedbackChallenge = challenge;
});
models.Challenge.create({
name: 'redirect',
description: 'Wherever you go, there you are.',
solved: false
}).success(function (challenge) {
challenges.redirectChallenge = challenge;
});
models.Challenge.create({
name: 'accessBasket',
description: 'Access someone else\'s basket.',
solved: false
}).success(function (challenge) {
challenges.basketChallenge = challenge;
});
models.Challenge.create({
name: 'negativeOrder',
description: 'Place an order that makes you rich.',
solved: false
}).success(function (challenge) {
challenges.negativeOrderChallenge = challenge;
});
models.Challenge.create({
name: 'confidentialDocument',
description: 'Access a confidential document.',
solved: false
}).success(function (challenge) {
challenges.directoryListingChallenge = challenge;
});
models.Challenge.create({
name: 'adminSection',
description: 'Access the administration section of the store.',
solved: false
}).success(function (challenge) {
challenges.adminSectionChallenge = challenge;
});
models.Challenge.create({
name: 'csrf',
description: 'Change Bender\'s password into <i>slurmCl4ssic</i>.',
solved: false
}).success(function (challenge) {
challenges.csrfChallenge = challenge;
});
models.Challenge.create({
name: 'changeProduct',
description: 'Change the link in the description of the <a href="/#/search?q=O-Saft">O-Saft product</a> to <i>http:https://kimminich.de</i>.',
solved: false
}).success(function (challenge) {
challenges.changeProductChallenge = challenge;
});
models.Challenge.create({
name: 'vulnerableComponent',
description: '<a href="/#/contact">Inform the shop</a> about a vulnerable library it is using. (Mention the exact library name and version in your complaint.)',
solved: false
}).success(function (challenge) {
challenges.knownVulnerableComponentChallenge = challenge;
});
models.Challenge.create({
name: 'easterEgg1',
description: 'Find the hidden <a href="http:https://en.wikipedia.org/wiki/Easter_egg_(media)" target="_blank">easter egg</a>.',
solved: false
}).success(function (challenge) {
challenges.easterEggLevelOneChallenge = challenge;
});
models.Challenge.create({
name: 'easterEgg2',
description: 'Apply some advanced cryptanalysis to find <i>the real</i> easter egg.',
solved: false
}).success(function (challenge) {
Expand Down
1 change: 1 addition & 0 deletions models/challenge.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

module.exports = function (sequelize, DataTypes) {
var Challenge = sequelize.define('Challenge', {
name: DataTypes.STRING,
description: DataTypes.STRING,
solved: DataTypes.BOOLEAN
});
Expand Down
1 change: 1 addition & 0 deletions protractor.conf.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/*jslint node: true */
exports.config = {
allScriptsTimeout: 11000,

Expand Down
18 changes: 18 additions & 0 deletions test/e2e/_sharedExpectationsSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
protractor.expect = {
challengeSolved: function (context) {
describe("challenge", function () {
var challenge;

beforeEach(function () {
challenge = context.challenge;
browser.get('/#/score-board');
});

it("should be solved on score board", function () {
expect(element(by.id(challenge + '.solved')).getAttribute('class')).not.toMatch('ng-hide');
expect(element(by.id(challenge + '.notSolved')).getAttribute('class')).toMatch('ng-hide');
});

});
}
}
7 changes: 5 additions & 2 deletions test/e2e/searchSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('search', function () {
expect(productDescriptions.first().getText()).toMatch(/hand-picked/);
});

it('search query should be susceptible to XSS attacks', function () {
it('search query should be susceptible to reflected XSS attacks', function () {
element(by.model('searchQuery')).sendKeys('<script>alert("XSS1")</script>');

element(by.id('searchButton')).click();
Expand All @@ -39,6 +39,9 @@ describe('search', function () {
expect(alert.getText()).toEqual('XSS1');
alert.accept();
});

});

});
protractor.expect.challengeSolved({challenge: 'xss1'});

});
3 changes: 3 additions & 0 deletions test/server/challengeApiSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ frisby.create('GET all challenges ')
.expectHeaderContains('content-type', 'application/json')
.expectJSONTypes('data.*', {
id: Number,
name: String,
description: String,
solved: Boolean
})
Expand All @@ -27,6 +28,7 @@ frisby.create('GET existing challenge by id is forbidden via public API even whe
frisby.create('POST new challenge is forbidden via public API even when authenticated')
.addHeaders(authHeader)
.post(API_URL + '/Challenges', {
name: 'Invulnerability',
description: 'I am not a vulnerability!',
solved: false
})
Expand All @@ -36,6 +38,7 @@ frisby.create('POST new challenge is forbidden via public API even when authenti
frisby.create('PUT update existing challenge is forbidden via public API even when authenticated')
.addHeaders(authHeader)
.put(API_URL + '/Challenges/1', {
name: 'Vulnerability',
description: "I am a vulnerability!!!",
rating: 1
})
Expand Down

0 comments on commit c009505

Please sign in to comment.