Skip to content

Commit

Permalink
- Fixed all absolute paths I could find
Browse files Browse the repository at this point in the history
- Fixed SSTI test, which failed because it didnÄt trigger the serverside scoring
- Fixed timing issues in registerSpec and contactSpec, where the XSS didn't work if the browser was too fast
- Added code way to simulate a proxy environment ina  subfolder. Run via "node test/e2eSubfolder.js"
- Added e2e test for subfolder. Run via "npm run e2e -- subfolder"
- Added e2e test for subfolder to travis

Signed-off-by: JamesCullum <JamesCullum@users.noreply.github.com>
  • Loading branch information
JamesCullum committed Mar 26, 2020
1 parent e74095d commit 1cba547
Show file tree
Hide file tree
Showing 43 changed files with 271 additions and 162 deletions.
8 changes: 7 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,13 @@ jobs:
os: linux
script:
- export NODE_ENV=test
- npm run protractor
- npm run e2e
- stage: e2e
if: tag IS blank
os: linux
script:
- export NODE_ENV=test
- npm run e2e -- subfolder
- stage: smoke
if: tag IS blank
os: linux
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/Services/socket-io.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export class SocketIoService {
constructor (private ngZone: NgZone) {
this.ngZone.runOutsideAngular(() => {
if (environment.hostServer === '.') {
this._socket = this.io.connect(window.location.href, {
path: (window.location.pathname === '/' ? '/' : window.location.pathname + '/') + 'socket.io'
this._socket = this.io.connect(window.location.origin, {
path: (window.location.pathname.endsWith('/') ? window.location.pathname : window.location.pathname + '/') + 'socket.io'
})
} else {
this._socket = this.io.connect(environment.hostServer)
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/app/payment/payment.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,16 @@
<i style="margin-left: 3px;" class="fas fa-thumbs-up confirmation"></i>)
</small>
<div class="button-container" style="margin-top: 6px;">
<a href="/redirect?to=http://shop.spreadshirt.com/juiceshop">
<a href="./redirect?to=http://shop.spreadshirt.com/juiceshop">
<button mat-stroked-button><i class="fas fa-tshirt fa-lg"></i> Spreadshirt (US)</button>
</a>
<a href="/redirect?to=http://shop.spreadshirt.de/juiceshop">
<a href="./redirect?to=http://shop.spreadshirt.de/juiceshop">
<button mat-stroked-button><i class="fas fa-tshirt fa-lg"></i> Spreadshirt (DE)</button>
</a>
<a href="/redirect?to=https://www.stickeryou.com/products/owasp-juice-shop/794">
<a href="./redirect?to=https://www.stickeryou.com/products/owasp-juice-shop/794">
<button mat-stroked-button><i class="fas fa-sticky-note fa-lg"></i> StickerYou</button>
</a>
<a href="/redirect?to=http://leanpub.com/juice-shop">
<a href="./redirect?to=http://leanpub.com/juice-shop">
<button mat-stroked-button><i class="fab fa-leanpub fa-lg"></i> Leanpub</button>
</a>
</div>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/app/payment/payment.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ describe('PaymentComponent', () => {
const data = {
data: {
data: 'bitcoin:1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
url: '/redirect?to=https://blockchain.info/address/1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
url: './redirect?to=https://blockchain.info/address/1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
address: '1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
title: 'TITLE_BITCOIN_ADDRESS'
}
Expand All @@ -239,7 +239,7 @@ describe('PaymentComponent', () => {
const data = {
data: {
data: 'dash:Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW',
url: '/redirect?to=https://explorer.dash.org/address/Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW',
url: './redirect?to=https://explorer.dash.org/address/Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW',
address: 'Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW',
title: 'TITLE_DASH_ADDRESS'
}
Expand All @@ -252,7 +252,7 @@ describe('PaymentComponent', () => {
const data = {
data: {
data: '0x0f933ab9fCAAA782D0279C300D73750e1311EAE6',
url: '/redirect?to=https://etherscan.io/address/0x0f933ab9fcaaa782d0279c300d73750e1311eae6',
url: './redirect?to=https://etherscan.io/address/0x0f933ab9fcaaa782d0279c300d73750e1311eae6',
address: '0x0f933ab9fCAAA782D0279C300D73750e1311EAE6',
title: 'TITLE_ETHER_ADDRESS'
}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/app/payment/payment.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ export class PaymentComponent implements OnInit {
this.dialog.open(QrCodeComponent, {
data: {
data: 'bitcoin:1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
url: '/redirect?to=https://blockchain.info/address/1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
url: './redirect?to=https://blockchain.info/address/1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
address: '1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
title: 'TITLE_BITCOIN_ADDRESS'
}
Expand All @@ -226,7 +226,7 @@ export class PaymentComponent implements OnInit {
this.dialog.open(QrCodeComponent, {
data: {
data: 'dash:Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW',
url: '/redirect?to=https://explorer.dash.org/address/Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW',
url: './redirect?to=https://explorer.dash.org/address/Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW',
address: 'Xr556RzuwX6hg5EGpkybbv5RanJoZN17kW',
title: 'TITLE_DASH_ADDRESS'
}
Expand All @@ -237,7 +237,7 @@ export class PaymentComponent implements OnInit {
this.dialog.open(QrCodeComponent, {
data: {
data: '0x0f933ab9fCAAA782D0279C300D73750e1311EAE6',
url: '/redirect?to=https://etherscan.io/address/0x0f933ab9fcaaa782d0279c300d73750e1311eae6',
url: './redirect?to=https://etherscan.io/address/0x0f933ab9fcaaa782d0279c300d73750e1311eae6',
address: '0x0f933ab9fCAAA782D0279C300D73750e1311EAE6',
title: 'TITLE_ETHER_ADDRESS'
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/sidenav/sidenav.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ <h3 mat-subheader class="side-subHeader" translate>COMPANY</h3>
</span>
</a>

<a *ngIf="showGitHubLink" mat-list-item href="/redirect?to=https://github.com/bkimminich/juice-shop"
<a *ngIf="showGitHubLink" mat-list-item href="./redirect?to=https://github.com/bkimminich/juice-shop"
aria-label="Go to OWASP Juice Shop GitHub page">
<mat-icon matListIcon class="fab fa-github fa-lg"></mat-icon>
<span class="menu-text truncate">
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/token-sale/token-sale.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ <h5><i class='fas fa-comments fa-2x'></i> <span style="margin-left: 10px;" [inne

</div>

<img src="/assets/public/images/padding/56px.png"/>
<img src="assets/public/images/padding/56px.png"/>
</div>


28 changes: 14 additions & 14 deletions frontend/src/assets/private/threejs-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
<html>
<head>
<title>Welcome to Planet Orangeuze</title>
<script src="/assets/private/three.js"></script>
<script src="/assets/private/OrbitControls.js"></script>
<script src="/assets/private/dat.gui.min.js"></script>
<script src="/assets/private/stats.min.js"></script>
<script src="/assets/private/EffectComposer.js"></script>
<script src="/assets/private/RenderPass.js"></script>
<script src="/assets/private/CopyShader.js"></script>
<script src="/assets/private/ShaderPass.js"></script>
<script src="/assets/private/MaskPass.js"></script>
<script src="assets/private/three.js"></script>
<script src="assets/private/OrbitControls.js"></script>
<script src="assets/private/dat.gui.min.js"></script>
<script src="assets/private/stats.min.js"></script>
<script src="assets/private/EffectComposer.js"></script>
<script src="assets/private/RenderPass.js"></script>
<script src="assets/private/CopyShader.js"></script>
<script src="assets/private/ShaderPass.js"></script>
<script src="assets/private/MaskPass.js"></script>
<style>
body {
margin: 0;
Expand Down Expand Up @@ -86,7 +86,7 @@
cameraBG.position.z = 50;
sceneBG = new THREE.Scene();

var materialColor = new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("/assets/private/starry_background.jpg"), depthTest: false });
var materialColor = new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture("assets/private/starry_background.jpg"), depthTest: false });
var bgPlane = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), materialColor);
bgPlane.position.z = -100;
bgPlane.scale.set(window.innerWidth * 2, window.innerHeight * 2, 1);
Expand All @@ -110,9 +110,9 @@


function createOrangeMaterial() {
var orangeTexture = THREE.ImageUtils.loadTexture("/assets/private/orangemap2k.jpg");
var specularMap = THREE.ImageUtils.loadTexture("/assets/private/earthspec4k.jpg");
var normalMap = THREE.ImageUtils.loadTexture("/assets/private/earth_normalmap_flat4k.jpg");
var orangeTexture = THREE.ImageUtils.loadTexture("assets/private/orangemap2k.jpg");
var specularMap = THREE.ImageUtils.loadTexture("assets/private/earthspec4k.jpg");
var normalMap = THREE.ImageUtils.loadTexture("assets/private/earth_normalmap_flat4k.jpg");

var orangeMaterial = new THREE.MeshPhongMaterial();
orangeMaterial.map = orangeTexture;
Expand All @@ -127,7 +127,7 @@
}

function createCloudMaterial() {
var cloudTexture = THREE.ImageUtils.loadTexture("/assets/private/fair_clouds_4k.png");
var cloudTexture = THREE.ImageUtils.loadTexture("assets/private/fair_clouds_4k.png");

var cloudMaterial = new THREE.MeshPhongMaterial();
cloudMaterial.map = cloudTexture;
Expand Down
2 changes: 1 addition & 1 deletion lib/startup/customizeEasterEgg.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const customizeEasterEgg = () => {
}

const replaceImagePath = (overlay) => {
const textureDeclaration = 'orangeTexture = THREE.ImageUtils.loadTexture("/assets/private/' + overlay + '");'
const textureDeclaration = 'orangeTexture = THREE.ImageUtils.loadTexture("assets/private/' + overlay + '");'
replace({
regex: /orangeTexture = .*;/,
replacement: textureDeclaration,
Expand Down
2 changes: 1 addition & 1 deletion lib/startup/registerWebsocketEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const registerWebsocketEvents = (server) => {
})

socket.on('verifySvgInjectionChallenge', data => {
utils.solveIf(challenges.svgInjectionChallenge, () => { return data && data.match(/.*\.\.\/\.\.\/\.\.\/\.\.\/redirect\?to=https?:\/\/placekitten.com\/(g\/)?[\d]+\/[\d]+.*/) && insecurity.isRedirectAllowed(data) })
utils.solveIf(challenges.svgInjectionChallenge, () => { return data && data.match(/.*\.\.\/\.\.\/\.\.\/\.\.[\w/-]*?\/redirect\?to=https?:\/\/placekitten.com\/(g\/)?[\d]+\/[\d]+.*/) && insecurity.isRedirectAllowed(data) })
})
})
}
Expand Down
9 changes: 7 additions & 2 deletions protractor.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* SPDX-License-Identifier: MIT
*/

const url = require('url')

let proxy = {
proxyType: 'autodetect'
}
Expand Down Expand Up @@ -47,13 +49,16 @@ exports.config = {
savePath: 'build/reports/e2e_results'
}))

let basePath = (new url.URL(browser.baseUrl)).pathname
if (basePath === '/') basePath = ''

// Get all banners out of the way
browser.get('/#')
browser.get(basePath + '/#')
browser.manage().addCookie({ name: 'cookieconsent_status', value: 'dismiss' })
browser.manage().addCookie({ name: 'welcomebanner_status', value: 'dismiss' })

// Ensure score board shows all challenges (by default only 1-star challenges are shown)
browser.get('/#/score-board')
browser.get(basePath + '/#/score-board')
element(by.id('btnToggleAllDifficulties')).click()
}
}
Expand Down
9 changes: 9 additions & 0 deletions protractor.subfolder.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright (c) 2014-2020 Bjoern Kimminich.
* SPDX-License-Identifier: MIT
*/

const protractorConfig = require('./protractor.conf.js').config

protractorConfig.baseUrl = 'http://localhost:3001/subfolder'
exports.config = protractorConfig
4 changes: 2 additions & 2 deletions routes/profileImageFileUpload.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ module.exports = function fileUpload () {
}).catch(error => {
next(error)
})
res.location('/profile')
res.redirect('/profile')
res.location((process.env.basePath || '') + '/profile')
res.redirect((process.env.basePath || '') + '/profile')
} else {
next(new Error('Blocked illegal activity by ' + req.connection.remoteAddress))
}
Expand Down
4 changes: 2 additions & 2 deletions routes/profileImageUrlUpload.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ module.exports = function profileImageUrlUpload () {
next(new Error('Blocked illegal activity by ' + req.connection.remoteAddress))
}
}
res.location('/profile')
res.redirect('/profile')
res.location((process.env.basePath || '') + '/profile')
res.redirect((process.env.basePath || '') + '/profile')
}
}
4 changes: 2 additions & 2 deletions routes/updateUserProfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module.exports = function updateUserProfile () {
} else {
next(new Error('Blocked illegal activity by ' + req.connection.remoteAddress))
}
res.location('/profile')
res.redirect('/profile')
res.location((process.env.basePath || '') + '/profile')
res.redirect((process.env.basePath || '') + '/profile')
}
}
14 changes: 13 additions & 1 deletion server.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,19 @@ const serveIndexMiddleware = (req, res, next) => {
const origEnd = res.end
res.end = function () {
if (arguments.length) {
arguments[0] = arguments[0].replace(/a href="\/([^"]+?)"/, 'a href="$1"')
const reqPath = req.originalUrl.replace(/\?.*$/, '')
const currentFolder = reqPath.split('/').pop()
arguments[0] = arguments[0].replace(/a href="([^"]+?)"/gi, function (matchString, matchedUrl) {
let relativePath = path.relative(reqPath, matchedUrl)
if (relativePath === '') {
relativePath = currentFolder
} else if (!relativePath.startsWith('.') && currentFolder !== '') {
relativePath = currentFolder + '/' + relativePath
} else {
relativePath = relativePath.replace('..', '.')
}
return 'a href="' + relativePath + '"'
})
}
origEnd.apply(this, arguments)
}
Expand Down
9 changes: 7 additions & 2 deletions test/e2e/_sharedSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@
*/

const otplib = require('otplib')
const url = require('url')

let basePath = (new url.URL(browser.baseUrl)).pathname
if (basePath === '/') basePath = ''
protractor.basePath = basePath

protractor.expect = {
challengeSolved: function (context) {
describe('(shared)', () => {
beforeEach(() => {
browser.get('/#/score-board')
browser.get(protractor.basePath + '/#/score-board')
})

it("challenge '" + context.challenge + "' should be solved on score board", () => {
Expand All @@ -24,7 +29,7 @@ protractor.beforeEach = {
login: function (context) {
describe('(shared)', () => {
beforeEach(() => {
browser.get('/#/login')
browser.get(protractor.basePath + '/#/login')

element(by.id('email')).sendKeys(context.email)
element(by.id('password')).sendKeys(context.password)
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/administrationSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('/#/administration', () => {
protractor.beforeEach.login({ email: 'admin@' + config.get('application.domain'), password: 'admin123' })

it('should be possible to access administration section with admin user', () => {
browser.get('/#/administration')
browser.get(protractor.basePath + '/#/administration')
expect(browser.getCurrentUrl()).toMatch(/\/administration/)
})

Expand All @@ -21,7 +21,7 @@ describe('/#/administration', () => {
protractor.beforeEach.login({ email: 'admin@' + config.get('application.domain'), password: 'admin123' })

it('should be possible for any admin user to delete feedback', () => {
browser.get('/#/administration')
browser.get(protractor.basePath + '/#/administration')

$$('.mat-cell.mat-column-remove > button').first().click()
browser.wait(protractor.ExpectedConditions.stalenessOf(element(by.js(selectFiveStarRating))), 5000)
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/b2bOrderSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('/b2b/v2/order', () => {
describe('challenge "rce"', () => {
it('an infinite loop deserialization payload should not bring down the server', () => {
browser.waitForAngularEnabled(false)
browser.executeScript('var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.status == 500) { console.log("Success"); }}; xhttp.open("POST","http://localhost:3000/b2b/v2/orders/", true); xhttp.setRequestHeader("Content-type","application/json"); xhttp.setRequestHeader("Authorization",`Bearer ${localStorage.getItem("token")}`); xhttp.send(JSON.stringify({"orderLinesData": "(function dos() { while(true); })()"}));') // eslint-disable-line
browser.executeScript('var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.status == 500) { console.log("Success"); }}; xhttp.open("POST","'+browser.baseUrl+'/b2b/v2/orders/", true); xhttp.setRequestHeader("Content-type","application/json"); xhttp.setRequestHeader("Authorization",`Bearer ${localStorage.getItem("token")}`); xhttp.send(JSON.stringify({"orderLinesData": "(function dos() { while(true); })()"}));') // eslint-disable-line
browser.driver.sleep(1000)
browser.waitForAngularEnabled(true)
})
Expand All @@ -24,7 +24,7 @@ describe('/b2b/v2/order', () => {
describe('challenge "rceOccupy"', () => {
it('should be possible to cause request timeout using a recursive regular expression payload', () => {
browser.waitForAngularEnabled(false)
browser.executeScript('var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.status == 503) { console.log("Success"); }}; xhttp.open("POST","http://localhost:3000/b2b/v2/orders/", true); xhttp.setRequestHeader("Content-type","application/json"); xhttp.setRequestHeader("Authorization",`Bearer ${localStorage.getItem("token")}`); xhttp.send(JSON.stringify({"orderLinesData": "/((a+)+)b/.test(\'aaaaaaaaaaaaaaaaaaaaaaaaaaaaa\')"}));') // eslint-disable-line
browser.executeScript('var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.status == 503) { console.log("Success"); }}; xhttp.open("POST","'+browser.baseUrl+'/b2b/v2/orders/", true); xhttp.setRequestHeader("Content-type","application/json"); xhttp.setRequestHeader("Authorization",`Bearer ${localStorage.getItem("token")}`); xhttp.send(JSON.stringify({"orderLinesData": "/((a+)+)b/.test(\'aaaaaaaaaaaaaaaaaaaaaaaaaaaaa\')"}));') // eslint-disable-line
browser.driver.sleep(3000) // 2sec for the deserialization timeout plus 1sec for Angular
browser.waitForAngularEnabled(true)
})
Expand Down
Loading

0 comments on commit 1cba547

Please sign in to comment.