├── gulp.png ├── attacker-app ├── gulp.png ├── src │ ├── server │ │ ├── favicon.ico │ │ ├── utils │ │ │ └── 404.js │ │ ├── routes.js │ │ ├── data.js │ │ └── app.js │ └── client │ │ ├── images │ │ ├── busy.gif │ │ ├── icon.png │ │ ├── gulp-tiny.png │ │ └── AngularJS-small.png │ │ ├── app │ │ ├── widgets │ │ │ ├── widgets.module.js │ │ │ ├── widget-header.html │ │ │ ├── ht-widget-header.directive.js │ │ │ └── ht-img-person.directive.js │ │ ├── blocks │ │ │ ├── logger │ │ │ │ ├── logger.module.js │ │ │ │ └── logger.js │ │ │ ├── exception │ │ │ │ ├── exception.module.js │ │ │ │ ├── exception.js │ │ │ │ ├── exception-handler.provider.js │ │ │ │ └── exception-handler.provider.spec.js │ │ │ └── router │ │ │ │ ├── router.module.js │ │ │ │ └── router-helper.provider.js │ │ ├── layout │ │ │ ├── layout.module.js │ │ │ ├── ht-top-nav.html │ │ │ ├── shell.html │ │ │ ├── sidebar.html │ │ │ ├── ht-top-nav.directive.js │ │ │ ├── shell.controller.spec.js │ │ │ ├── shell.controller.js │ │ │ ├── sidebar.controller.js │ │ │ ├── sidebar.controller.spec.js │ │ │ ├── ht-sidebar.directive.js │ │ │ └── ht-sidebar.directive.spec.js │ │ ├── dashboard │ │ │ ├── dashboard.module.js │ │ │ ├── dashboard.route.js │ │ │ ├── dashboard.route.spec.js │ │ │ ├── dashboard.html │ │ │ ├── dashboard.controller.js │ │ │ └── dashboard.controller.spec.js │ │ ├── csrf-attack │ │ │ ├── csrf-attack.module.js │ │ │ ├── csrf-attack.controller.js │ │ │ ├── csrf-attack.route.js │ │ │ ├── csrf-attack.route.spec.js │ │ │ ├── csrf-attack.html │ │ │ └── csrf-attack.controller.spec.js │ │ ├── clickjacking-attack │ │ │ ├── clickjacking-attack.module.js │ │ │ ├── clickjacking-attack.controller.js │ │ │ ├── clickjacking-attack.html │ │ │ ├── clickjacking-attack.route.js │ │ │ ├── clickjacking-attack.route.spec.js │ │ │ └── clickjacking-attack.controller.spec.js │ │ ├── core │ │ │ ├── constants.js │ │ │ ├── core.module.js │ │ │ ├── core.route.js │ │ │ ├── dataservice.js │ │ │ ├── config.js │ │ │ ├── core.route.spec.js │ │ │ └── 404.html │ │ └── app.module.js │ │ ├── test-helpers │ │ ├── bind-polyfill.js │ │ └── mock-data.js │ │ ├── specs.html │ │ └── index.html ├── .bowerrc ├── .gitignore ├── .editorconfig ├── bower.json ├── .jshintrc ├── .jscsrc ├── karma.conf.js ├── package.json ├── gulp.config.js └── README.md ├── src ├── server │ ├── favicon.ico │ ├── utils │ │ └── 404.js │ ├── data.js │ ├── app.js │ └── routes.js └── client │ ├── images │ ├── busy.gif │ ├── icon.png │ ├── gulp-tiny.png │ └── AngularJS-small.png │ ├── app │ ├── widgets │ │ ├── widgets.module.js │ │ ├── widget-header.html │ │ ├── ht-widget-header.directive.js │ │ └── ht-img-person.directive.js │ ├── blocks │ │ ├── logger │ │ │ ├── logger.module.js │ │ │ └── logger.js │ │ ├── exception │ │ │ ├── exception.module.js │ │ │ ├── exception.js │ │ │ ├── exception-handler.provider.js │ │ │ └── exception-handler.provider.spec.js │ │ └── router │ │ │ ├── router.module.js │ │ │ └── router-helper.provider.js │ ├── layout │ │ ├── layout.module.js │ │ ├── sidebar.html │ │ ├── shell.html │ │ ├── ht-top-nav.html │ │ ├── shell.controller.spec.js │ │ ├── shell.controller.js │ │ ├── sidebar.controller.js │ │ ├── sidebar.controller.spec.js │ │ ├── ht-sidebar.directive.js │ │ ├── ht-top-nav.directive.js │ │ └── ht-sidebar.directive.spec.js │ ├── csrf │ │ ├── csrf.module.js │ │ ├── csrf.route.js │ │ ├── csrf.route.spec.js │ │ ├── csrf.controller.spec.js │ │ ├── csrf.controller.js │ │ └── csrf.html │ ├── dashboard │ │ ├── dashboard.module.js │ │ ├── dashboard.route.js │ │ ├── dashboard.route.spec.js │ │ ├── dashboard.html │ │ ├── dashboard.controller.js │ │ └── dashboard.controller.spec.js │ ├── xss-search │ │ ├── xss-search.module.js │ │ ├── xss-search.route.js │ │ ├── xss-search.route.spec.js │ │ ├── xss-search.controller.spec.js │ │ ├── xss-search.html │ │ └── xss-search.controller.js │ ├── clickjacking │ │ ├── clickjacking.module.js │ │ ├── clickjacking.controller.js │ │ ├── clickjacking.html │ │ ├── clickjacking.route.js │ │ ├── clickjacking.route.spec.js │ │ └── clickjacking.controller.spec.js │ ├── core │ │ ├── constants.js │ │ ├── core.module.js │ │ ├── core.route.js │ │ ├── config.js │ │ ├── core.route.spec.js │ │ ├── dataservice.js │ │ ├── 404.html │ │ └── user.service.js │ └── app.module.js │ ├── test-helpers │ ├── bind-polyfill.js │ └── mock-data.js │ ├── specs.html │ └── index.html ├── .bowerrc ├── .gitignore ├── .editorconfig ├── bower.json ├── .jshintrc ├── .jscsrc ├── karma.conf.js ├── package.json ├── gulp.config.js └── README.md /gulp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/gulp.png -------------------------------------------------------------------------------- /attacker-app/gulp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/attacker-app/gulp.png -------------------------------------------------------------------------------- /src/server/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/src/server/favicon.ico -------------------------------------------------------------------------------- /src/client/images/busy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/src/client/images/busy.gif -------------------------------------------------------------------------------- /src/client/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/src/client/images/icon.png -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components", 3 | "scripts": { 4 | "postinstall": "gulp wiredep" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/client/images/gulp-tiny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/src/client/images/gulp-tiny.png -------------------------------------------------------------------------------- /attacker-app/src/server/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/attacker-app/src/server/favicon.ico -------------------------------------------------------------------------------- /attacker-app/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components", 3 | "scripts": { 4 | "postinstall": "gulp wiredep" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/client/images/AngularJS-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/src/client/images/AngularJS-small.png -------------------------------------------------------------------------------- /attacker-app/src/client/images/busy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/attacker-app/src/client/images/busy.gif -------------------------------------------------------------------------------- /attacker-app/src/client/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/attacker-app/src/client/images/icon.png -------------------------------------------------------------------------------- /src/client/app/widgets/widgets.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.widgets', []); 5 | })(); 6 | -------------------------------------------------------------------------------- /attacker-app/src/client/images/gulp-tiny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/attacker-app/src/client/images/gulp-tiny.png -------------------------------------------------------------------------------- /src/client/app/blocks/logger/logger.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('blocks.logger', []); 5 | })(); 6 | -------------------------------------------------------------------------------- /src/client/app/layout/layout.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.layout', ['app.core']); 5 | })(); 6 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/widgets/widgets.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.widgets', []); 5 | })(); 6 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/blocks/logger/logger.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('blocks.logger', []); 5 | })(); 6 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/layout/layout.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.layout', ['app.core']); 5 | })(); 6 | -------------------------------------------------------------------------------- /attacker-app/src/client/images/AngularJS-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djadmin/vulnerable-app/HEAD/attacker-app/src/client/images/AngularJS-small.png -------------------------------------------------------------------------------- /src/client/app/blocks/exception/exception.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('blocks.exception', ['blocks.logger']); 5 | })(); 6 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/blocks/exception/exception.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('blocks.exception', ['blocks.logger']); 5 | })(); 6 | -------------------------------------------------------------------------------- /src/client/app/csrf/csrf.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.csrf', [ 5 | 'app.core', 6 | 'app.widgets' 7 | ]); 8 | })(); 9 | -------------------------------------------------------------------------------- /attacker-app/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 3 | node_modules/ 4 | bower_components/ 5 | 6 | # other 7 | .tmp 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 3 | node_modules/ 4 | bower_components/ 5 | 6 | # other 7 | .tmp 8 | report/ 9 | build/ -------------------------------------------------------------------------------- /src/client/app/blocks/router/router.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('blocks.router', [ 5 | 'ui.router', 6 | 'blocks.logger' 7 | ]); 8 | })(); 9 | -------------------------------------------------------------------------------- /src/client/app/dashboard/dashboard.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.dashboard', [ 5 | 'app.core', 6 | 'app.widgets' 7 | ]); 8 | })(); 9 | -------------------------------------------------------------------------------- /src/client/app/xss-search/xss-search.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.xss-search', [ 5 | 'app.core', 6 | 'app.widgets' 7 | ]); 8 | })(); 9 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/dashboard/dashboard.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.dashboard', [ 5 | 'app.core', 6 | 'app.widgets' 7 | ]); 8 | })(); 9 | -------------------------------------------------------------------------------- /src/client/app/clickjacking/clickjacking.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.clickjacking', [ 5 | 'app.core', 6 | 'app.widgets' 7 | ]); 8 | })(); 9 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/blocks/router/router.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('blocks.router', [ 5 | 'ui.router', 6 | 'blocks.logger' 7 | ]); 8 | })(); 9 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/csrf-attack/csrf-attack.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.csrf-attack', [ 5 | 'app.core', 6 | 'app.widgets' 7 | ]); 8 | })(); 9 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/clickjacking-attack/clickjacking-attack.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('app.clickjacking-attack', [ 5 | 'app.core', 6 | 'app.widgets' 7 | ]); 8 | })(); 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /src/client/app/core/constants.js: -------------------------------------------------------------------------------- 1 | /* global toastr:false, moment:false */ 2 | (function() { 3 | 'use strict'; 4 | 5 | angular 6 | .module('app.core') 7 | .constant('toastr', toastr) 8 | .constant('moment', moment); 9 | })(); 10 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/core/constants.js: -------------------------------------------------------------------------------- 1 | /* global toastr:false, moment:false */ 2 | (function() { 3 | 'use strict'; 4 | 5 | angular 6 | .module('app.core') 7 | .constant('toastr', toastr) 8 | .constant('moment', moment); 9 | })(); 10 | -------------------------------------------------------------------------------- /attacker-app/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /src/client/app/core/core.module.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core', [ 6 | 'ngAnimate', 'ngSanitize', 7 | 'blocks.exception', 'blocks.logger', 'blocks.router', 8 | 'ui.router', 'ngplus' 9 | ]); 10 | })(); 11 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/core/core.module.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core', [ 6 | 'ngAnimate', 'ngSanitize', 7 | 'blocks.exception', 'blocks.logger', 'blocks.router', 8 | 'ui.router', 'ngplus' 9 | ]); 10 | })(); 11 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/app.module.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('app', [ 5 | 'app.core', 6 | 'app.widgets', 7 | 'app.dashboard', 8 | 'app.csrf-attack', 9 | 'app.clickjacking-attack', 10 | 'app.layout' 11 | ]); 12 | 13 | })(); 14 | -------------------------------------------------------------------------------- /src/client/app/app.module.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('app', [ 5 | 'app.core', 6 | 'app.widgets', 7 | 'app.dashboard', 8 | 'app.xss-search', 9 | 'app.csrf', 10 | 'app.clickjacking', 11 | 'app.layout' 12 | ]); 13 | 14 | })(); 15 | -------------------------------------------------------------------------------- /src/client/app/widgets/widget-header.html: -------------------------------------------------------------------------------- 1 |
2 |
{{title}}
3 | ({{subtitle}}) 4 |
5 | {{rightText}} 6 |
7 |
-------------------------------------------------------------------------------- /attacker-app/src/client/app/widgets/widget-header.html: -------------------------------------------------------------------------------- 1 |
2 |
{{title}}
3 | ({{subtitle}}) 4 |
5 | {{rightText}} 6 |
7 |
-------------------------------------------------------------------------------- /attacker-app/src/client/app/csrf-attack/csrf-attack.controller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.csrf-attack') 6 | .controller('CsrfController', CsrfController); 7 | 8 | CsrfController.$inject = ['$q', 'logger']; 9 | /* @ngInject */ 10 | function CsrfController($q, logger) { 11 | var vm = this; 12 | vm.title = 'CSRF-Attack'; 13 | } 14 | })(); 15 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/clickjacking-attack/clickjacking-attack.controller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.clickjacking-attack') 6 | .controller('ClickjackingController', ClickjackingController); 7 | 8 | ClickjackingController.$inject = ['$q', 'logger']; 9 | /* @ngInject */ 10 | function ClickjackingController($q, logger) { 11 | var vm = this; 12 | vm.title = 'Clickjacking-Attack'; 13 | } 14 | })(); 15 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/clickjacking-attack/clickjacking-attack.html: -------------------------------------------------------------------------------- 1 |
2 | 12 | 13 | 14 |
-------------------------------------------------------------------------------- /src/server/utils/404.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | var service = { 3 | notFoundMiddleware: notFoundMiddleware, 4 | send404: send404 5 | }; 6 | return service; 7 | 8 | function notFoundMiddleware(req, res, next) { 9 | send404(req, res, 'API endpoint not found'); 10 | } 11 | 12 | function send404(req, res, description) { 13 | var data = { 14 | status: 404, 15 | message: 'Not Found', 16 | description: description, 17 | url: req.url 18 | }; 19 | res.status(404) 20 | .send(data) 21 | .end(); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/layout/ht-top-nav.html: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /attacker-app/src/server/utils/404.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | var service = { 3 | notFoundMiddleware: notFoundMiddleware, 4 | send404: send404 5 | }; 6 | return service; 7 | 8 | function notFoundMiddleware(req, res, next) { 9 | send404(req, res, 'API endpoint not found'); 10 | } 11 | 12 | function send404(req, res, description) { 13 | var data = { 14 | status: 404, 15 | message: 'Not Found', 16 | description: description, 17 | url: req.url 18 | }; 19 | res.status(404) 20 | .send(data) 21 | .end(); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/client/app/core/core.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core') 6 | .run(appRun); 7 | 8 | /* @ngInject */ 9 | function appRun(routerHelper) { 10 | var otherwise = '/404'; 11 | routerHelper.configureStates(getStates(), otherwise); 12 | } 13 | 14 | function getStates() { 15 | return [ 16 | { 17 | state: '404', 18 | config: { 19 | url: '/404', 20 | templateUrl: 'app/core/404.html', 21 | title: '404' 22 | } 23 | } 24 | ]; 25 | } 26 | })(); 27 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/core/core.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core') 6 | .run(appRun); 7 | 8 | /* @ngInject */ 9 | function appRun(routerHelper) { 10 | var otherwise = '/404'; 11 | routerHelper.configureStates(getStates(), otherwise); 12 | } 13 | 14 | function getStates() { 15 | return [ 16 | { 17 | state: '404', 18 | config: { 19 | url: '/404', 20 | templateUrl: 'app/core/404.html', 21 | title: '404' 22 | } 23 | } 24 | ]; 25 | } 26 | })(); 27 | -------------------------------------------------------------------------------- /src/client/app/layout/sidebar.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 15 | 16 |
17 | -------------------------------------------------------------------------------- /src/client/app/layout/shell.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
7 | 8 |
9 | 10 |
14 | 15 | 16 |
{{vm.busyMessage}}
17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/layout/shell.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
7 | 8 |
9 | 10 |
14 | 15 | 16 |
{{vm.busyMessage}}
17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/layout/sidebar.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 15 | 16 |
17 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/layout/ht-top-nav.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.layout') 6 | .directive('htTopNav', htTopNav); 7 | 8 | /* @ngInject */ 9 | function htTopNav () { 10 | var directive = { 11 | bindToController: true, 12 | controller: TopNavController, 13 | controllerAs: 'vm', 14 | restrict: 'EA', 15 | scope: { 16 | 'navline': '=' 17 | }, 18 | templateUrl: 'app/layout/ht-top-nav.html' 19 | }; 20 | 21 | /* @ngInject */ 22 | function TopNavController() { 23 | var vm = this; 24 | } 25 | 26 | return directive; 27 | } 28 | })(); 29 | -------------------------------------------------------------------------------- /attacker-app/src/server/routes.js: -------------------------------------------------------------------------------- 1 | var router = require('express').Router(); 2 | var four0four = require('./utils/404')(); 3 | var data = require('./data'); 4 | 5 | router.get('/people', getPeople); 6 | router.get('/person/:id', getPerson); 7 | router.get('/*', four0four.notFoundMiddleware); 8 | 9 | module.exports = router; 10 | 11 | ////////////// 12 | 13 | function getPeople(req, res, next) { 14 | res.status(200).send(data.people); 15 | } 16 | 17 | function getPerson(req, res, next) { 18 | var id = +req.params.id; 19 | var person = data.people.filter(function(p) { 20 | return p.id === id; 21 | })[0]; 22 | 23 | if (person) { 24 | res.status(200).send(person); 25 | } else { 26 | four0four.send404(req, res, 'person ' + id + ' not found'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/client/app/clickjacking/clickjacking.controller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.clickjacking') 6 | .controller('ClickjackingController', ClickjackingController); 7 | 8 | ClickjackingController.$inject = ['$q', 'userservice', 'logger']; 9 | /* @ngInject */ 10 | function ClickjackingController($q, userservice, logger) { 11 | var vm = this; 12 | vm.title = 'Clickjacking'; 13 | vm.deleteProfile = deleteProfile; 14 | 15 | activate(); 16 | 17 | function activate() { 18 | logger.info('Activated Clickjacking View'); 19 | } 20 | 21 | function deleteProfile() { 22 | logger.info('The profile was successfully deleted!'); 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /src/server/data.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | people: getPeople() 3 | }; 4 | 5 | function getPeople() { 6 | return [ 7 | {id: 1, firstName: 'John', lastName: 'Papa', age: 25, location: 'Florida'}, 8 | {id: 2, firstName: 'Ward', lastName: 'Bell', age: 31, location: 'California'}, 9 | {id: 3, firstName: 'Colleen', lastName: 'Jones', age: 21, location: 'New York'}, 10 | {id: 4, firstName: 'Madelyn', lastName: 'Green', age: 18, location: 'North Dakota'}, 11 | {id: 5, firstName: 'Ella', lastName: 'Jobs', age: 18, location: 'South Dakota'}, 12 | {id: 6, firstName: 'Landon', lastName: 'Gates', age: 11, location: 'South Carolina'}, 13 | {id: 7, firstName: 'Haley', lastName: 'Guthrie', age: 35, location: 'Wyoming'}, 14 | {id: 8, firstName: 'Aaron', lastName: 'Jinglehiemer', age: 22, location: 'Utah'} 15 | ]; 16 | } 17 | -------------------------------------------------------------------------------- /attacker-app/src/server/data.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | people: getPeople() 3 | }; 4 | 5 | function getPeople() { 6 | return [ 7 | {id: 1, firstName: 'John', lastName: 'Papa', age: 25, location: 'Florida'}, 8 | {id: 2, firstName: 'Ward', lastName: 'Bell', age: 31, location: 'California'}, 9 | {id: 3, firstName: 'Colleen', lastName: 'Jones', age: 21, location: 'New York'}, 10 | {id: 4, firstName: 'Madelyn', lastName: 'Green', age: 18, location: 'North Dakota'}, 11 | {id: 5, firstName: 'Ella', lastName: 'Jobs', age: 18, location: 'South Dakota'}, 12 | {id: 6, firstName: 'Landon', lastName: 'Gates', age: 11, location: 'South Carolina'}, 13 | {id: 7, firstName: 'Haley', lastName: 'Guthrie', age: 35, location: 'Wyoming'}, 14 | {id: 8, firstName: 'Aaron', lastName: 'Jinglehiemer', age: 22, location: 'Utah'} 15 | ]; 16 | } 17 | -------------------------------------------------------------------------------- /src/client/app/widgets/ht-widget-header.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.widgets') 6 | .directive('htWidgetHeader', htWidgetHeader); 7 | 8 | /* @ngInject */ 9 | function htWidgetHeader() { 10 | //Usage: 11 | //
12 | // Creates: 13 | //
16 | var directive = { 17 | scope: { 18 | 'title': '@', 19 | 'subtitle': '@', 20 | 'rightText': '@', 21 | 'allowCollapse': '@' 22 | }, 23 | templateUrl: 'app/widgets/widget-header.html', 24 | restrict: 'EA' 25 | }; 26 | return directive; 27 | } 28 | })(); 29 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/widgets/ht-widget-header.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.widgets') 6 | .directive('htWidgetHeader', htWidgetHeader); 7 | 8 | /* @ngInject */ 9 | function htWidgetHeader() { 10 | //Usage: 11 | //
12 | // Creates: 13 | //
16 | var directive = { 17 | scope: { 18 | 'title': '@', 19 | 'subtitle': '@', 20 | 'rightText': '@', 21 | 'allowCollapse': '@' 22 | }, 23 | templateUrl: 'app/widgets/widget-header.html', 24 | restrict: 'EA' 25 | }; 26 | return directive; 27 | } 28 | })(); 29 | -------------------------------------------------------------------------------- /src/client/app/widgets/ht-img-person.directive.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.widgets') 6 | .directive('htImgPerson', htImgPerson); 7 | 8 | htImgPerson.$inject = ['config']; 9 | /* @ngInject */ 10 | function htImgPerson (config) { 11 | //Usage: 12 | // 13 | var basePath = config.imageBasePath; 14 | var unknownImage = config.unknownPersonImageSource; 15 | var directive = { 16 | link: link, 17 | restrict: 'A' 18 | }; 19 | return directive; 20 | 21 | function link(scope, element, attrs) { 22 | attrs.$observe('htImgPerson', function (value) { 23 | value = basePath + (value || unknownImage); 24 | attrs.$set('src', value); 25 | }); 26 | } 27 | } 28 | })(); 29 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/widgets/ht-img-person.directive.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.widgets') 6 | .directive('htImgPerson', htImgPerson); 7 | 8 | htImgPerson.$inject = ['config']; 9 | /* @ngInject */ 10 | function htImgPerson (config) { 11 | //Usage: 12 | // 13 | var basePath = config.imageBasePath; 14 | var unknownImage = config.unknownPersonImageSource; 15 | var directive = { 16 | link: link, 17 | restrict: 'A' 18 | }; 19 | return directive; 20 | 21 | function link(scope, element, attrs) { 22 | attrs.$observe('htImgPerson', function (value) { 23 | value = basePath + (value || unknownImage); 24 | attrs.$set('src', value); 25 | }); 26 | } 27 | } 28 | })(); 29 | -------------------------------------------------------------------------------- /src/client/app/blocks/exception/exception.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('blocks.exception') 6 | .factory('exception', exception); 7 | 8 | /* @ngInject */ 9 | function exception($q, logger) { 10 | var service = { 11 | catcher: catcher 12 | }; 13 | return service; 14 | 15 | function catcher(message) { 16 | return function(e) { 17 | var thrownDescription; 18 | var newMessage; 19 | if (e.data && e.data.description) { 20 | thrownDescription = '\n' + e.data.description; 21 | newMessage = message + thrownDescription; 22 | } 23 | e.data.description = newMessage; 24 | logger.error(newMessage); 25 | return $q.reject(e); 26 | }; 27 | } 28 | } 29 | })(); 30 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/blocks/exception/exception.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('blocks.exception') 6 | .factory('exception', exception); 7 | 8 | /* @ngInject */ 9 | function exception($q, logger) { 10 | var service = { 11 | catcher: catcher 12 | }; 13 | return service; 14 | 15 | function catcher(message) { 16 | return function(e) { 17 | var thrownDescription; 18 | var newMessage; 19 | if (e.data && e.data.description) { 20 | thrownDescription = '\n' + e.data.description; 21 | newMessage = message + thrownDescription; 22 | } 23 | e.data.description = newMessage; 24 | logger.error(newMessage); 25 | return $q.reject(e); 26 | }; 27 | } 28 | } 29 | })(); 30 | -------------------------------------------------------------------------------- /src/client/app/csrf/csrf.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.csrf') 6 | .run(appRun); 7 | 8 | appRun.$inject = ['routerHelper']; 9 | /* @ngInject */ 10 | function appRun(routerHelper) { 11 | routerHelper.configureStates(getStates()); 12 | } 13 | 14 | function getStates() { 15 | return [ 16 | { 17 | state: 'csrf', 18 | config: { 19 | url: '/csrf', 20 | templateUrl: 'app/csrf/csrf.html', 21 | controller: 'CsrfController', 22 | controllerAs: 'vm', 23 | title: 'CSRF', 24 | settings: { 25 | nav: 1, 26 | content: ' Profile' 27 | } 28 | } 29 | } 30 | ]; 31 | } 32 | })(); 33 | -------------------------------------------------------------------------------- /src/client/app/dashboard/dashboard.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.dashboard') 6 | .run(appRun); 7 | 8 | appRun.$inject = ['routerHelper']; 9 | /* @ngInject */ 10 | function appRun(routerHelper) { 11 | routerHelper.configureStates(getStates()); 12 | } 13 | 14 | function getStates() { 15 | return [ 16 | { 17 | state: 'dashboard', 18 | config: { 19 | url: '/', 20 | templateUrl: 'app/dashboard/dashboard.html', 21 | controller: 'DashboardController', 22 | controllerAs: 'vm', 23 | title: 'dashboard', 24 | settings: { 25 | nav: 1, 26 | content: ' Dashboard' 27 | } 28 | } 29 | } 30 | ]; 31 | } 32 | })(); 33 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/csrf-attack/csrf-attack.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.csrf-attack') 6 | .run(appRun); 7 | 8 | appRun.$inject = ['routerHelper']; 9 | /* @ngInject */ 10 | function appRun(routerHelper) { 11 | routerHelper.configureStates(getStates()); 12 | } 13 | 14 | function getStates() { 15 | return [ 16 | { 17 | state: 'csrf', 18 | config: { 19 | url: '/', 20 | templateUrl: 'app/csrf-attack/csrf-attack.html', 21 | controller: 'CsrfController', 22 | controllerAs: 'vm', 23 | title: 'CSRF-Attack', 24 | settings: { 25 | nav: 1, 26 | content: ' CSRF-Attack' 27 | } 28 | } 29 | } 30 | ]; 31 | } 32 | })(); 33 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/dashboard/dashboard.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.dashboard') 6 | .run(appRun); 7 | 8 | appRun.$inject = ['routerHelper']; 9 | /* @ngInject */ 10 | function appRun(routerHelper) { 11 | routerHelper.configureStates(getStates()); 12 | } 13 | 14 | function getStates() { 15 | return [ 16 | { 17 | state: 'dashboard', 18 | config: { 19 | url: '/', 20 | templateUrl: 'app/dashboard/dashboard.html', 21 | controller: 'DashboardController', 22 | controllerAs: 'vm', 23 | title: 'dashboard', 24 | settings: { 25 | nav: 1, 26 | content: ' Dashboard' 27 | } 28 | } 29 | } 30 | ]; 31 | } 32 | })(); 33 | -------------------------------------------------------------------------------- /src/client/app/xss-search/xss-search.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.xss-search') 6 | .run(appRun); 7 | 8 | appRun.$inject = ['routerHelper']; 9 | /* @ngInject */ 10 | function appRun(routerHelper) { 11 | routerHelper.configureStates(getStates()); 12 | } 13 | 14 | function getStates() { 15 | return [ 16 | { 17 | state: 'xss-search', 18 | config: { 19 | url: '/xss-search', 20 | templateUrl: 'app/xss-search/xss-search.html', 21 | controller: 'XssSearchController', 22 | controllerAs: 'vm', 23 | title: 'XSS Search', 24 | settings: { 25 | nav: 1, 26 | content: ' Search' 27 | } 28 | } 29 | } 30 | ]; 31 | } 32 | })(); 33 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/core/dataservice.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core') 6 | .factory('dataservice', dataservice); 7 | 8 | dataservice.$inject = ['$http', '$q', 'exception', 'logger']; 9 | /* @ngInject */ 10 | function dataservice($http, $q, exception, logger) { 11 | var service = { 12 | getPeople: getPeople, 13 | getMessageCount: getMessageCount 14 | }; 15 | 16 | return service; 17 | 18 | function getMessageCount() { return $q.when(72); } 19 | 20 | function getPeople() { 21 | return $http.get('/api/people') 22 | .then(success) 23 | .catch(fail); 24 | 25 | function success(response) { 26 | return response.data; 27 | } 28 | 29 | function fail(e) { 30 | return exception.catcher('XHR Failed for getPeople')(e); 31 | } 32 | } 33 | } 34 | })(); 35 | -------------------------------------------------------------------------------- /src/client/app/clickjacking/clickjacking.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |

See the attacker-app clickjacking-attack view for more details on this vulnerability

11 | 12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
-------------------------------------------------------------------------------- /src/client/app/clickjacking/clickjacking.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.clickjacking') 6 | .run(appRun); 7 | 8 | appRun.$inject = ['routerHelper']; 9 | /* @ngInject */ 10 | function appRun(routerHelper) { 11 | routerHelper.configureStates(getStates()); 12 | } 13 | 14 | function getStates() { 15 | return [ 16 | { 17 | state: 'clickjacking', 18 | config: { 19 | url: '/clickjacking', 20 | templateUrl: 'app/clickjacking/clickjacking.html', 21 | controller: 'ClickjackingController', 22 | controllerAs: 'vm', 23 | title: 'Clickjacking', 24 | settings: { 25 | nav: 1, 26 | content: ' Delete it All!' 27 | } 28 | } 29 | } 30 | ]; 31 | } 32 | })(); 33 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/clickjacking-attack/clickjacking-attack.route.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.clickjacking-attack') 6 | .run(appRun); 7 | 8 | appRun.$inject = ['routerHelper']; 9 | /* @ngInject */ 10 | function appRun(routerHelper) { 11 | routerHelper.configureStates(getStates()); 12 | } 13 | 14 | function getStates() { 15 | return [ 16 | { 17 | state: 'clickjacking', 18 | config: { 19 | url: '/', 20 | templateUrl: 'app/clickjacking-attack/clickjacking-attack.html', 21 | controller: 'ClickjackingController', 22 | controllerAs: 'vm', 23 | title: 'Clickjacking-Attack', 24 | settings: { 25 | nav: 1, 26 | content: ' Clickjacking-Attack' 27 | } 28 | } 29 | } 30 | ]; 31 | } 32 | })(); 33 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vulnerable-app", 3 | "version": "0.0.1", 4 | "description": "vulnerable-app", 5 | "authors": [], 6 | "license": "MIT", 7 | "ignore": [ 8 | "**/.*", 9 | "node_modules", 10 | "bower_components", 11 | "test", 12 | "tests" 13 | ], 14 | "devDependencies": { 15 | "angular-mocks": "^1.5.6", 16 | "sinon": "http://sinonjs.org/releases/sinon-1.12.1.js", 17 | "bardjs": "^0.1.4" 18 | }, 19 | "dependencies": { 20 | "jquery": "^2.2.4", 21 | "angular": "^1.5.6", 22 | "angular-sanitize": "^1.5.6", 23 | "bootstrap": "^3.3.5", 24 | "extras.angular.plus": "^0.9.2", 25 | "font-awesome": "^4.3.0", 26 | "moment": "^2.10.3", 27 | "angular-ui-router": "^0.4.2", 28 | "toastr": "^2.1.1", 29 | "angular-animate": "^1.5.6" 30 | }, 31 | "overrides": { 32 | "bootstrap": { 33 | "main": "dist/css/bootstrap.css", 34 | "dist": "dist/js/bootstrap.js" 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/client/app/layout/ht-top-nav.html: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /src/client/app/core/config.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | var core = angular.module('app.core'); 5 | 6 | core.config(toastrConfig); 7 | 8 | toastrConfig.$inject = ['toastr']; 9 | /* @ngInject */ 10 | function toastrConfig(toastr) { 11 | toastr.options.timeOut = 4000; 12 | toastr.options.positionClass = 'toast-bottom-right'; 13 | } 14 | 15 | var config = { 16 | appErrorPrefix: '[vulnerable-app Error] ', 17 | appTitle: 'vulnerable-app' 18 | }; 19 | 20 | core.value('config', config); 21 | 22 | core.config(configure); 23 | 24 | configure.$inject = ['$logProvider', 'routerHelperProvider', 'exceptionHandlerProvider']; 25 | /* @ngInject */ 26 | function configure($logProvider, routerHelperProvider, exceptionHandlerProvider) { 27 | if ($logProvider.debugEnabled) { 28 | $logProvider.debugEnabled(true); 29 | } 30 | exceptionHandlerProvider.configure(config.appErrorPrefix); 31 | routerHelperProvider.configure({docTitle: config.appTitle + ': '}); 32 | } 33 | 34 | })(); 35 | -------------------------------------------------------------------------------- /src/client/app/csrf/csrf.route.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('csrf routes', function () { 3 | describe('state', function () { 4 | var view = 'app/csrf/csrf.html'; 5 | 6 | beforeEach(function() { 7 | module('app.csrf', bard.fakeToastr); 8 | bard.inject('$httpBackend', '$location', '$rootScope', '$state', '$templateCache'); 9 | }); 10 | 11 | beforeEach(function() { 12 | $templateCache.put(view, ''); 13 | }); 14 | 15 | bard.verifyNoOutstandingHttpRequests(); 16 | 17 | it('should map state csrf to url /csrf ', function() { 18 | expect($state.href('csrf', {})).to.equal('/csrf'); 19 | }); 20 | 21 | it('should map /csrf route to csrf View template', function () { 22 | expect($state.get('csrf').templateUrl).to.equal(view); 23 | }); 24 | 25 | it('of csrf should work with $state.go', function () { 26 | $state.go('csrf'); 27 | $rootScope.$apply(); 28 | expect($state.is('csrf')); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/core/config.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | var core = angular.module('app.core'); 5 | 6 | core.config(toastrConfig); 7 | 8 | toastrConfig.$inject = ['toastr']; 9 | /* @ngInject */ 10 | function toastrConfig(toastr) { 11 | toastr.options.timeOut = 4000; 12 | toastr.options.positionClass = 'toast-bottom-right'; 13 | } 14 | 15 | var config = { 16 | appErrorPrefix: '[attacker-app Error] ', 17 | appTitle: 'attacker-app' 18 | }; 19 | 20 | core.value('config', config); 21 | 22 | core.config(configure); 23 | 24 | configure.$inject = ['$logProvider', 'routerHelperProvider', 'exceptionHandlerProvider']; 25 | /* @ngInject */ 26 | function configure($logProvider, routerHelperProvider, exceptionHandlerProvider) { 27 | if ($logProvider.debugEnabled) { 28 | $logProvider.debugEnabled(true); 29 | } 30 | exceptionHandlerProvider.configure(config.appErrorPrefix); 31 | routerHelperProvider.configure({docTitle: config.appTitle + ': '}); 32 | } 33 | 34 | })(); 35 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/csrf-attack/csrf-attack.route.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('csrf routes', function () { 3 | describe('state', function () { 4 | var view = 'app/csrf/csrf.html'; 5 | 6 | beforeEach(function() { 7 | module('app.csrf-attack', bard.fakeToastr); 8 | bard.inject('$httpBackend', '$location', '$rootScope', '$state', '$templateCache'); 9 | }); 10 | 11 | beforeEach(function() { 12 | $templateCache.put(view, ''); 13 | }); 14 | 15 | bard.verifyNoOutstandingHttpRequests(); 16 | 17 | it('should map state csrf to url / ', function() { 18 | expect($state.href('csrf', {})).to.equal('/'); 19 | }); 20 | 21 | it('should map /csrf route to csrf View template', function () { 22 | expect($state.get('csrf').templateUrl).to.equal(view); 23 | }); 24 | 25 | it('of csrf should work with $state.go', function () { 26 | $state.go('csrf'); 27 | $rootScope.$apply(); 28 | expect($state.is('csrf')); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/client/app/core/core.route.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('core', function() { 3 | describe('state', function() { 4 | var views = { 5 | four0four: 'app/core/404.html' 6 | }; 7 | 8 | beforeEach(function() { 9 | module('app.core', bard.fakeToastr); 10 | bard.inject('$location', '$rootScope', '$state', '$templateCache'); 11 | $templateCache.put(views.core, ''); 12 | }); 13 | 14 | it('should map /404 route to 404 View template', function() { 15 | expect($state.get('404').templateUrl).to.equal(views.four0four); 16 | }); 17 | 18 | it('of dashboard should work with $state.go', function() { 19 | $state.go('404'); 20 | $rootScope.$apply(); 21 | expect($state.is('404')); 22 | }); 23 | 24 | it('should route /invalid to the otherwise (404) route', function() { 25 | $location.path('/invalid'); 26 | $rootScope.$apply(); 27 | expect($state.current.templateUrl).to.equal(views.four0four); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /src/client/app/layout/shell.controller.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('ShellController', function() { 3 | var controller; 4 | 5 | beforeEach(function() { 6 | bard.appModule('app.layout'); 7 | bard.inject('$controller', '$q', '$rootScope', '$timeout', 'dataservice'); 8 | }); 9 | 10 | beforeEach(function () { 11 | controller = $controller('ShellController'); 12 | $rootScope.$apply(); 13 | }); 14 | 15 | bard.verifyNoOutstandingHttpRequests(); 16 | 17 | describe('Shell controller', function() { 18 | it('should be created successfully', function () { 19 | expect(controller).to.be.defined; 20 | }); 21 | 22 | it('should show splash screen', function () { 23 | expect($rootScope.showSplash).to.be.true; 24 | }); 25 | 26 | it('should hide splash screen after timeout', function (done) { 27 | $timeout(function() { 28 | expect($rootScope.showSplash).to.be.false; 29 | done(); 30 | }, 1000); 31 | $timeout.flush(); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/core/core.route.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('core', function() { 3 | describe('state', function() { 4 | var views = { 5 | four0four: 'app/core/404.html' 6 | }; 7 | 8 | beforeEach(function() { 9 | module('app.core', bard.fakeToastr); 10 | bard.inject('$location', '$rootScope', '$state', '$templateCache'); 11 | $templateCache.put(views.core, ''); 12 | }); 13 | 14 | it('should map /404 route to 404 View template', function() { 15 | expect($state.get('404').templateUrl).to.equal(views.four0four); 16 | }); 17 | 18 | it('of dashboard should work with $state.go', function() { 19 | $state.go('404'); 20 | $rootScope.$apply(); 21 | expect($state.is('404')); 22 | }); 23 | 24 | it('should route /invalid to the otherwise (404) route', function() { 25 | $location.path('/invalid'); 26 | $rootScope.$apply(); 27 | expect($state.current.templateUrl).to.equal(views.four0four); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /src/client/app/layout/shell.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.layout') 6 | .controller('ShellController', ShellController); 7 | 8 | ShellController.$inject = ['$rootScope', '$timeout', 'config', 'logger']; 9 | /* @ngInject */ 10 | function ShellController($rootScope, $timeout, config, logger) { 11 | var vm = this; 12 | vm.busyMessage = 'Please wait ...'; 13 | vm.isBusy = true; 14 | $rootScope.showSplash = true; 15 | vm.navline = { 16 | title: config.appTitle, 17 | text: 'Created by John Papa', 18 | link: 'http://twitter.com/john_papa' 19 | }; 20 | 21 | activate(); 22 | 23 | function activate() { 24 | logger.success(config.appTitle + ' loaded!', null); 25 | hideSplash(); 26 | } 27 | 28 | function hideSplash() { 29 | //Force a 1 second delay so we can see the splash. 30 | $timeout(function() { 31 | $rootScope.showSplash = false; 32 | }, 1000); 33 | } 34 | } 35 | })(); 36 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/layout/shell.controller.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('ShellController', function() { 3 | var controller; 4 | 5 | beforeEach(function() { 6 | bard.appModule('app.layout'); 7 | bard.inject('$controller', '$q', '$rootScope', '$timeout', 'dataservice'); 8 | }); 9 | 10 | beforeEach(function () { 11 | controller = $controller('ShellController'); 12 | $rootScope.$apply(); 13 | }); 14 | 15 | bard.verifyNoOutstandingHttpRequests(); 16 | 17 | describe('Shell controller', function() { 18 | it('should be created successfully', function () { 19 | expect(controller).to.be.defined; 20 | }); 21 | 22 | it('should show splash screen', function () { 23 | expect($rootScope.showSplash).to.be.true; 24 | }); 25 | 26 | it('should hide splash screen after timeout', function (done) { 27 | $timeout(function() { 28 | expect($rootScope.showSplash).to.be.false; 29 | done(); 30 | }, 1000); 31 | $timeout.flush(); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /attacker-app/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "attacker-app", 3 | "version": "0.0.1", 4 | "description": "attacker-app", 5 | "authors": [], 6 | "license": "MIT", 7 | "ignore": [ 8 | "**/.*", 9 | "node_modules", 10 | "bower_components", 11 | "test", 12 | "tests" 13 | ], 14 | "devDependencies": { 15 | "angular-mocks": "^1.4.5", 16 | "sinon": "http://sinonjs.org/releases/sinon-1.12.1.js", 17 | "bardjs": "^0.1.4" 18 | }, 19 | "dependencies": { 20 | "jquery": "^2.1.4", 21 | "angular": "^1.4.5", 22 | "angular-sanitize": "^1.4.5", 23 | "bootstrap": "^3.3.5", 24 | "extras.angular.plus": "^0.9.2", 25 | "font-awesome": "^4.3.0", 26 | "moment": "^2.10.3", 27 | "angular-ui-router": "^0.2.15", 28 | "toastr": "^2.1.1", 29 | "angular-animate": "^1.4.5" 30 | }, 31 | "resolutions": { 32 | "angular": "1.3.17" 33 | }, 34 | "overrides": { 35 | "bootstrap": { 36 | "main": "dist/css/bootstrap.css", 37 | "dist": "dist/js/bootstrap.js" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /attacker-app/src/client/app/layout/shell.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.layout') 6 | .controller('ShellController', ShellController); 7 | 8 | ShellController.$inject = ['$rootScope', '$timeout', 'config', 'logger']; 9 | /* @ngInject */ 10 | function ShellController($rootScope, $timeout, config, logger) { 11 | var vm = this; 12 | vm.busyMessage = 'Please wait ...'; 13 | vm.isBusy = true; 14 | $rootScope.showSplash = true; 15 | vm.navline = { 16 | title: config.appTitle, 17 | text: 'Created by John Papa', 18 | link: 'http://twitter.com/john_papa' 19 | }; 20 | 21 | activate(); 22 | 23 | function activate() { 24 | logger.success(config.appTitle + ' loaded!', null); 25 | hideSplash(); 26 | } 27 | 28 | function hideSplash() { 29 | //Force a 1 second delay so we can see the splash. 30 | $timeout(function() { 31 | $rootScope.showSplash = false; 32 | }, 1000); 33 | } 34 | } 35 | })(); 36 | -------------------------------------------------------------------------------- /src/client/app/dashboard/dashboard.route.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('dashboard routes', function () { 3 | describe('state', function () { 4 | var view = 'app/dashboard/dashboard.html'; 5 | 6 | beforeEach(function() { 7 | module('app.dashboard', bard.fakeToastr); 8 | bard.inject('$httpBackend', '$location', '$rootScope', '$state', '$templateCache'); 9 | }); 10 | 11 | beforeEach(function() { 12 | $templateCache.put(view, ''); 13 | }); 14 | 15 | bard.verifyNoOutstandingHttpRequests(); 16 | 17 | it('should map state dashboard to url / ', function() { 18 | expect($state.href('dashboard', {})).to.equal('/'); 19 | }); 20 | 21 | it('should map /dashboard route to dashboard View template', function () { 22 | expect($state.get('dashboard').templateUrl).to.equal(view); 23 | }); 24 | 25 | it('of dashboard should work with $state.go', function () { 26 | $state.go('dashboard'); 27 | $rootScope.$apply(); 28 | expect($state.is('dashboard')); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/dashboard/dashboard.route.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('dashboard routes', function () { 3 | describe('state', function () { 4 | var view = 'app/dashboard/dashboard.html'; 5 | 6 | beforeEach(function() { 7 | module('app.dashboard', bard.fakeToastr); 8 | bard.inject('$httpBackend', '$location', '$rootScope', '$state', '$templateCache'); 9 | }); 10 | 11 | beforeEach(function() { 12 | $templateCache.put(view, ''); 13 | }); 14 | 15 | bard.verifyNoOutstandingHttpRequests(); 16 | 17 | it('should map state dashboard to url / ', function() { 18 | expect($state.href('dashboard', {})).to.equal('/'); 19 | }); 20 | 21 | it('should map /dashboard route to dashboard View template', function () { 22 | expect($state.get('dashboard').templateUrl).to.equal(view); 23 | }); 24 | 25 | it('of dashboard should work with $state.go', function () { 26 | $state.go('dashboard'); 27 | $rootScope.$apply(); 28 | expect($state.is('dashboard')); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/client/app/xss-search/xss-search.route.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('xss-search routes', function () { 3 | describe('state', function () { 4 | var view = 'app/xss-search/xss-search.html'; 5 | 6 | beforeEach(function() { 7 | module('app.xss-search', bard.fakeToastr); 8 | bard.inject('$httpBackend', '$location', '$rootScope', '$state', '$templateCache'); 9 | }); 10 | 11 | beforeEach(function() { 12 | $templateCache.put(view, ''); 13 | }); 14 | 15 | bard.verifyNoOutstandingHttpRequests(); 16 | 17 | it('should map state xss-search to url /xss-search ', function() { 18 | expect($state.href('xss-search', {})).to.equal('/xss-search'); 19 | }); 20 | 21 | it('should map /xss-search route to xss-search View template', function () { 22 | expect($state.get('xss-search').templateUrl).to.equal(view); 23 | }); 24 | 25 | it('of xss-search should work with $state.go', function () { 26 | $state.go('xss-search'); 27 | $rootScope.$apply(); 28 | expect($state.is('xss-search')); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/client/app/layout/sidebar.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.layout') 6 | .controller('SidebarController', SidebarController); 7 | 8 | SidebarController.$inject = ['$state', 'routerHelper']; 9 | /* @ngInject */ 10 | function SidebarController($state, routerHelper) { 11 | var vm = this; 12 | var states = routerHelper.getStates(); 13 | vm.isCurrent = isCurrent; 14 | 15 | activate(); 16 | 17 | function activate() { getNavRoutes(); } 18 | 19 | function getNavRoutes() { 20 | vm.navRoutes = states.filter(function(r) { 21 | return r.settings && r.settings.nav; 22 | }).sort(function(r1, r2) { 23 | return r1.settings.nav - r2.settings.nav; 24 | }); 25 | } 26 | 27 | function isCurrent(route) { 28 | if (!route.title || !$state.current || !$state.current.title) { 29 | return ''; 30 | } 31 | var menuName = route.title; 32 | return $state.current.title.substr(0, menuName.length) === menuName ? 'current' : ''; 33 | } 34 | } 35 | })(); 36 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/layout/sidebar.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.layout') 6 | .controller('SidebarController', SidebarController); 7 | 8 | SidebarController.$inject = ['$state', 'routerHelper']; 9 | /* @ngInject */ 10 | function SidebarController($state, routerHelper) { 11 | var vm = this; 12 | var states = routerHelper.getStates(); 13 | vm.isCurrent = isCurrent; 14 | 15 | activate(); 16 | 17 | function activate() { getNavRoutes(); } 18 | 19 | function getNavRoutes() { 20 | vm.navRoutes = states.filter(function(r) { 21 | return r.settings && r.settings.nav; 22 | }).sort(function(r1, r2) { 23 | return r1.settings.nav - r2.settings.nav; 24 | }); 25 | } 26 | 27 | function isCurrent(route) { 28 | if (!route.title || !$state.current || !$state.current.title) { 29 | return ''; 30 | } 31 | var menuName = route.title; 32 | return $state.current.title.substr(0, menuName.length) === menuName ? 'current' : ''; 33 | } 34 | } 35 | })(); 36 | -------------------------------------------------------------------------------- /src/client/app/dashboard/dashboard.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |

11 | Welcome to this security demo. The purpose of this application is to demonstrate security vulnerabilities through an application that doesn't implement any mitigation techniques. This particular application is used for demonstrating Cross-Site Scripting (XSS), Cross-Site Request Forgery and Clickjacking vulnerabilities. 12 |

13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
-------------------------------------------------------------------------------- /src/client/app/clickjacking/clickjacking.route.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('clickjacking routes', function () { 3 | describe('state', function () { 4 | var view = 'app/clickjacking/clickjacking.html'; 5 | 6 | beforeEach(function() { 7 | module('app.clickjacking', bard.fakeToastr); 8 | bard.inject('$httpBackend', '$location', '$rootScope', '$state', '$templateCache'); 9 | }); 10 | 11 | beforeEach(function() { 12 | $templateCache.put(view, ''); 13 | }); 14 | 15 | bard.verifyNoOutstandingHttpRequests(); 16 | 17 | it('should map state clickjacking to url /clickjacking ', function() { 18 | expect($state.href('clickjacking', {})).to.equal('/clickjacking'); 19 | }); 20 | 21 | it('should map /clickjacking route to clickjacking View template', function () { 22 | expect($state.get('clickjacking').templateUrl).to.equal(view); 23 | }); 24 | 25 | it('of clickjacking should work with $state.go', function () { 26 | $state.go('clickjacking'); 27 | $rootScope.$apply(); 28 | expect($state.is('clickjacking')); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/client/app/xss-search/xss-search.controller.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('XssSearchController', function() { 3 | var controller; 4 | var people = mockData.getMockPeople(); 5 | 6 | beforeEach(function() { 7 | bard.appModule('app.xss-search'); 8 | bard.inject('$controller', '$log', '$q', '$rootScope', 'dataservice'); 9 | }); 10 | 11 | beforeEach(function () { 12 | sinon.stub(dataservice, 'getPeople').returns($q.when(people)); 13 | controller = $controller('XssSearchController'); 14 | $rootScope.$apply(); 15 | }); 16 | 17 | bard.verifyNoOutstandingHttpRequests(); 18 | 19 | describe('XssSearch controller', function() { 20 | it('should be created successfully', function () { 21 | expect(controller).to.be.defined; 22 | }); 23 | 24 | describe('after activate', function() { 25 | it('should have title of XssSearch', function () { 26 | expect(controller.title).to.equal('XSS Search'); 27 | }); 28 | 29 | it('should have logged "Activated"', function() { 30 | expect($log.info.logs).to.match(/Activated/); 31 | }); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/clickjacking-attack/clickjacking-attack.route.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('clickjacking routes', function () { 3 | describe('state', function () { 4 | var view = 'app/clickjacking-attack/clickjacking-attack.html'; 5 | 6 | beforeEach(function() { 7 | module('app.clickjacking-attack', bard.fakeToastr); 8 | bard.inject('$httpBackend', '$location', '$rootScope', '$state', '$templateCache'); 9 | }); 10 | 11 | beforeEach(function() { 12 | $templateCache.put(view, ''); 13 | }); 14 | 15 | bard.verifyNoOutstandingHttpRequests(); 16 | 17 | it('should map state clickjacking to url / ', function() { 18 | expect($state.href('clickjacking', {})).to.equal('/'); 19 | }); 20 | 21 | it('should map /clickjacking route to clickjacking View template', function () { 22 | expect($state.get('clickjacking').templateUrl).to.equal(view); 23 | }); 24 | 25 | it('of clickjacking should work with $state.go', function () { 26 | $state.go('clickjacking'); 27 | $rootScope.$apply(); 28 | expect($state.is('clickjacking')); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/dashboard/dashboard.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |

11 | Welcome to this security demo. The purpose of this application is to demonstrate how to attack security vulnerabilities through an application that doesn't implement any mitigation techniques. This particular application is used for demonstrating attacks with Cross-Site Scripting (XSS), Cross-Site Request Forgery and Clickjacking vulnerabilities. 12 |

13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
-------------------------------------------------------------------------------- /src/client/app/clickjacking/clickjacking.controller.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('ClickjackingController', function() { 3 | var controller; 4 | var people = mockData.getMockPeople(); 5 | 6 | beforeEach(function() { 7 | bard.appModule('app.clickjacking'); 8 | bard.inject('$controller', '$log', '$q', '$rootScope', 'dataservice'); 9 | }); 10 | 11 | beforeEach(function () { 12 | sinon.stub(dataservice, 'getPeople').returns($q.when(people)); 13 | controller = $controller('ClickjackingController'); 14 | $rootScope.$apply(); 15 | }); 16 | 17 | bard.verifyNoOutstandingHttpRequests(); 18 | 19 | describe('Clickjacking controller', function() { 20 | it('should be created successfully', function () { 21 | expect(controller).to.be.defined; 22 | }); 23 | 24 | describe('after activate', function() { 25 | it('should have title of Clickjacking', function () { 26 | expect(controller.title).to.equal('Clickjacking'); 27 | }); 28 | 29 | it('should have logged "Activated"', function() { 30 | expect($log.info.logs).to.match(/Activated/); 31 | }); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/client/app/csrf/csrf.controller.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('CsrfController', function() { 3 | var controller; 4 | var profile = mockData.getMockProfile(); 5 | 6 | beforeEach(function() { 7 | bard.appModule('app.csrf'); 8 | bard.inject('$controller', '$log', '$q', '$rootScope', 'userservice'); 9 | }); 10 | 11 | beforeEach(function () { 12 | sinon.stub(userservice, 'getProfile').returns($q.when(profile)); 13 | sinon.stub(userservice, 'updateProfile').returns($q.when(profile)); 14 | controller = $controller('CsrfController'); 15 | $rootScope.$apply(); 16 | }); 17 | 18 | bard.verifyNoOutstandingHttpRequests(); 19 | 20 | describe('Csrf controller', function() { 21 | it('should be created successfully', function () { 22 | expect(controller).to.be.defined; 23 | }); 24 | 25 | describe('after activate', function() { 26 | it('should have title of Csrf', function () { 27 | expect(controller.title).to.equal('CSRF'); 28 | }); 29 | 30 | it('should have logged "Activated"', function() { 31 | expect($log.info.logs).to.match(/Activated/); 32 | }); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/csrf-attack/csrf-attack.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
-------------------------------------------------------------------------------- /src/client/app/blocks/logger/logger.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('blocks.logger') 6 | .factory('logger', logger); 7 | 8 | logger.$inject = ['$log', 'toastr']; 9 | 10 | /* @ngInject */ 11 | function logger($log, toastr) { 12 | var service = { 13 | showToasts: true, 14 | 15 | error : error, 16 | info : info, 17 | success : success, 18 | warning : warning, 19 | 20 | // straight to console; bypass toastr 21 | log : $log.log 22 | }; 23 | 24 | return service; 25 | ///////////////////// 26 | 27 | function error(message, data, title) { 28 | toastr.error(message, title); 29 | $log.error('Error: ' + message, data); 30 | } 31 | 32 | function info(message, data, title) { 33 | toastr.info(message, title); 34 | $log.info('Info: ' + message, data); 35 | } 36 | 37 | function success(message, data, title) { 38 | toastr.success(message, title); 39 | $log.info('Success: ' + message, data); 40 | } 41 | 42 | function warning(message, data, title) { 43 | toastr.warning(message, title); 44 | $log.warn('Warning: ' + message, data); 45 | } 46 | } 47 | }()); 48 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/blocks/logger/logger.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('blocks.logger') 6 | .factory('logger', logger); 7 | 8 | logger.$inject = ['$log', 'toastr']; 9 | 10 | /* @ngInject */ 11 | function logger($log, toastr) { 12 | var service = { 13 | showToasts: true, 14 | 15 | error : error, 16 | info : info, 17 | success : success, 18 | warning : warning, 19 | 20 | // straight to console; bypass toastr 21 | log : $log.log 22 | }; 23 | 24 | return service; 25 | ///////////////////// 26 | 27 | function error(message, data, title) { 28 | toastr.error(message, title); 29 | $log.error('Error: ' + message, data); 30 | } 31 | 32 | function info(message, data, title) { 33 | toastr.info(message, title); 34 | $log.info('Info: ' + message, data); 35 | } 36 | 37 | function success(message, data, title) { 38 | toastr.success(message, title); 39 | $log.info('Success: ' + message, data); 40 | } 41 | 42 | function warning(message, data, title) { 43 | toastr.warning(message, title); 44 | $log.warn('Warning: ' + message, data); 45 | } 46 | } 47 | }()); 48 | -------------------------------------------------------------------------------- /src/client/test-helpers/bind-polyfill.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Phantom.js does not support Function.prototype.bind (at least not before v.2.0 3 | * That's just crazy. Everybody supports bind. 4 | * Read about it here: https://groups.google.com/forum/#!msg/phantomjs/r0hPOmnCUpc/uxusqsl2LNoJ 5 | * This polyfill is copied directly from MDN 6 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility 7 | */ 8 | if (!Function.prototype.bind) { 9 | /*jshint freeze: false */ 10 | Function.prototype.bind = function (oThis) { 11 | if (typeof this !== 'function') { 12 | // closest thing possible to the ECMAScript 5 13 | // internal IsCallable function 14 | var msg = 'Function.prototype.bind - what is trying to be bound is not callable'; 15 | throw new TypeError(msg); 16 | } 17 | 18 | var aArgs = Array.prototype.slice.call(arguments, 1), 19 | fToBind = this, 20 | FuncNoOp = function () {}, 21 | fBound = function () { 22 | return fToBind.apply(this instanceof FuncNoOp && oThis ? this : oThis, 23 | aArgs.concat(Array.prototype.slice.call(arguments))); 24 | }; 25 | 26 | FuncNoOp.prototype = this.prototype; 27 | fBound.prototype = new FuncNoOp(); 28 | 29 | return fBound; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "es3": false, 7 | "forin": true, 8 | "freeze": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": "nofunc", 12 | "newcap": true, 13 | "noarg": true, 14 | "noempty": true, 15 | "nonbsp": true, 16 | "nonew": true, 17 | "plusplus": false, 18 | "quotmark": "single", 19 | "undef": true, 20 | "unused": false, 21 | "strict": false, 22 | "maxparams": 10, 23 | "maxdepth": 5, 24 | "maxstatements": 40, 25 | "maxcomplexity": 8, 26 | "maxlen": 120, 27 | 28 | "asi": false, 29 | "boss": false, 30 | "debug": false, 31 | "eqnull": true, 32 | "esnext": false, 33 | "evil": false, 34 | "expr": false, 35 | "funcscope": false, 36 | "globalstrict": false, 37 | "iterator": false, 38 | "lastsemic": false, 39 | "laxbreak": false, 40 | "laxcomma": false, 41 | "loopfunc": true, 42 | "maxerr": 50, 43 | "moz": false, 44 | "multistr": false, 45 | "notypeof": false, 46 | "proto": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "sub": true, 50 | "supernew": false, 51 | "validthis": false, 52 | "noyield": false, 53 | 54 | "browser": true, 55 | "node": true, 56 | 57 | "globals": { 58 | "angular": false 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /attacker-app/src/client/test-helpers/bind-polyfill.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Phantom.js does not support Function.prototype.bind (at least not before v.2.0 3 | * That's just crazy. Everybody supports bind. 4 | * Read about it here: https://groups.google.com/forum/#!msg/phantomjs/r0hPOmnCUpc/uxusqsl2LNoJ 5 | * This polyfill is copied directly from MDN 6 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility 7 | */ 8 | if (!Function.prototype.bind) { 9 | /*jshint freeze: false */ 10 | Function.prototype.bind = function (oThis) { 11 | if (typeof this !== 'function') { 12 | // closest thing possible to the ECMAScript 5 13 | // internal IsCallable function 14 | var msg = 'Function.prototype.bind - what is trying to be bound is not callable'; 15 | throw new TypeError(msg); 16 | } 17 | 18 | var aArgs = Array.prototype.slice.call(arguments, 1), 19 | fToBind = this, 20 | FuncNoOp = function () {}, 21 | fBound = function () { 22 | return fToBind.apply(this instanceof FuncNoOp && oThis ? this : oThis, 23 | aArgs.concat(Array.prototype.slice.call(arguments))); 24 | }; 25 | 26 | FuncNoOp.prototype = this.prototype; 27 | fBound.prototype = new FuncNoOp(); 28 | 29 | return fBound; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /attacker-app/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "es3": false, 7 | "forin": true, 8 | "freeze": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": "nofunc", 12 | "newcap": true, 13 | "noarg": true, 14 | "noempty": true, 15 | "nonbsp": true, 16 | "nonew": true, 17 | "plusplus": false, 18 | "quotmark": "single", 19 | "undef": true, 20 | "unused": false, 21 | "strict": false, 22 | "maxparams": 10, 23 | "maxdepth": 5, 24 | "maxstatements": 40, 25 | "maxcomplexity": 8, 26 | "maxlen": 120, 27 | 28 | "asi": false, 29 | "boss": false, 30 | "debug": false, 31 | "eqnull": true, 32 | "esnext": false, 33 | "evil": false, 34 | "expr": false, 35 | "funcscope": false, 36 | "globalstrict": false, 37 | "iterator": false, 38 | "lastsemic": false, 39 | "laxbreak": false, 40 | "laxcomma": false, 41 | "loopfunc": true, 42 | "maxerr": 50, 43 | "moz": false, 44 | "multistr": false, 45 | "notypeof": false, 46 | "proto": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "sub": true, 50 | "supernew": false, 51 | "validthis": false, 52 | "noyield": false, 53 | 54 | "browser": true, 55 | "node": true, 56 | 57 | "globals": { 58 | "angular": false 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/client/app/xss-search/xss-search.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 |                                 
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
-------------------------------------------------------------------------------- /src/client/app/dashboard/dashboard.controller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.dashboard') 6 | .controller('DashboardController', DashboardController); 7 | 8 | DashboardController.$inject = ['$q', 'dataservice', 'logger']; 9 | /* @ngInject */ 10 | function DashboardController($q, dataservice, logger) { 11 | var vm = this; 12 | vm.news = { 13 | title: 'vulnerable-app', 14 | description: 'Hot Towel Angular is a SPA template for Angular developers.' 15 | }; 16 | vm.messageCount = 0; 17 | vm.people = []; 18 | vm.title = 'Dashboard'; 19 | 20 | activate(); 21 | 22 | function activate() { 23 | var promises = [getMessageCount(), getPeople()]; 24 | return $q.all(promises).then(function() { 25 | logger.info('Activated Dashboard View'); 26 | }); 27 | } 28 | 29 | function getMessageCount() { 30 | return dataservice.getMessageCount().then(function (data) { 31 | vm.messageCount = data; 32 | return vm.messageCount; 33 | }); 34 | } 35 | 36 | function getPeople() { 37 | return dataservice.getPeople().then(function (data) { 38 | vm.people = data; 39 | return vm.people; 40 | }); 41 | } 42 | } 43 | })(); 44 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/dashboard/dashboard.controller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.dashboard') 6 | .controller('DashboardController', DashboardController); 7 | 8 | DashboardController.$inject = ['$q', 'dataservice', 'logger']; 9 | /* @ngInject */ 10 | function DashboardController($q, dataservice, logger) { 11 | var vm = this; 12 | vm.news = { 13 | title: 'attacker-app', 14 | description: 'Hot Towel Angular is a SPA template for Angular developers.' 15 | }; 16 | vm.messageCount = 0; 17 | vm.people = []; 18 | vm.title = 'Dashboard'; 19 | 20 | activate(); 21 | 22 | function activate() { 23 | var promises = [getMessageCount(), getPeople()]; 24 | return $q.all(promises).then(function() { 25 | logger.info('Activated Dashboard View'); 26 | }); 27 | } 28 | 29 | function getMessageCount() { 30 | return dataservice.getMessageCount().then(function (data) { 31 | vm.messageCount = data; 32 | return vm.messageCount; 33 | }); 34 | } 35 | 36 | function getPeople() { 37 | return dataservice.getPeople().then(function (data) { 38 | vm.people = data; 39 | return vm.people; 40 | }); 41 | } 42 | } 43 | })(); 44 | -------------------------------------------------------------------------------- /attacker-app/src/client/test-helpers/mock-data.js: -------------------------------------------------------------------------------- 1 | /* jshint -W079 */ 2 | var mockData = (function() { 3 | return { 4 | getMockPeople: getMockPeople, 5 | getMockStates: getMockStates 6 | }; 7 | 8 | function getMockStates() { 9 | return [ 10 | { 11 | state: 'dashboard', 12 | config: { 13 | url: '/', 14 | templateUrl: 'app/dashboard/dashboard.html', 15 | title: 'dashboard', 16 | settings: { 17 | nav: 1, 18 | content: ' Dashboard' 19 | } 20 | } 21 | } 22 | ]; 23 | } 24 | 25 | function getMockPeople() { 26 | return [ 27 | {firstName: 'John', lastName: 'Papa', age: 25, location: 'Florida'}, 28 | {firstName: 'Ward', lastName: 'Bell', age: 31, location: 'California'}, 29 | {firstName: 'Colleen', lastName: 'Jones', age: 21, location: 'New York'}, 30 | {firstName: 'Madelyn', lastName: 'Green', age: 18, location: 'North Dakota'}, 31 | {firstName: 'Ella', lastName: 'Jobs', age: 18, location: 'South Dakota'}, 32 | {firstName: 'Landon', lastName: 'Gates', age: 11, location: 'South Carolina'}, 33 | {firstName: 'Haley', lastName: 'Guthrie', age: 35, location: 'Wyoming'} 34 | ]; 35 | } 36 | })(); 37 | -------------------------------------------------------------------------------- /src/client/app/core/dataservice.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core') 6 | .factory('dataservice', dataservice); 7 | 8 | dataservice.$inject = ['$http', '$q', 'exception', 'logger']; 9 | /* @ngInject */ 10 | function dataservice($http, $q, exception, logger) { 11 | var service = { 12 | getPeople: getPeople, 13 | getMessageCount: getMessageCount, 14 | search: search 15 | }; 16 | 17 | return service; 18 | 19 | function search(searchTerm) { 20 | return $http.get('/api/search?searchTerm=' + searchTerm) 21 | .then(success) 22 | .catch(fail); 23 | 24 | function success(response) { 25 | return response.data; 26 | } 27 | 28 | function fail(e) { 29 | return exception.catcher('XHR Failed for search')(e); 30 | } 31 | } 32 | 33 | function getMessageCount() { return $q.when(72); } 34 | 35 | function getPeople() { 36 | return $http.get('/api/people') 37 | .then(success) 38 | .catch(fail); 39 | 40 | function success(response) { 41 | return response.data; 42 | } 43 | 44 | function fail(e) { 45 | return exception.catcher('XHR Failed for getPeople')(e); 46 | } 47 | } 48 | } 49 | })(); 50 | -------------------------------------------------------------------------------- /src/client/app/core/404.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
    7 |
  • 8 |
    9 |
    10 | 404Page Not Found 11 |
    12 |
    13 |
  • 14 |
15 |
16 |
17 |
18 |
19 |
21 |
22 |
23 | No soup for you! 24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/core/404.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
    7 |
  • 8 |
    9 |
    10 | 404Page Not Found 11 |
    12 |
    13 |
  • 14 |
15 |
16 |
17 |
18 |
19 |
21 |
22 |
23 | No soup for you! 24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | -------------------------------------------------------------------------------- /src/client/app/xss-search/xss-search.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.xss-search') 6 | .controller('XssSearchController', XssSearchController); 7 | 8 | XssSearchController.$inject = ['$q', '$sanitize', '$sce', 'dataservice', 'logger', '$location', 9 | '$scope', '$timeout']; 10 | /* @ngInject */ 11 | function XssSearchController($q, $sanitize, $sce, dataservice, logger, $location, 12 | $scope, $timeout) { 13 | var vm = this; 14 | vm.title = 'XSS Search'; 15 | vm.search = search; 16 | vm.searchResults = undefined; 17 | 18 | $timeout(function () { 19 | $scope.searchTerm = $location.hash(); 20 | vm.search($scope.searchTerm); 21 | }, 1000); 22 | 23 | activate(); 24 | 25 | function activate() { 26 | logger.info('Activated XSS Search View'); 27 | } 28 | 29 | function search(searchTerm) { 30 | dataservice.search(searchTerm) 31 | .then(function(response) { 32 | // Intentionally trusting as HTML for demonstration purposes 33 | console.log('Search response: ', response); 34 | $location.hash(response); 35 | vm.searchResults = $sce.trustAsHtml(response); 36 | }) 37 | .catch(function(error) { 38 | logger.error(error); 39 | }); 40 | } 41 | } 42 | })(); 43 | -------------------------------------------------------------------------------- /src/client/app/layout/sidebar.controller.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('layout', function() { 3 | describe('sidebar', function() { 4 | var controller; 5 | var views = { 6 | dashboard: 'app/dashboard/dashboard.html', 7 | customers: 'app/customers/customers.html' 8 | }; 9 | 10 | beforeEach(function() { 11 | module('app.layout', bard.fakeToastr); 12 | bard.inject('$controller', '$httpBackend', '$location', 13 | '$rootScope', '$state', 'routerHelper'); 14 | }); 15 | 16 | beforeEach(function() { 17 | routerHelper.configureStates(mockData.getMockStates(), '/'); 18 | controller = $controller('SidebarController'); 19 | $rootScope.$apply(); 20 | }); 21 | 22 | bard.verifyNoOutstandingHttpRequests(); 23 | 24 | it('should have isCurrent() for / to return `current`', function() { 25 | $location.path('/'); 26 | expect(controller.isCurrent($state.current)).to.equal('current'); 27 | }); 28 | 29 | it('should have isCurrent() for /customers to return `current`', function() { 30 | $location.path('/customers'); 31 | expect(controller.isCurrent($state.current)).to.equal('current'); 32 | }); 33 | 34 | it('should have isCurrent() for non route not return `current`', function() { 35 | $location.path('/invalid'); 36 | expect(controller.isCurrent({title: 'invalid'})).not.to.equal('current'); 37 | }); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /attacker-app/src/client/app/layout/sidebar.controller.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint -W117, -W030 */ 2 | describe('layout', function() { 3 | describe('sidebar', function() { 4 | var controller; 5 | var views = { 6 | dashboard: 'app/dashboard/dashboard.html', 7 | customers: 'app/customers/customers.html' 8 | }; 9 | 10 | beforeEach(function() { 11 | module('app.layout', bard.fakeToastr); 12 | bard.inject('$controller', '$httpBackend', '$location', 13 | '$rootScope', '$state', 'routerHelper'); 14 | }); 15 | 16 | beforeEach(function() { 17 | routerHelper.configureStates(mockData.getMockStates(), '/'); 18 | controller = $controller('SidebarController'); 19 | $rootScope.$apply(); 20 | }); 21 | 22 | bard.verifyNoOutstandingHttpRequests(); 23 | 24 | it('should have isCurrent() for / to return `current`', function() { 25 | $location.path('/'); 26 | expect(controller.isCurrent($state.current)).to.equal('current'); 27 | }); 28 | 29 | it('should have isCurrent() for /customers to return `current`', function() { 30 | $location.path('/customers'); 31 | expect(controller.isCurrent($state.current)).to.equal('current'); 32 | }); 33 | 34 | it('should have isCurrent() for non route not return `current`', function() { 35 | $location.path('/invalid'); 36 | expect(controller.isCurrent({title: 'invalid'})).not.to.equal('current'); 37 | }); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/client/app/layout/ht-sidebar.directive.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.layout') 6 | .directive('htSidebar', htSidebar); 7 | 8 | /* @ngInject */ 9 | function htSidebar () { 10 | // Opens and closes the sidebar menu. 11 | // Usage: 12 | //
13 | //
14 | // Creates: 15 | //