XSS Lesson Modifications (#367)
* initial cut on XSS, need to add some tests still * initial unit tests for assignment endpoints * updating header comment license thingy * comment, clean up * Stubs for security unit test * Additional Unit Testing * isEncoded and isNotEncoded Unit Tests added * http-proxies updates * update for XXE solutions * Work-around to handle special chars in action ... currently to be able to match {userId} in hint creation/assignment for IDOR * IDOR hints updated * mitigation content update * mitigation content update ... 2 * Lesson Overview updates * including restart lesson fix for lesson overview
This commit is contained in:
parent
3ec5b8708e
commit
82ef171a50
@ -973,15 +973,8 @@ cookie-container {
|
|||||||
padding-top:2px;
|
padding-top:2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attack-link.solved-true {
|
|
||||||
color:#88FB88;
|
|
||||||
}
|
|
||||||
|
|
||||||
.attack-link.solved-false {
|
.attack-link.solved-false {
|
||||||
color:#f2baba;
|
background-color:#ac2925;
|
||||||
}
|
|
||||||
|
|
||||||
.attack-link.cur-page, .page-link.cur-page {
|
|
||||||
color:#fff;
|
color:#fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -989,6 +982,17 @@ cookie-container {
|
|||||||
color:#eee;
|
color:#eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.attack-link.solved-true {
|
||||||
|
/*color:#88FB88;*/
|
||||||
|
background-color:#247506;
|
||||||
|
color:#fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attack-link.cur-page, .page-link.cur-page {
|
||||||
|
color:#fff;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
.page-link-wrapper {
|
.page-link-wrapper {
|
||||||
display:inline-block;
|
display:inline-block;
|
||||||
}
|
}
|
||||||
|
@ -18,17 +18,13 @@ define(['jquery',
|
|||||||
'goatApp/view/TitleView',
|
'goatApp/view/TitleView',
|
||||||
'goatApp/model/LessonProgressModel',
|
'goatApp/model/LessonProgressModel',
|
||||||
'goatApp/view/LessonProgressView',
|
'goatApp/view/LessonProgressView',
|
||||||
'goatApp/view/LessonOverviewView',
|
'goatApp/view/LessonOverviewView'
|
||||||
'goatApp/model/LessonOverviewModel'
|
|
||||||
],
|
],
|
||||||
function($,
|
function($,
|
||||||
_,
|
_,
|
||||||
Backbone,
|
Backbone,
|
||||||
LessonContentModel,
|
LessonContentModel,
|
||||||
LessonContentView,
|
LessonContentView,
|
||||||
// PlanView,
|
|
||||||
// SourceView,
|
|
||||||
// SolutionView,
|
|
||||||
HintView,
|
HintView,
|
||||||
HelpControlsView,
|
HelpControlsView,
|
||||||
ParamView,
|
ParamView,
|
||||||
@ -41,8 +37,7 @@ define(['jquery',
|
|||||||
TitleView,
|
TitleView,
|
||||||
LessonProgressModel,
|
LessonProgressModel,
|
||||||
LessonProgressView,
|
LessonProgressView,
|
||||||
LessonOverviewView,
|
LessonOverviewView
|
||||||
LessonOverviewModel
|
|
||||||
) {
|
) {
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
@ -50,8 +45,6 @@ define(['jquery',
|
|||||||
this.lessonContent = new LessonContentModel();
|
this.lessonContent = new LessonContentModel();
|
||||||
this.lessonProgressModel = new LessonProgressModel();
|
this.lessonProgressModel = new LessonProgressModel();
|
||||||
this.lessonProgressView = new LessonProgressView(this.lessonProgressModel);
|
this.lessonProgressView = new LessonProgressView(this.lessonProgressModel);
|
||||||
this.lessonOverviewModel = new LessonOverviewModel();
|
|
||||||
this.lessonOverview = new LessonOverviewView(this.lessonOverviewModel);
|
|
||||||
this.lessonContentView = options.lessonContentView;
|
this.lessonContentView = options.lessonContentView;
|
||||||
this.titleView = options.titleView;
|
this.titleView = options.titleView;
|
||||||
this.developerControlsView = new DeveloperControlsView();
|
this.developerControlsView = new DeveloperControlsView();
|
||||||
@ -63,7 +56,6 @@ define(['jquery',
|
|||||||
this.userAndInfoView = new UserAndInfoView();
|
this.userAndInfoView = new UserAndInfoView();
|
||||||
this.menuButtonView = new MenuButtonView();
|
this.menuButtonView = new MenuButtonView();
|
||||||
this.listenTo(this.lessonContentView, 'assignment:complete', this.updateMenu);
|
this.listenTo(this.lessonContentView, 'assignment:complete', this.updateMenu);
|
||||||
this.listenTo(this.lessonContentView, 'assignment:complete', this.updateLessonOverview);
|
|
||||||
this.listenTo(this.lessonContentView, 'endpoints:filtered', this.filterPageHints);
|
this.listenTo(this.lessonContentView, 'endpoints:filtered', this.filterPageHints);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -111,13 +103,11 @@ define(['jquery',
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.listenTo(this.helpControlsView,'hints:show',this.showHints);
|
this.listenTo(this.helpControlsView,'hints:show',this.showHints);
|
||||||
this.listenTo(this.helpControlsView,'lessonOverview:show',this.showLessonOverview)
|
|
||||||
|
|
||||||
this.listenTo(this.helpControlsView,'lesson:restart',this.restartLesson);
|
this.listenTo(this.helpControlsView,'lesson:restart',this.restartLesson);
|
||||||
this.listenTo(this.developerControlsView, 'dev:labels', this.restartLesson);
|
this.listenTo(this.developerControlsView, 'dev:labels', this.restartLesson);
|
||||||
|
|
||||||
this.helpControlsView.render();
|
this.helpControlsView.render();
|
||||||
this.lessonOverview.hideLessonOverview();
|
|
||||||
this.titleView.render(this.lessonInfoModel.get('lessonTitle'));
|
this.titleView.render(this.lessonInfoModel.get('lessonTitle'));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -125,10 +115,6 @@ define(['jquery',
|
|||||||
this.trigger('menu:reload')
|
this.trigger('menu:reload')
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateLessonOverview = function() {
|
|
||||||
this.lessonOverviewModel.fetch();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.onContentLoaded = function(loadHelps) {
|
this.onContentLoaded = function(loadHelps) {
|
||||||
this.lessonInfoModel = new LessonInfoModel();
|
this.lessonInfoModel = new LessonInfoModel();
|
||||||
this.listenTo(this.lessonInfoModel,'info:loaded',this.onInfoLoaded);
|
this.listenTo(this.lessonInfoModel,'info:loaded',this.onInfoLoaded);
|
||||||
@ -198,10 +184,6 @@ define(['jquery',
|
|||||||
this.lessonHintView.render();
|
this.lessonHintView.render();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.showLessonOverview = function() {
|
|
||||||
this.lessonOverviewModel.fetch().then(this.lessonOverview.render());
|
|
||||||
};
|
|
||||||
|
|
||||||
this.restartLesson = function() {
|
this.restartLesson = function() {
|
||||||
var self=this;
|
var self=this;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@ -210,6 +192,7 @@ define(['jquery',
|
|||||||
}).done(function(lessonLink) {
|
}).done(function(lessonLink) {
|
||||||
self.loadLesson(self.name);
|
self.loadLesson(self.name);
|
||||||
self.updateMenu();
|
self.updateMenu();
|
||||||
|
self.callPaginationUpdate();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -218,9 +201,14 @@ define(['jquery',
|
|||||||
this.lessonContentView.showTestParam(param);
|
this.lessonContentView.showTestParam(param);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.callPaginationUpdate = function () {
|
||||||
|
this.lessonContentView.updatePagination();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return Controller;
|
return Controller;
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
define([
|
||||||
|
'backbone'],
|
||||||
|
function(
|
||||||
|
Backbone) {
|
||||||
|
return Backbone.Model.extend({});
|
||||||
|
});
|
@ -0,0 +1,14 @@
|
|||||||
|
define([
|
||||||
|
'backbone',
|
||||||
|
'goatApp/model/AssignmentStatusModel'
|
||||||
|
],
|
||||||
|
function(
|
||||||
|
Backbone,
|
||||||
|
AssignmentStatusModel) {
|
||||||
|
return Backbone.Collection.extend({
|
||||||
|
//tagName: 'ul',
|
||||||
|
url: 'service/lessonoverview.mvc',
|
||||||
|
model: AssignmentStatusModel
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,10 +0,0 @@
|
|||||||
define([
|
|
||||||
'backbone'],
|
|
||||||
function(
|
|
||||||
Backbone) {
|
|
||||||
return Backbone.Collection.extend({
|
|
||||||
//tagName: 'ul',
|
|
||||||
url: 'service/lessonoverview.mvc'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -54,21 +54,24 @@ define(['jquery',
|
|||||||
webgoat.customjs.jquery = $; //passing jquery into custom js scope ... still klunky, but works for now
|
webgoat.customjs.jquery = $; //passing jquery into custom js scope ... still klunky, but works for now
|
||||||
webgoat.customjs.jqueryVuln = $vuln;
|
webgoat.customjs.jqueryVuln = $vuln;
|
||||||
|
|
||||||
// temporary shim to support dom-xss assignment
|
// shim to support xss lesson
|
||||||
webgoat.customjs.phoneHome = function (e) {
|
webgoat.customjs.phoneHome = function (e) {
|
||||||
console.log('phoneHome invoked');
|
console.log('phoneHome invoked');
|
||||||
console.log(arguments.callee);
|
|
||||||
//
|
|
||||||
webgoat.customjs.jquery.ajax({
|
webgoat.customjs.jquery.ajax({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: "/WebGoat/CrossSiteScripting/dom-xss",
|
url: "/WebGoat/CrossSiteScripting/phone-home-xss",
|
||||||
data: {param1: 42, param2: 24},
|
data: {param1: 42, param2: 24},
|
||||||
headers: {
|
headers: {
|
||||||
"webgoat-requested-by": "dom-xss-vuln"
|
"webgoat-requested-by": "dom-xss-vuln"
|
||||||
},
|
},
|
||||||
contentType: 'application/x-www-form-urlencoded; charset=UTF-8'
|
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||||
|
success: function (data) {
|
||||||
|
//devs leave stuff like this in all the time
|
||||||
|
console.log('phone home said ' + data);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize: function () {
|
initialize: function () {
|
||||||
|
@ -34,7 +34,6 @@ function($,_,Backbone) {
|
|||||||
this.$el.find('#show-solution-button').unbind().on('click',_.bind(this.showSolution,this)).show();
|
this.$el.find('#show-solution-button').unbind().on('click',_.bind(this.showSolution,this)).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
//this.$el.find('#show-lesson-overview-button').unbind().on('click', _.bind(this.showLessonOverview, this)).show();
|
|
||||||
this.$el.find('#restart-lesson-button').unbind().on('click',_.bind(this.restartLesson,this)).show();
|
this.$el.find('#restart-lesson-button').unbind().on('click',_.bind(this.restartLesson,this)).show();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -52,9 +51,6 @@ function($,_,Backbone) {
|
|||||||
|
|
||||||
restartLesson: function() {
|
restartLesson: function() {
|
||||||
this.trigger('lesson:restart');
|
this.trigger('lesson:restart');
|
||||||
},
|
|
||||||
showLessonOverview: function() {
|
|
||||||
this.trigger('lessonOverview:show');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -77,7 +77,7 @@ function($,
|
|||||||
filterHint: function(endpoint) {
|
filterHint: function(endpoint) {
|
||||||
var self = this;
|
var self = this;
|
||||||
_.each(this.collection.models, function(hintModel) {
|
_.each(this.collection.models, function(hintModel) {
|
||||||
if (endpoint.indexOf(hintModel.get('assignmentPath')) > -1) {
|
if (endpoint.indexOf(hintModel.get('assignmentPath')) > -1 || decodeURIComponent(endpoint).indexOf(hintModel.get('assignmentPath')) > -1) {
|
||||||
self.hintsToShow.push(hintModel.get('hint'));
|
self.hintsToShow.push(hintModel.get('hint'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -60,6 +60,10 @@ define(['jquery',
|
|||||||
this.paginationControlView = new PaginationControlView(this.$contentPages,this.model.get('lessonUrl'));
|
this.paginationControlView = new PaginationControlView(this.$contentPages,this.model.get('lessonUrl'));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updatePagination: function() {
|
||||||
|
this.paginationControlView.updateCollection();
|
||||||
|
},
|
||||||
|
|
||||||
getCurrentPage: function () {
|
getCurrentPage: function () {
|
||||||
return this.currentPage;
|
return this.currentPage;
|
||||||
},
|
},
|
||||||
@ -120,6 +124,7 @@ define(['jquery',
|
|||||||
markAssignmentComplete: function () {
|
markAssignmentComplete: function () {
|
||||||
this.curForm.reset();
|
this.curForm.reset();
|
||||||
$(this.curForm).siblings('.assignment-success').find('i').removeClass('hidden');
|
$(this.curForm).siblings('.assignment-success').find('i').removeClass('hidden');
|
||||||
|
this.paginationControlView.updateCollection();
|
||||||
},
|
},
|
||||||
|
|
||||||
markAssignmentIncomplete: function () {
|
markAssignmentIncomplete: function () {
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
define(['jquery',
|
define(['jquery',
|
||||||
'underscore',
|
'underscore',
|
||||||
'backbone',
|
'backbone',
|
||||||
'goatApp/model/LessonOverviewModel',
|
'goatApp/model/LessonOverviewCollection',
|
||||||
'text!templates/lesson_overview.html'],
|
'text!templates/lesson_overview.html'],
|
||||||
function($,
|
function($,
|
||||||
_,
|
_,
|
||||||
Backbone,
|
Backbone,
|
||||||
LessonOverviewModel,
|
LessonOverviewCollection,
|
||||||
LessonOverviewTemplate) {
|
LessonOverviewTemplate) {
|
||||||
return Backbone.View.extend({
|
return Backbone.View.extend({
|
||||||
template: LessonOverviewTemplate,
|
template: LessonOverviewTemplate,
|
||||||
el:'#lesson-overview',
|
el:'#lesson-overview',
|
||||||
initialize: function (lessonOverviewModel) {
|
initialize: function (lessonOverviewCollection) {
|
||||||
this.model = lessonOverviewModel;
|
this.collection = lessonOverviewModel;
|
||||||
this.listenTo(this.model, 'change add remove update reset', this.render);
|
this.listenTo(this.collection, 'change add remove update reset', this.render);
|
||||||
this.hideLessonOverview();
|
this.hideLessonOverview();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
define(['jquery',
|
define(['jquery',
|
||||||
'underscore',
|
'underscore',
|
||||||
'backbone',
|
'backbone',
|
||||||
'goatApp/model/LessonOverviewModel',
|
'goatApp/model/LessonOverviewCollection',
|
||||||
'text!templates/paging_controls.html'],
|
'text!templates/paging_controls.html'],
|
||||||
function ($,
|
function ($,
|
||||||
_,
|
_,
|
||||||
Backbone,
|
Backbone,
|
||||||
LessonOverviewModel,
|
LessonOverviewCollection,
|
||||||
PaginationTemplate) {
|
PaginationTemplate) {
|
||||||
return Backbone.View.extend({
|
return Backbone.View.extend({
|
||||||
template: PaginationTemplate,
|
template: PaginationTemplate,
|
||||||
@ -14,24 +14,27 @@ define(['jquery',
|
|||||||
|
|
||||||
initialize: function ($contentPages,baseLessonUrl) {
|
initialize: function ($contentPages,baseLessonUrl) {
|
||||||
this.$contentPages = $contentPages;
|
this.$contentPages = $contentPages;
|
||||||
this.model = new LessonOverviewModel();
|
this.collection = new LessonOverviewCollection();
|
||||||
this.listenTo(this.model, 'change add remove update reset', this.render);
|
this.listenTo(this.collection, 'reset', this.render);
|
||||||
this.numPages = this.$contentPages.length;
|
this.numPages = this.$contentPages.length;
|
||||||
this.baseUrl = baseLessonUrl;
|
this.baseUrl = baseLessonUrl;
|
||||||
|
this.collection.fetch({reset:true});
|
||||||
this.model.fetch();
|
|
||||||
this.initPagination();
|
this.initPagination();
|
||||||
this.render();
|
//this.render();
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function () {
|
render: function (e) {
|
||||||
this.parseLinks();
|
this.parseLinks();
|
||||||
var t = _.template(this.template);
|
var t = _.template(this.template);
|
||||||
this.$el.html(t({'overview':this.lessonOverview}));
|
this.$el.html(t({'overview':this.lessonOverview}));
|
||||||
this.bindNavButtons();
|
this.bindNavButtons();
|
||||||
this.hideShowNavButtons();
|
this.hideShowNavButtons();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateCollection: function() {
|
||||||
|
this.collection.fetch({reset:true});
|
||||||
|
},
|
||||||
|
|
||||||
bindNavButtons: function() {
|
bindNavButtons: function() {
|
||||||
this.$el.find('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').unbind().on('click',this.incrementPageView.bind(this));
|
this.$el.find('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').unbind().on('click',this.incrementPageView.bind(this));
|
||||||
this.$el.find('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-left.show-prev-page').unbind().on('click', this.decrementPageView.bind(this));
|
this.$el.find('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-left.show-prev-page').unbind().on('click', this.decrementPageView.bind(this));
|
||||||
@ -42,17 +45,20 @@ define(['jquery',
|
|||||||
var assignmentCount = this.$contentPages.find('.attack-container');
|
var assignmentCount = this.$contentPages.find('.attack-container');
|
||||||
var solvedMap = {};
|
var solvedMap = {};
|
||||||
var pages = [];
|
var pages = [];
|
||||||
// one pass on solved assignmets
|
|
||||||
_.each(this.model.toJSON(), function(assignment) {
|
_.each(this.collection.models, function(model) {
|
||||||
if (assignment.solved) {
|
//alert (model.get('solved'));
|
||||||
var key = assignment.assignment.path; //.replace(/\//g,'');
|
if (model.get('solved')) {
|
||||||
solvedMap[key] = assignment.assignment.name;
|
var key = model.get('assignment').path.replace(/\//g,'');
|
||||||
}
|
solvedMap[key] = model.get('assignment').name;
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
isAttackSolved = function (path) {
|
isAttackSolved = function (path) {
|
||||||
//strip
|
//strip
|
||||||
var newPath = path.replace(/^\/WebGoat/,'');
|
var newPath = path.replace(/^\/WebGoat/,'');
|
||||||
|
var newPath = newPath.replace(/\//g,'');
|
||||||
if (typeof solvedMap[newPath] !== 'undefined') {
|
if (typeof solvedMap[newPath] !== 'undefined') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -68,7 +74,7 @@ define(['jquery',
|
|||||||
pageClass = 'page-link';
|
pageClass = 'page-link';
|
||||||
pages.push({content:'content',pageClass:pageClass,curPageClass:curPageClass});
|
pages.push({content:'content',pageClass:pageClass,curPageClass:curPageClass});
|
||||||
} else {
|
} else {
|
||||||
var $assignmentForms = $(page).find('.attack-container form');
|
var $assignmentForms = $(page).find('.attack-container form.attack-form');
|
||||||
// use for loop to avoid anonymous function scope hell
|
// use for loop to avoid anonymous function scope hell
|
||||||
//var pageAssignments = {content:'attack',attacks:[]}
|
//var pageAssignments = {content:'attack',attacks:[]}
|
||||||
pageClass = 'attack-link'
|
pageClass = 'attack-link'
|
||||||
@ -87,6 +93,7 @@ define(['jquery',
|
|||||||
pages.push({solvedClass:solvedClass,content:'assignment',curPageClass:curPageClass,pageClass:pageClass});
|
pages.push({solvedClass:solvedClass,content:'assignment',curPageClass:curPageClass,pageClass:pageClass});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//assign to the view
|
//assign to the view
|
||||||
this.lessonOverview = {
|
this.lessonOverview = {
|
||||||
baseUrl: this.baseUrl,
|
baseUrl: this.baseUrl,
|
||||||
@ -134,7 +141,7 @@ define(['jquery',
|
|||||||
this.hideNextPageButton();
|
this.hideNextPageButton();
|
||||||
this.showPrevPageButton;
|
this.showPrevPageButton;
|
||||||
}
|
}
|
||||||
this.render();
|
this.collection.fetch({reset:true});
|
||||||
},
|
},
|
||||||
|
|
||||||
decrementPageView: function() {
|
decrementPageView: function() {
|
||||||
@ -151,7 +158,7 @@ define(['jquery',
|
|||||||
this.hidePrevPageButton();
|
this.hidePrevPageButton();
|
||||||
this.showNextPageButton()
|
this.showNextPageButton()
|
||||||
}
|
}
|
||||||
this.render();
|
this.collection.fetch({reset:true});
|
||||||
},
|
},
|
||||||
|
|
||||||
hideShowNavButtons: function () {
|
hideShowNavButtons: function () {
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author nbaars
|
||||||
|
* @since 4/8/17.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@XmlRootElement
|
||||||
|
public class Comment {
|
||||||
|
private String user;
|
||||||
|
private String dateTime;
|
||||||
|
private String text;
|
||||||
|
}
|
||||||
|
|
@ -17,40 +17,40 @@ import java.io.IOException;
|
|||||||
|
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||||
* please see http://www.owasp.org/
|
* please see http://www.owasp.org/
|
||||||
*
|
*
|
||||||
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||||
* License, or (at your option) any later version.
|
* License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* General Public License for more details.
|
* General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this program; if
|
* You should have received a copy of the GNU General Public License along with this program; if
|
||||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
* 02111-1307, USA.
|
* 02111-1307, USA.
|
||||||
*
|
*
|
||||||
* Getting Source ==============
|
* Getting Source ==============
|
||||||
*
|
*
|
||||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||||
* projects.
|
* projects.
|
||||||
*
|
*
|
||||||
* For details, please see http://webgoat.github.io
|
* For details, please see http://webgoat.github.io
|
||||||
*
|
*
|
||||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||||
* @created October 28, 2003
|
* @created October 28, 2003
|
||||||
*/
|
*/
|
||||||
@AssignmentPath("/CrossSiteScripting/attack5a")
|
@AssignmentPath("/CrossSiteScripting/attack5a")
|
||||||
public class CrossSiteScriptingLesson5a extends AssignmentEndpoint {
|
public class CrossSiteScriptingLesson5a extends AssignmentEndpoint {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
UserSessionData userSessionData;
|
UserSessionData userSessionData;
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET)
|
@RequestMapping(method = RequestMethod.GET)
|
||||||
public @ResponseBody AttackResult completed(@RequestParam Integer QTY1,
|
public @ResponseBody AttackResult completed(@RequestParam Integer QTY1,
|
||||||
@ -58,35 +58,34 @@ public class CrossSiteScriptingLesson5a extends AssignmentEndpoint {
|
|||||||
@RequestParam Integer QTY4, @RequestParam String field1,
|
@RequestParam Integer QTY4, @RequestParam String field1,
|
||||||
@RequestParam Integer field2, HttpServletRequest request)
|
@RequestParam Integer field2, HttpServletRequest request)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// System.out.println("foo");
|
|
||||||
// Should add some QTY validation here. Someone could have fun and enter a negative quantity and get merchanidise and a refund :)
|
|
||||||
double totalSale = QTY1.intValue() * 69.99 + QTY2.intValue() * 27.99 + QTY3.intValue() * 1599.99 + QTY4.intValue() * 299.99;
|
|
||||||
|
|
||||||
userSessionData.setValue("xss-reflected1-complete",(Object)"false");
|
double totalSale = QTY1.intValue() * 69.99 + QTY2.intValue() * 27.99 + QTY3.intValue() * 1599.99 + QTY4.intValue() * 299.99;
|
||||||
StringBuffer cart = new StringBuffer();
|
|
||||||
cart.append("Thank you for shopping at WebGoat. <br />You're support is appreciated<hr />");
|
|
||||||
cart.append("<p>We have chaged credit card:" + field1 + "<br />");
|
|
||||||
cart.append( " ------------------- <br />");
|
|
||||||
cart.append( " $" + totalSale);
|
|
||||||
|
|
||||||
//init state
|
userSessionData.setValue("xss-reflected1-complete",(Object)"false");
|
||||||
if (userSessionData.getValue("xss-reflected1-complete") == null) {
|
StringBuffer cart = new StringBuffer();
|
||||||
userSessionData.setValue("xss-reflected1-complete",(Object)"false");
|
cart.append("Thank you for shopping at WebGoat. <br />You're support is appreciated<hr />");
|
||||||
}
|
cart.append("<p>We have chaged credit card:" + field1 + "<br />");
|
||||||
|
cart.append( " ------------------- <br />");
|
||||||
|
cart.append( " $" + totalSale);
|
||||||
|
|
||||||
if (field1.toLowerCase().contains("<script>alert('my javascript here')</script>")) {
|
//init state
|
||||||
|
if (userSessionData.getValue("xss-reflected1-complete") == null) {
|
||||||
|
userSessionData.setValue("xss-reflected1-complete",(Object)"false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field1.toLowerCase().contains("<script>alert('my javascript here')</script>")) {
|
||||||
//return trackProgress()
|
//return trackProgress()
|
||||||
userSessionData.setValue("xss-reflected-5a-complete","true");
|
userSessionData.setValue("xss-reflected-5a-complete","true");
|
||||||
return trackProgress(success()
|
return trackProgress(success()
|
||||||
.feedback("xss-reflected-5a-success")
|
.feedback("xss-reflected-5a-success")
|
||||||
.output(cart.toString())
|
.output(cart.toString())
|
||||||
.build());
|
.build());
|
||||||
} else {
|
} else {
|
||||||
userSessionData.setValue("xss-reflected1-complete","false");
|
userSessionData.setValue("xss-reflected1-complete","false");
|
||||||
return trackProgress(success()
|
return trackProgress(success()
|
||||||
.feedback("xss-reflected-5a-failure")
|
.feedback("xss-reflected-5a-failure")
|
||||||
.output(cart.toString())
|
.output(cart.toString())
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,40 @@
|
|||||||
|
/***************************************************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||||
|
* please see http://www.owasp.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||||
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program; if
|
||||||
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Getting Source ==============
|
||||||
|
*
|
||||||
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||||
|
* projects.
|
||||||
|
*
|
||||||
|
* For details, please see http://webgoat.github.io
|
||||||
|
*
|
||||||
|
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||||
|
* @created October 28, 2003
|
||||||
|
*/
|
||||||
|
|
||||||
package org.owasp.webgoat.plugin;
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||||
import org.owasp.webgoat.assignments.AttackResult;
|
import org.owasp.webgoat.assignments.AttackResult;
|
||||||
|
import org.owasp.webgoat.session.UserSessionData;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
@ -10,27 +42,27 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by jason on 11/23/16.
|
@AssignmentPath("/CrossSiteScripting/phone-home-xss")
|
||||||
*/
|
|
||||||
@AssignmentPath("/CrossSiteScripting/dom-xss")
|
|
||||||
public class DOMCrossSiteScripting extends AssignmentEndpoint {
|
public class DOMCrossSiteScripting extends AssignmentEndpoint {
|
||||||
@RequestMapping(method = RequestMethod.POST)
|
@RequestMapping(method = RequestMethod.POST)
|
||||||
public @ResponseBody
|
public @ResponseBody
|
||||||
AttackResult completed(@RequestParam Integer param1,
|
AttackResult completed(@RequestParam Integer param1,
|
||||||
@RequestParam Integer param2, HttpServletRequest request) throws IOException {
|
@RequestParam Integer param2, HttpServletRequest request) throws IOException {
|
||||||
|
|
||||||
|
UserSessionData userSessionData = getUserSessionData();
|
||||||
|
SecureRandom number = new SecureRandom();
|
||||||
|
userSessionData.setValue("randValue",number.nextInt());
|
||||||
|
|
||||||
if (param1 == 42 && param2 == 24 && request.getHeader("webgoat-requested-by").equals("dom-xss-vuln")) {
|
if (param1 == 42 && param2 == 24 && request.getHeader("webgoat-requested-by").equals("dom-xss-vuln")) {
|
||||||
System.out.println("DOM-XSS successful, param1 is 42");
|
System.out.println(userSessionData.getValue("randValue") + " << randValue");
|
||||||
return trackProgress(success().build());
|
return trackProgress(success().output("phoneHome Response is " + userSessionData.getValue("randValue").toString()).build());
|
||||||
} else {
|
} else {
|
||||||
return trackProgress(failed().build());
|
return trackProgress(failed().build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// something like ... http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere%3Cscript%3Ewebgoat.customjs.phoneHome();%3C%2Fscript%3E
|
// something like ... http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere%3Cscript%3Ewebgoat.customjs.phoneHome();%3C%2Fscript%3E--andMoreGarbageHere
|
||||||
// or http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere<script>webgoat.customjs.phoneHome();<%2Fscript>
|
// or http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere<script>webgoat.customjs.phoneHome();<%2Fscript>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
|||||||
package org.owasp.webgoat.plugin;
|
|
||||||
|
|
||||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
|
||||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
|
||||||
import org.owasp.webgoat.assignments.AttackResult;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by jason on 11/23/16.
|
|
||||||
*/
|
|
||||||
@AssignmentPath("/CrossSiteScripting/dom-follow-up")
|
|
||||||
public class DOMCrossSiteScriptingFollowUp extends AssignmentEndpoint {
|
|
||||||
@RequestMapping(method = RequestMethod.POST)
|
|
||||||
public @ResponseBody
|
|
||||||
AttackResult completed(@RequestParam String successMessage) throws IOException {
|
|
||||||
if (successMessage.equals("DOM-XSS successful, param1 is 42")) {
|
|
||||||
return trackProgress(success().feedback("xss-dom-message-success").build());
|
|
||||||
} else {
|
|
||||||
return trackProgress(failed().feedback("xss-dom-message-success").build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// something like ... http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere%3Cscript%3Ewebgoat.customjs.phoneHome();%3C%2Fscript%3E
|
|
||||||
// or http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere<script>webgoat.customjs.phoneHome();<%2Fscript>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
|||||||
|
/***************************************************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||||
|
* please see http://www.owasp.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||||
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program; if
|
||||||
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Getting Source ==============
|
||||||
|
*
|
||||||
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||||
|
* projects.
|
||||||
|
*
|
||||||
|
* For details, please see http://webgoat.github.io
|
||||||
|
*
|
||||||
|
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||||
|
* @created October 28, 2003
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||||
|
import org.owasp.webgoat.assignments.AttackResult;
|
||||||
|
import org.owasp.webgoat.session.UserSessionData;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by jason on 11/23/16.
|
||||||
|
*/
|
||||||
|
@AssignmentPath("/CrossSiteScripting/dom-follow-up")
|
||||||
|
public class DOMCrossSiteScriptingVerifier extends AssignmentEndpoint {
|
||||||
|
@RequestMapping(method = RequestMethod.POST)
|
||||||
|
public @ResponseBody
|
||||||
|
AttackResult completed(@RequestParam String successMessage) throws IOException {
|
||||||
|
|
||||||
|
UserSessionData userSessionData = getUserSessionData();
|
||||||
|
|
||||||
|
if (successMessage.equals(userSessionData.getValue("randValue").toString())) {
|
||||||
|
return trackProgress(success().feedback("xss-dom-message-success").build());
|
||||||
|
} else {
|
||||||
|
return trackProgress(failed().feedback("xss-dom-message-failure").build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// something like ... http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere%3Cscript%3Ewebgoat.customjs.phoneHome();%3C%2Fscript%3E
|
||||||
|
// or http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere<script>webgoat.customjs.phoneHome();<%2Fscript>
|
@ -0,0 +1,65 @@
|
|||||||
|
/***************************************************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||||
|
* please see http://www.owasp.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||||
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program; if
|
||||||
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Getting Source ==============
|
||||||
|
*
|
||||||
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||||
|
* projects.
|
||||||
|
*
|
||||||
|
* For details, please see http://webgoat.github.io
|
||||||
|
*
|
||||||
|
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||||
|
* @created October 28, 2003
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||||
|
import org.owasp.webgoat.assignments.AttackResult;
|
||||||
|
import org.owasp.webgoat.session.UserSessionData;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by jason on 11/23/16.
|
||||||
|
*/
|
||||||
|
@AssignmentPath("/CrossSiteScripting/stored-xss-follow-up")
|
||||||
|
public class StoredCrossSiteScriptingVerifier extends AssignmentEndpoint {
|
||||||
|
@RequestMapping(method = RequestMethod.POST)
|
||||||
|
public @ResponseBody
|
||||||
|
AttackResult completed(@RequestParam String successMessage) throws IOException {
|
||||||
|
|
||||||
|
UserSessionData userSessionData = getUserSessionData();
|
||||||
|
|
||||||
|
if (successMessage.equals(userSessionData.getValue("randValue").toString())) {
|
||||||
|
return trackProgress(success().feedback("xss-stored-callback-success").build());
|
||||||
|
} else {
|
||||||
|
return trackProgress(failed().feedback("xss-stored-callback-failure").build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// something like ... http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere%3Cscript%3Ewebgoat.customjs.phoneHome();%3C%2Fscript%3E
|
||||||
|
// or http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere<script>webgoat.customjs.phoneHome();<%2Fscript>
|
@ -0,0 +1,118 @@
|
|||||||
|
/***************************************************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||||
|
* please see http://www.owasp.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||||
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program; if
|
||||||
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Getting Source ==============
|
||||||
|
*
|
||||||
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||||
|
* projects.
|
||||||
|
*
|
||||||
|
* For details, please see http://webgoat.github.io
|
||||||
|
*
|
||||||
|
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||||
|
* @created October 28, 2003
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
|
import com.beust.jcommander.internal.Lists;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.google.common.collect.EvictingQueue;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
import org.joda.time.format.DateTimeFormat;
|
||||||
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||||
|
import org.owasp.webgoat.assignments.AttackResult;
|
||||||
|
import org.owasp.webgoat.session.WebSession;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.owasp.encoder.*;
|
||||||
|
|
||||||
|
import static org.springframework.http.MediaType.ALL_VALUE;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||||
|
|
||||||
|
@AssignmentPath("/CrossSiteScripting/stored-xss")
|
||||||
|
public class StoredXssComments extends AssignmentEndpoint {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebSession webSession;
|
||||||
|
private static DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd, HH:mm:ss");
|
||||||
|
|
||||||
|
private static final Map<String, EvictingQueue<Comment>> userComments = Maps.newHashMap();
|
||||||
|
private static final EvictingQueue<Comment> comments = EvictingQueue.create(100);
|
||||||
|
private static final String phoneHomeString = "<script>webgoat.customjs.phoneHome()</script>";
|
||||||
|
|
||||||
|
static {
|
||||||
|
comments.add(new Comment("secUriTy", DateTime.now().toString(fmt), "<script>console.warn('unit test me')</script>Comment for Unit Testing"));
|
||||||
|
comments.add(new Comment("webgoat", DateTime.now().toString(fmt), "This comment is safe"));
|
||||||
|
comments.add(new Comment("guest", DateTime.now().toString(fmt), "This one is safe too."));
|
||||||
|
comments.add(new Comment("guest", DateTime.now().toString(fmt), "Can you post a comment, calling webgoat.customjs.phoneHome() ?"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(method = GET, produces = MediaType.APPLICATION_JSON_VALUE,consumes = ALL_VALUE)
|
||||||
|
@ResponseBody
|
||||||
|
public Collection<Comment> retrieveComments() {
|
||||||
|
Collection<Comment> allComments = Lists.newArrayList();
|
||||||
|
// no filtering applied here at render
|
||||||
|
allComments.addAll(comments);
|
||||||
|
|
||||||
|
return allComments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(method = RequestMethod.POST)
|
||||||
|
@ResponseBody
|
||||||
|
public AttackResult createNewComment (@RequestBody String commentStr) throws IOException {
|
||||||
|
|
||||||
|
Comment comment = parseJson(commentStr);
|
||||||
|
|
||||||
|
EvictingQueue<Comment> comments = userComments.getOrDefault(webSession.getUserName(), EvictingQueue.create(100));
|
||||||
|
comments.add(comment);
|
||||||
|
comment.setDateTime(DateTime.now().toString(fmt));
|
||||||
|
comment.setUser(webSession.getUserName());
|
||||||
|
|
||||||
|
userComments.put(webSession.getUserName(), comments);
|
||||||
|
|
||||||
|
if (comment.getText().contains(phoneHomeString)) {
|
||||||
|
return (success().feedback("xss-stored-comment-success").build());
|
||||||
|
} else {
|
||||||
|
return (failed().feedback("xss-stored-comment-failure").build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Comment parseJson(String comment) {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
try {
|
||||||
|
return mapper.readValue(comment, Comment.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return new Comment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
|||||||
|
/* Component: Posts */
|
||||||
|
.post .post-heading {
|
||||||
|
height: 95px;
|
||||||
|
padding: 20px 15px;
|
||||||
|
}
|
||||||
|
.post .post-heading .avatar {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
display: block;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
.post .post-heading .meta .title {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.post .post-heading .meta .title a {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.post .post-heading .meta .title a:hover {
|
||||||
|
color: #aaaaaa;
|
||||||
|
}
|
||||||
|
.post .post-heading .meta .time {
|
||||||
|
margin-top: 8px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.post .post-image .image {
|
||||||
|
width:20%;
|
||||||
|
height: 40%;
|
||||||
|
}
|
||||||
|
.post .post-description {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
.post .post-footer {
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
.post .post-footer .input-group-addon a {
|
||||||
|
color: #454545;
|
||||||
|
}
|
||||||
|
.post .post-footer .comments-list {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 20px;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
.post .post-footer .comments-list .comment {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.post .post-footer .comments-list .comment .avatar {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
.post .post-footer .comments-list .comment .comment-heading {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.post .post-footer .comments-list .comment .comment-heading .user {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
display: inline;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.post .post-footer .comments-list .comment .comment-heading .time {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #aaa;
|
||||||
|
margin-top: 0;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.post .post-footer .comments-list .comment .comment-body {
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
.post .post-footer .comments-list .comment > .comments-list {
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
@ -2,368 +2,307 @@
|
|||||||
|
|
||||||
<html xmlns:th="http://www.thymeleaf.org">
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
|
||||||
<div class="lesson-page-wrapper">
|
<div class="lesson-page-wrapper">
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||||
<div class="adoc-content" th:replace="doc:CrossSiteScripting_plan.adoc"></div>
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_plan.adoc"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="lesson-page-wrapper">
|
<div class="lesson-page-wrapper">
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||||
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content1.adoc"></div>
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content1.adoc"></div>
|
||||||
<div class="attack-container">
|
<div class="attack-container">
|
||||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||||
<div id="lessonContent">
|
<div id="lessonContent">
|
||||||
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
||||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/CrossSiteScripting/attack1"
|
action="/WebGoat/CrossSiteScripting/attack1"
|
||||||
enctype="application/json;charset=UTF-8">
|
enctype="application/json;charset=UTF-8">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Were the cookies the same on each tab?</td>
|
<td>Were the cookies the same on each tab?</td>
|
||||||
<td><input name="answer_xss_1" value="" type="TEXT" /></td>
|
<td><input name="answer_xss_1" value="" type="TEXT" /></td>
|
||||||
<td><input
|
<td><input
|
||||||
name="answer" value="Submit" type="SUBMIT"/></td>
|
name="answer" value="Submit" type="SUBMIT"/></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
|
||||||
<div class="attack-feedback"></div>
|
|
||||||
<div class="attack-output"></div>
|
|
||||||
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
||||||
<div class="lesson-page-wrapper">
|
<div class="attack-feedback"></div>
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
<div class="attack-output"></div>
|
||||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
||||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
|
||||||
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content2.adoc"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="lesson-page-wrapper">
|
</div>
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
<div class="lesson-page-wrapper">
|
||||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||||
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content3.adoc"></div>
|
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||||
</div>
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content2.adoc"></div>
|
||||||
<div class="lesson-page-wrapper">
|
</div>
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
<div class="lesson-page-wrapper">
|
||||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||||
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content4.adoc"></div>
|
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||||
</div>
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content3.adoc"></div>
|
||||||
<div class="lesson-page-wrapper">
|
</div>
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
<div class="lesson-page-wrapper">
|
||||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||||
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content5.adoc"></div>
|
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||||
<img align="middle" th:src="@{/images/Reflected-XSS.png}" />
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content4.adoc"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="lesson-page-wrapper">
|
<div class="lesson-page-wrapper">
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||||
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content5a.adoc"></div>
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content5.adoc"></div>
|
||||||
<div class="attack-container">
|
<img align="middle" th:src="@{/images/Reflected-XSS.png}" />
|
||||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
</div>
|
||||||
<div id="lessonContent">
|
<div class="lesson-page-wrapper">
|
||||||
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
|
||||||
method="GET" name="xss-5a"
|
|
||||||
action="/WebGoat/CrossSiteScripting/attack5a"
|
|
||||||
enctype="application/json;charset=UTF-8">
|
|
||||||
<hr width="90%" />
|
|
||||||
<center>
|
|
||||||
<h1>Shopping Cart</h1>
|
|
||||||
</center>
|
|
||||||
<table width="90%" cellspacing="0" cellpadding="2" border="1"
|
|
||||||
align="center">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th width="80%">Shopping Cart Items -- To Buy Now</th>
|
|
||||||
<th width="10%">Price</th>
|
|
||||||
<th width="3%">Quantity</th>
|
|
||||||
<th width="7%">Total</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Studio RTA - Laptop/Reading Cart with Tilting Surface -
|
|
||||||
Cherry</td>
|
|
||||||
<td align="right">69.99</td>
|
|
||||||
<td align="right"><input size="6" value="1" name="QTY1"
|
|
||||||
type="TEXT" /></td>
|
|
||||||
<td>$0.00</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Dynex - Traditional Notebook Case</td>
|
|
||||||
<td align="right">27.99</td>
|
|
||||||
<td align="right"><input size="6" value="1" name="QTY2"
|
|
||||||
type="TEXT" /></td>
|
|
||||||
<td>$0.00</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Hewlett-Packard - Pavilion Notebook with Intel Centrino</td>
|
|
||||||
<td align="right">1599.99</td>
|
|
||||||
<td align="right"><input size="6" value="1" name="QTY3"
|
|
||||||
type="TEXT" /></td>
|
|
||||||
<td>$0.00</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>3 - Year Performance Service Plan $1000 and Over</td>
|
|
||||||
<td align="right">299.99</td>
|
|
||||||
<td align="right"><input size="6" value="1" name="QTY4"
|
|
||||||
type="TEXT" /></td>
|
|
||||||
<td>$0.00</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<br />
|
|
||||||
<table width="90%" cellspacing="0" cellpadding="2" border="0"
|
|
||||||
align="center">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>The total charged to your credit card:</td>
|
|
||||||
<td>$0.00</td>
|
|
||||||
<td><input name="SUBMIT" value="UpdateCart" type="SUBMIT" /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan="2"> </td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Enter your credit card number:</td>
|
|
||||||
<td><input name="field1" value="4128 3214 0002 1999"
|
|
||||||
type="TEXT" /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Enter your three digit access code:</td>
|
|
||||||
<td><input name="field2" value="111" type="TEXT" /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan="2" align="center"><input name="SUBMIT"
|
|
||||||
value="Purchase" type="SUBMIT" /></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<br />
|
|
||||||
<hr width="90%"/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
|
||||||
<div class="attack-feedback"></div>
|
|
||||||
<div class="attack-output"></div>
|
|
||||||
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="lesson-page-wrapper">
|
|
||||||
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content5b.adoc"></div>
|
|
||||||
<div class="attack-container">
|
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
|
||||||
method="POST" name="xss-5b"
|
|
||||||
action="/WebGoat/CrossSiteScripting/attack5b"
|
|
||||||
enctype="application/json;charset=UTF-8">
|
|
||||||
<input size="4" value="" name="isReflectedXSS" type="text" />
|
|
||||||
<input type="submit" name="reflectedXssSubmit" value="Submit"/>
|
|
||||||
</form>
|
|
||||||
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
|
||||||
<div class="attack-feedback"></div>
|
|
||||||
<div class="attack-output"></div>
|
|
||||||
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="lesson-page-wrapper">
|
|
||||||
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content6.adoc"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="lesson-page-wrapper">
|
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
|
||||||
<!-- include content here. Content will be presented via asciidocs files,
|
|
||||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||||
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content6a.adoc"></div>
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content5a.adoc"></div>
|
||||||
<div class="attack-container">
|
<div class="attack-container">
|
||||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
<div id="lessonContent">
|
||||||
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
||||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="DOMTestRoute"
|
method="GET" name="xss-5a"
|
||||||
action="/WebGoat/CrossSiteScripting/attack6a"
|
action="/WebGoat/CrossSiteScripting/attack5a"
|
||||||
enctype="application/json;charset=UTF-8">
|
enctype="application/json;charset=UTF-8">
|
||||||
<input name="DOMTestRoute" value="" type="TEXT" />
|
<hr width="90%" />
|
||||||
<input name="SubmitTestRoute" value="Submit" type="SUBMIT"/>
|
<center>
|
||||||
</form>
|
<h1>Shopping Cart</h1>
|
||||||
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
</center>
|
||||||
<div class="attack-feedback"></div>
|
<table width="90%" cellspacing="0" cellpadding="2" border="1"
|
||||||
<div class="attack-output"></div>
|
align="center">
|
||||||
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th width="80%">Shopping Cart Items -- To Buy Now</th>
|
||||||
|
<th width="10%">Price</th>
|
||||||
|
<th width="3%">Quantity</th>
|
||||||
|
<th width="7%">Total</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Studio RTA - Laptop/Reading Cart with Tilting Surface -
|
||||||
|
Cherry</td>
|
||||||
|
<td align="right">69.99</td>
|
||||||
|
<td align="right"><input size="6" value="1" name="QTY1"
|
||||||
|
type="TEXT" /></td>
|
||||||
|
<td>$0.00</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Dynex - Traditional Notebook Case</td>
|
||||||
|
<td align="right">27.99</td>
|
||||||
|
<td align="right"><input size="6" value="1" name="QTY2"
|
||||||
|
type="TEXT" /></td>
|
||||||
|
<td>$0.00</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Hewlett-Packard - Pavilion Notebook with Intel Centrino</td>
|
||||||
|
<td align="right">1599.99</td>
|
||||||
|
<td align="right"><input size="6" value="1" name="QTY3"
|
||||||
|
type="TEXT" /></td>
|
||||||
|
<td>$0.00</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>3 - Year Performance Service Plan $1000 and Over</td>
|
||||||
|
<td align="right">299.99</td>
|
||||||
|
<td align="right"><input size="6" value="1" name="QTY4"
|
||||||
|
type="TEXT" /></td>
|
||||||
|
<td>$0.00</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<br />
|
||||||
|
<table width="90%" cellspacing="0" cellpadding="2" border="0"
|
||||||
|
align="center">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>The total charged to your credit card:</td>
|
||||||
|
<td>$0.00</td>
|
||||||
|
<td><input name="SUBMIT" value="UpdateCart" type="SUBMIT" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Enter your credit card number:</td>
|
||||||
|
<td><input name="field1" value="4128 3214 0002 1999"
|
||||||
|
type="TEXT" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Enter your three digit access code:</td>
|
||||||
|
<td><input name="field2" value="111" type="TEXT" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" align="center"><input name="SUBMIT"
|
||||||
|
value="Purchase" type="SUBMIT" /></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<br />
|
||||||
|
<hr width="90%"/>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
||||||
|
<div class="attack-feedback"></div>
|
||||||
|
<div class="attack-output"></div>
|
||||||
|
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="lesson-page-wrapper">
|
</div>
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
|
||||||
<!-- include content here. Content will be presented via asciidocs files,
|
|
||||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
|
||||||
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content6b.adoc"></div>
|
|
||||||
<div class="attack-container">
|
|
||||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
|
||||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
|
||||||
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
|
||||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
|
||||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
|
||||||
method="POST" name="DOMFollowUp"
|
|
||||||
action="/WebGoat/CrossSiteScripting/dom-follow-up"
|
|
||||||
enctype="application/json;charset=UTF-8">
|
|
||||||
<input name="successMessage" value="" type="TEXT" />
|
|
||||||
<input name="submitMessage" value="Submit" type="SUBMIT"/>
|
|
||||||
</form>
|
|
||||||
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
|
||||||
<div class="attack-feedback"></div>
|
|
||||||
<div class="attack-output"></div>
|
|
||||||
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content5b.adoc"></div>
|
||||||
|
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
</div>
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content7.adoc"></div>-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content8.adoc"></div>-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content9.adoc"></div>-->
|
|
||||||
<!--<img align="middle" th:src="@{/plugin_lessons/plugin/CrossSiteScripting/images/Reflected-XSS.png}" />-->
|
|
||||||
<!--</div>-->
|
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content6.adoc"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
<div class="lesson-page-wrapper">
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||||
<!--<!– include content here. Content will be presented via asciidocs files,-->
|
<!-- include content here. Content will be presented via asciidocs files,
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||||
<!--<div class="adoc-content"-->
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content6a.adoc"></div>
|
||||||
<!--th:replace="doc:CrossSiteScripting_content9a.adoc"></div>-->
|
<div class="attack-container">
|
||||||
<!--<div class="attack-container">-->
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
<!--<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>-->
|
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||||
<!--<!– using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat –>-->
|
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||||
|
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
||||||
|
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||||
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
|
method="POST" name="DOMTestRoute"
|
||||||
|
action="/WebGoat/CrossSiteScripting/attack6a"
|
||||||
|
enctype="application/json;charset=UTF-8">
|
||||||
|
<input name="DOMTestRoute" value="" type="TEXT" />
|
||||||
|
<input name="SubmitTestRoute" value="Submit" type="SUBMIT"/>
|
||||||
|
</form>
|
||||||
|
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
||||||
|
<div class="attack-feedback"></div>
|
||||||
|
<div class="attack-output"></div>
|
||||||
|
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!--<!– using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat –>-->
|
<div class="lesson-page-wrapper">
|
||||||
<!--<!– you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework –>-->
|
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||||
<!--<!– of course, you can write your own ajax submission /handling in your own javascript if you like –>-->
|
<!-- include content here. Content will be presented via asciidocs files,
|
||||||
<!--<form class="attack-form" accept-charset="UNKNOWN" method="POST"-->
|
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||||
<!--name="form" action="/WebGoat/CrossSiteScripting/attack9a"-->
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content6b.adoc"></div>
|
||||||
<!--enctype="application/json;charset=UTF-8">-->
|
<div class="attack-container">
|
||||||
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
|
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||||
|
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||||
|
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
||||||
|
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||||
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
|
method="POST" name="DOMFollowUp"
|
||||||
|
action="/WebGoat/CrossSiteScripting/dom-follow-up"
|
||||||
|
enctype="application/json;charset=UTF-8">
|
||||||
|
<input name="successMessage" value="" type="TEXT" />
|
||||||
|
<input name="submitMessage" value="Submit" type="SUBMIT"/>
|
||||||
|
</form>
|
||||||
|
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
||||||
|
<div class="attack-feedback"></div>
|
||||||
|
<div class="attack-output"></div>
|
||||||
|
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!--<table cellspacing="0" cellpadding="0" border="0">-->
|
<div class="lesson-page-wrapper">
|
||||||
<!--<tbody>-->
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content7.adoc"></div>
|
||||||
<!--<tr>-->
|
</div>
|
||||||
<!--<td>Title:</td>-->
|
|
||||||
<!--<td><input name="title" value="" type="TEXT" /></td>-->
|
|
||||||
<!--</tr>-->
|
|
||||||
<!--<tr>-->
|
|
||||||
<!--<td valign="TOP">Message:</td>-->
|
|
||||||
<!--<td><textarea cols="60" name="message" rows="5"></textarea></td>-->
|
|
||||||
<!--</tr>-->
|
|
||||||
<!--</tbody>-->
|
|
||||||
<!--</table>-->
|
|
||||||
<!--<p>-->
|
|
||||||
<!--<input name="SUBMIT" value="Submit" type="SUBMIT" />-->
|
|
||||||
<!--</p>-->
|
|
||||||
<!--<hr />-->
|
|
||||||
<!--<hr />-->
|
|
||||||
<!--<h1>Message List</h1>-->
|
|
||||||
<!--<table cellspacing="0" cellpadding="0" border="0">-->
|
|
||||||
<!--<tbody>-->
|
|
||||||
<!--<tr>-->
|
|
||||||
<!--<td><a href="#" style="cursor: hand" link="attack?Num=1"><u></u></a></td>-->
|
|
||||||
<!--</tr>-->
|
|
||||||
<!--</tbody>-->
|
|
||||||
<!--</table>-->
|
|
||||||
<!--</form>-->
|
|
||||||
|
|
||||||
<!--<!– do not remove the two following div's, this is where your feedback/output will land –>-->
|
<div class="lesson-page-wrapper">
|
||||||
<!--<div class="attack-feedback"></div>-->
|
|
||||||
<!--<div class="attack-output"></div>-->
|
|
||||||
<!--<!– ... of course, you can move them if you want to, but that will not look consistent to other lessons –>-->
|
|
||||||
<!--</div>-->
|
|
||||||
<!--</div>-->
|
|
||||||
|
|
||||||
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content7b.adoc"></div>
|
||||||
|
|
||||||
|
<!-- comment area -->
|
||||||
|
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/stored-xss.css}"/>
|
||||||
|
<script th:src="@{/lesson_js/stored-xss.js}" language="JavaScript"></script>
|
||||||
|
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
<div class="container-fluid">
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
<div class="panel post">
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content10.adoc"></div>-->
|
<div class="post-heading">
|
||||||
<!--</div>-->
|
<div class="pull-left image">
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
<img th:src="@{/images/avatar1.png}"
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
class="img-circle avatar" alt="user profile image"/>
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
</div>
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
<div class="pull-left meta">
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content11.adoc"></div>-->
|
<div class="title h5">
|
||||||
<!--</div>-->
|
<a href="#"><b>John Doe</b></a>
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
uploaded a photo.
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
</div>
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
<h6 class="text-muted time">24 days ago</h6>
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
</div>
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content12.adoc"></div>-->
|
</div>
|
||||||
<!--</div>-->
|
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
<div class="post-image">
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
<img th:src="@{images/cat.jpg}" class="image" alt="image post"/>
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
</div>
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content13.adoc"></div>-->
|
<div class="post-description">
|
||||||
<!--</div> -->
|
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
</div>
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
<div class="post-footer">
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
<div class="input-group">
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
<input class="form-control" id="commentInput" placeholder="Add a comment" type="text"/>
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content13a.adoc"></div>-->
|
<span class="input-group-addon">
|
||||||
<!--</div> -->
|
<i id="postComment" class="fa fa-edit" style="font-size: 20px"></i>
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
</span>
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
</div>
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
<ul class="comments-list">
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
<div id="list">
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content14.adoc"></div>-->
|
</div>
|
||||||
<!--</div> -->
|
</ul>
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
</div>
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
</div>
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
</div>
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
<!-- end comments -->
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content15.adoc"></div>-->
|
|
||||||
<!--</div> -->
|
<div class="attack-container">
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
<!-- this will be where they can store the additional comment -->
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content15a.adoc"></div>-->
|
method="POST" name="DOMFollowUp"
|
||||||
<!--</div>-->
|
action="/WebGoat/CrossSiteScripting/stored-xss-follow-up"
|
||||||
|
enctype="application/json;charset=UTF-8">
|
||||||
|
<input name="successMessage" value="" type="TEXT" />
|
||||||
|
<input name="submitMessage" value="Submit" type="SUBMIT"/>
|
||||||
|
</form>
|
||||||
|
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
||||||
|
<div class="attack-feedback"></div>
|
||||||
|
<div class="attack-output"></div>
|
||||||
|
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<!-- overview of XSS defenses -->
|
||||||
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content8.adoc"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<!-- links to OWASP XSS resources mainly -->
|
||||||
|
<div class="adoc-content" th:replace="doc:CrossSiteScripting_content9.adoc"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!--<div class="lesson-page-wrapper">-->
|
|
||||||
<!--<!– reuse this lesson-page-wrapper block for each 'page' of content in your lesson –>-->
|
|
||||||
<!--<!– include content here, or can be placed in another location. Content will be presented via asciidocs files,-->
|
|
||||||
<!--which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc –>-->
|
|
||||||
<!--<div class="adoc-content" th:replace="doc:CrossSiteScripting_content16.adoc"></div>-->
|
|
||||||
<!--</div> -->
|
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -8,5 +8,7 @@ xss-reflected-6a-failure=No, look at the example. Check the GoatRouter.js file.
|
|||||||
xss.lesson1.failure=Are you sure? Try using a tab from a different site.
|
xss.lesson1.failure=Are you sure? Try using a tab from a different site.
|
||||||
xss-dom-message-success=Correct, I hope you didn't cheat, using the console!
|
xss-dom-message-success=Correct, I hope you didn't cheat, using the console!
|
||||||
xss-dom-message-failure=Incorrect, keep trying. It should be obvious in the log when you are successful.
|
xss-dom-message-failure=Incorrect, keep trying. It should be obvious in the log when you are successful.
|
||||||
|
xss-stored-comment-success=It appears your payload should invoke the function. To tell for sure, you need to capture the value and put it in the form below. Then we will really know.
|
||||||
#xss-reflected-5b-do5a-first=Do the reflected xss attack prior to this, then come back and answer this.
|
xss-stored-comment-failure=We can't see the payload in your submission, but XSS can be tricky. Look for the call back fired after the comments reload. If you see that and can put the correct value there and put it in, maybe you did succeed.
|
||||||
|
xss-stored-callback-success=Yes, that is the correct value (note, it will be a different value each time the phoneHome endpoint is called).
|
||||||
|
xss-stored-callback-failure=No, that is not the correct value (note, it will be a different value each time the phoneHome endpoint is called).
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
@ -0,0 +1,45 @@
|
|||||||
|
$(document).ready(function () {
|
||||||
|
$("#postComment").on("click", function () {
|
||||||
|
var commentInput = $("#commentInput").val();
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: 'CrossSiteScripting/stored-xss',
|
||||||
|
data: JSON.stringify({text: commentInput}),
|
||||||
|
contentType: "application/json",
|
||||||
|
dataType: 'json'
|
||||||
|
}).then(
|
||||||
|
function () {
|
||||||
|
getChallenges();
|
||||||
|
$("#commentInput").val('');
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
var html = '<li class="comment">' +
|
||||||
|
'<div class="pull-left">' +
|
||||||
|
'<img class="avatar" src="images/avatar1.png" alt="avatar"/>' +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="comment-body">' +
|
||||||
|
'<div class="comment-heading">' +
|
||||||
|
'<h4 class="user">USER</h4>' +
|
||||||
|
'<h5 class="time">DATETIME</h5>' +
|
||||||
|
'</div>' +
|
||||||
|
'<p>COMMENT</p>' +
|
||||||
|
'</div>' +
|
||||||
|
'</li>';
|
||||||
|
|
||||||
|
getChallenges();
|
||||||
|
|
||||||
|
function getChallenges() {
|
||||||
|
$("#list").empty();
|
||||||
|
$.get('CrossSiteScripting/stored-xss', function (result, status) {
|
||||||
|
for (var i = 0; i < result.length; i++) {
|
||||||
|
var comment = html.replace('USER', result[i].user);
|
||||||
|
comment = comment.replace('DATETIME', result[i].dateTime);
|
||||||
|
comment = comment.replace('COMMENT', result[i].text);
|
||||||
|
$("#list").append(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
@ -1,5 +1,10 @@
|
|||||||
== Was it Really Reflected XSS?
|
== Self XSS or Reflected XSS?
|
||||||
|
|
||||||
You should have been able to execute script with the last example. Was it truly reflected XSS?
|
You should have been able to execute script with the last example. At this point, it would be considered 'self XSS' though.
|
||||||
|
|
||||||
|
Why is that?
|
||||||
|
|
||||||
|
That is because there is no link that would tigger that XSS.
|
||||||
|
You can try it yourself to see what happens ... go to (substitute localhost with your server's name or IP if you need to):
|
||||||
|
|
||||||
|
link: http://localhost:8080/WebGoat/CrossSiteScripting/attack5a?QTY1=1&QTY2=1&QTY3=1&QTY4=1&field1=<script>alert('my javascript here')</script>4128+3214+0002+1999&field2=111
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
== DOM-Based XSS Scenario
|
== Reflected and DOM-Based XSS
|
||||||
|
|
||||||
DOM-based XSS is similar to reflected. The difference is that the payload will never go to the server, but will only ever be processed by the client.
|
DOM-based XSS is another form of reflected XSS. Both are triggered by sending a link with inputs that are reflected to the browser.
|
||||||
|
The difference between DOM and 'traditional' reflected XSS is that, with DOM, the payload will never go to the server. It will only ever be processed by the client.
|
||||||
|
|
||||||
* Attacker sends a malicious URL to victim
|
|
||||||
|
* Attacker sends a malicious URL to victim
|
||||||
* Victim clicks on the link
|
* Victim clicks on the link
|
||||||
* That link may load a malicious web page or a web page they use (are logged into?) that has a vulnerable route/handler
|
* That link may load a malicious web page or a web page they use (are logged into?) that has a vulnerable route/handler
|
||||||
* If it's a malicious web page, it may use it's own JavaScript to attack another page/url with a vulnerable route/handler
|
* If it's a malicious web page, it may use it's own JavaScript to attack another page/url with a vulnerable route/handler
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
== Ientify Potential for DOM-Based XSS
|
== Ientify Potential for DOM-Based XSS
|
||||||
|
|
||||||
For this, you'll want to look for some 'test' code in the route handlers (javascript/backbone). Sometimes, test code gets left in.
|
DOM-Based XSS can usually be found by looking for the route configurations in the client-side code.
|
||||||
(Often times test code is very simple and lacks security or any quality controls!).
|
Look for a route that takes inputs that you can ID being 'reflected' to the page.
|
||||||
|
|
||||||
|
For this example, you'll want to look for some 'test' code in the route handlers (WebGoat uses backbone as its primary javascript library).
|
||||||
|
Sometimes, test code gets left in production (and often times test code is very simple and lacks security or any quality controls!).
|
||||||
|
|
||||||
Your objective is to find the route and exploit it. First though ... what is the base route? As an example, look at the URL for this lesson ...
|
Your objective is to find the route and exploit it. First though ... what is the base route? As an example, look at the URL for this lesson ...
|
||||||
it should look something like /WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/5 (although maybe slightly different). The 'base route' in this case is:
|
it should look something like /WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/5 (although maybe slightly different). The 'base route' in this case is:
|
||||||
*start.mvc#lesson/*
|
*start.mvc#lesson/*
|
||||||
|
|
||||||
The *CrossSiteScripting.lesson/5* after that are parameters that are processed by javascript route handler.
|
The *CrossSiteScripting.lesson/#* after that are parameters that are processed by javascript route handler.
|
||||||
|
|
||||||
So, what is test route for this test code?
|
So, what is test route for this test code?
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
== Try It! DOM-Based XSS
|
== Try It! DOM-Based XSS
|
||||||
|
|
||||||
Some attacks are 'blind'. Fortunately, you have the server running here so you will be able to tell if you are successful. Use the route you just found and see if
|
Some attacks are 'blind'. Fortunately, you have the server running here so you will be able to tell if you are successful.
|
||||||
you can use the fact that it reflects a parameter from the route without encoding to execute an internal function in WebGoat. The function you want to execute is ...
|
Use the route you just found and see if you can use the fact that it reflects a parameter from the route without encoding to execute an internal function in WebGoat.
|
||||||
|
The function you want to execute is ...
|
||||||
|
|
||||||
*webgoat.customjs.phoneHome()*
|
*webgoat.customjs.phoneHome()*
|
||||||
|
|
||||||
Sure, you could just use console/debug to trigger it, but you need to trigger it via a URL in a new tab. Once you complete it, paste the output message from the log below ...
|
Sure, you could just use console/debug to trigger it, but you need to trigger it via a URL in a new tab.
|
||||||
|
|
||||||
|
Once you do trigger it, a subsequent response will come to the browser with a random number. Put that random number in below.
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
== DOM-Based XSS Example
|
||||||
|
|
||||||
|
----
|
||||||
|
<script language="javascript"> function resetVals(form)
|
||||||
|
{
|
||||||
|
var temp = document.URL;
|
||||||
|
var idx = temp.indexOf('login?');
|
||||||
|
var errorMsg = temp.substring(idx+1,temp.length).split('=');
|
||||||
|
if (errorMsg\[1\].indexOf("/login?")!=-1)
|
||||||
|
{
|
||||||
|
var index = errorMsg\[1\].indexOf("/login?");
|
||||||
|
var msg = errorMsg\[1\].substring(index,length-1);
|
||||||
|
errorMsg\[1\] = msg;
|
||||||
|
}
|
||||||
|
document.write('<b>'+errorMsg\[1\]+'</b>');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
----
|
@ -1,18 +1,11 @@
|
|||||||
== DOM-Based XSS Example
|
== Stored XSS
|
||||||
|
Stored cross-site scripting is different in that the payload is persisted (stored) as opposed to passed/injected via a link.
|
||||||
|
|
||||||
----
|
== Stored XSS Scenario
|
||||||
<script language="javascript"> function resetVals(form)
|
* Attacker posts malicious script to a message board
|
||||||
{
|
* Message is stored in a server database
|
||||||
var temp = document.URL;
|
* Victim reads the message
|
||||||
var idx = temp.indexOf('login?');
|
* The malicious script embedded in the message board post executes in the victim’s browser
|
||||||
var errorMsg = temp.substring(idx+1,temp.length).split('=');
|
** The script steals sensitive information, like the session id, and releases it to the attacker
|
||||||
if (errorMsg\[1\].indexOf("/login?")!=-1)
|
|
||||||
{
|
*Victim does not realize attack occurred*
|
||||||
var index = errorMsg\[1\].indexOf("/login?");
|
|
||||||
var msg = errorMsg\[1\].substring(index,length-1);
|
|
||||||
errorMsg\[1\] = msg;
|
|
||||||
}
|
|
||||||
document.write('<b>'+errorMsg\[1\]+'</b>');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
----
|
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
See the comments below.
|
||||||
|
|
||||||
|
Add a comment with a javascript payload. Again ... you want to call the _webgoat.customjs.phoneHome_ function.
|
||||||
|
|
||||||
|
As an attacker (offensive security), keep in mind that most apps are not going to have such a straight-forwardly named compromise.
|
||||||
|
Also, you may have to find a way to load your own javascript dynamically to fully achieve goals of exfiltrating data.
|
@ -0,0 +1,20 @@
|
|||||||
|
== DOM-based XSS Defense
|
||||||
|
|
||||||
|
* Attacker creates url:
|
||||||
|
+
|
||||||
|
----
|
||||||
|
http://mylogin.com/login?error=<script>alert(“xss”)</script>
|
||||||
|
----
|
||||||
|
|
||||||
|
* JavaScript must enforce input validation
|
||||||
|
+
|
||||||
|
----
|
||||||
|
if ( errorMsg\[1\].match(/^[ a-zA-Z0-9:-]$/))
|
||||||
|
{
|
||||||
|
document.write(‘some error’);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
document.write('<b>'+errorMsg\[1\]+'</b>');
|
||||||
|
}
|
||||||
|
----
|
@ -1,20 +1,27 @@
|
|||||||
== DOM-based XSS Defense
|
== XSS Defense
|
||||||
|
|
||||||
* Attacker creates url:
|
|
||||||
+
|
|
||||||
----
|
|
||||||
http://mylogin.com/login?error=<script>alert(“xss”)</script>
|
|
||||||
----
|
|
||||||
|
|
||||||
* JavaScript must enforce input validation
|
=== Why?
|
||||||
+
|
Hopefully we've covered that by now. Bottom line, you don't want someone else's code running in the context of your users and their logged-in seession
|
||||||
----
|
|
||||||
if ( errorMsg\[1\].match(/^[ a-zA-Z0-9:-]$/))
|
=== What to encode?
|
||||||
{
|
The basic premise of defending against XSS is *output endoding* any untrusted input that goes to the screen.
|
||||||
document.write(‘some error’);
|
That may be changing with more sophisticated attacks, but is still the best defense we currently have. *AND* ... *context matters*
|
||||||
}
|
|
||||||
else
|
Another word on 'untrusted input'. If in doubt, treat everything (even data you populated in your DB as untrusted).
|
||||||
{
|
Sometimes data is shared across multiple systems and what you think is your data, may not have been created by you/your team.
|
||||||
document.write('<b>'+errorMsg\[1\]+'</b>');
|
|
||||||
}
|
=== When/Where?
|
||||||
----
|
Encode *as the data is sent to the browser* (not in your persisted data). In the case of *Single Page Apps (SPA's), you will need to encode
|
||||||
|
in the client*. Consult your framework/library for me details, but some resources will be provided on the next page.
|
||||||
|
|
||||||
|
=== How?
|
||||||
|
|
||||||
|
* Encode as HTML Entities in HTML Body
|
||||||
|
* Encode as HTML Entities in HTML Attribute
|
||||||
|
* Encode for Javascript if outputting user input to javascript (but think about that ... you're outputting user input into javascript on your page!!)
|
||||||
|
|
||||||
|
*DO NOT* try to blacklist/negative filter on strings like '<script>' and so forth.
|
||||||
|
|
||||||
|
|
||||||
|
...See the next page for some recommended resources and reading on Defending against XSS
|
@ -0,0 +1,8 @@
|
|||||||
|
== Stored XSS Scenario
|
||||||
|
* Attacker posts malicious script to a message board
|
||||||
|
* Message is stored in a server database
|
||||||
|
* Victim reads the message
|
||||||
|
* The malicious script embedded in the message board post executes in the victim’s browser
|
||||||
|
** The script steals sensitive information, like the session id, and releases it to the attacker
|
||||||
|
|
||||||
|
*Victim does not realize attack occurred*
|
@ -1,8 +1,46 @@
|
|||||||
== Stored XSS Scenario
|
== XSS Defense Resources
|
||||||
* Attacker posts malicious script to a message board
|
|
||||||
* Message is stored in a server database
|
|
||||||
* Victim reads the message
|
|
||||||
* The malicious script embedded in the message board post executes in the victim’s browser
|
|
||||||
** The script steals sensitive information, like the session id, and releases it to the attacker
|
|
||||||
|
|
||||||
*Victim does not realize attack occurred*
|
=== Java OWASP Encoder
|
||||||
|
Do not be bothered by the incubator status on this project, use it if you are doing Java Web Apps and want to defend against XSS, use this
|
||||||
|
link: https://www.owasp.org/index.php/OWASP_Java_Encoder_Project
|
||||||
|
|
||||||
|
=== General XSS prevention Cheat Sheet
|
||||||
|
link: https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
|
||||||
|
|
||||||
|
=== DOM XSS Prevention Cheat Sheet
|
||||||
|
link: https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet
|
||||||
|
|
||||||
|
=== XSS Filter Evasion
|
||||||
|
Good to know your enemy ...
|
||||||
|
link https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
|
||||||
|
|
||||||
|
=== Javascript Framework Specifics
|
||||||
|
|
||||||
|
Encoding in the client can be tricky. Here are somre resources to help with that. If you don't see your framework below (e.g. Ember, React, ???) and would like to contribute or suggest something ...
|
||||||
|
stop by https://github.com/WebGoat/WebGoat and file an issue (preferably with some recommendations/links) or fork and submit a PR.
|
||||||
|
|
||||||
|
==== jQuery
|
||||||
|
be aware if you are using something like ...
|
||||||
|
|
||||||
|
_$selector.html(userInputHere)_,
|
||||||
|
|
||||||
|
...you are in danger. If you want to use that, ensure you are doing someting more like:
|
||||||
|
|
||||||
|
_$selector.html(someEncodeHtmlMethod(userInputHere))_
|
||||||
|
|
||||||
|
OR
|
||||||
|
|
||||||
|
_$selector.*text*(someEncodeHtmlMethod(userInputHere))_
|
||||||
|
|
||||||
|
...if you only want the text of what is output by the user (http://stackoverflow.com/questions/9735045/is-jquery-text-method-xss-safe#9735118)
|
||||||
|
|
||||||
|
==== Backbone.js
|
||||||
|
(One character can make such a difference)
|
||||||
|
|
||||||
|
http://underscorejs.org/#template
|
||||||
|
|
||||||
|
https://nvisium.com/blog/2015/05/21/dont-break-your-backbone-xss-mitigation/
|
||||||
|
|
||||||
|
==== Angular
|
||||||
|
Angular has sought to escape by default, but the expression language has proven to have 'sandbox' escapes. Best to check
|
||||||
|
details of the version you are using and consult starting here: https://docs.angularjs.org/guide/security
|
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||||
|
* please see http://www.owasp.org/
|
||||||
|
* <p>
|
||||||
|
* Copyright (c) 2002 - 2017 Bruce Mayhew
|
||||||
|
* <p>
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
* <p>
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||||
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
* <p>
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program; if
|
||||||
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
* <p>
|
||||||
|
* Getting Source ==============
|
||||||
|
* <p>
|
||||||
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||||
|
* projects.
|
||||||
|
* <p>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
|
import org.hamcrest.CoreMatchers;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentEndpointTest;
|
||||||
|
import org.owasp.webgoat.session.UserSessionData;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class DOMCrossSiteScriptingTest extends AssignmentEndpointTest {
|
||||||
|
private MockMvc mockMvc;
|
||||||
|
private UserSessionData mockUserSessionData;
|
||||||
|
private String randVal = "12034837";
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
DOMCrossSiteScripting domXss = new DOMCrossSiteScripting();
|
||||||
|
init(domXss);
|
||||||
|
this.mockMvc = standaloneSetup(domXss).build();
|
||||||
|
// mocks
|
||||||
|
when(userSessionData.getValue("randValue")).thenReturn(randVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void success() throws Exception {
|
||||||
|
|
||||||
|
mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScripting/phone-home-xss")
|
||||||
|
.header("webgoat-requested-by","dom-xss-vuln")
|
||||||
|
.param("param1", "42")
|
||||||
|
.param("param2", "24"))
|
||||||
|
.andExpect(status().isOk()).andDo(MockMvcResultHandlers.print())
|
||||||
|
.andExpect(jsonPath("$.output", CoreMatchers.containsString("phoneHome Response is " + randVal)))
|
||||||
|
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void failure() throws Exception {
|
||||||
|
|
||||||
|
mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScripting/phone-home-xss")
|
||||||
|
.header("webgoat-requested-by","wrong-value")
|
||||||
|
.param("param1", "22")
|
||||||
|
.param("param2", "20"))
|
||||||
|
.andExpect(status().isOk()).andDo(MockMvcResultHandlers.print())
|
||||||
|
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||||
|
* please see http://www.owasp.org/
|
||||||
|
* <p>
|
||||||
|
* Copyright (c) 2002 - 2017 Bruce Mayhew
|
||||||
|
* <p>
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
* <p>
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||||
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
* <p>
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program; if
|
||||||
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
* <p>
|
||||||
|
* Getting Source ==============
|
||||||
|
* <p>
|
||||||
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||||
|
* projects.
|
||||||
|
* <p>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
|
import org.hamcrest.CoreMatchers;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentEndpointTest;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.ResultActions;
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
|
||||||
|
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class StoredXssCommentsTest extends AssignmentEndpointTest {
|
||||||
|
|
||||||
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
StoredXssComments storedXssComments = new StoredXssComments();
|
||||||
|
init(storedXssComments);
|
||||||
|
this.mockMvc = standaloneSetup(storedXssComments).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void success() throws Exception {
|
||||||
|
ResultActions results = mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScripting/stored-xss")
|
||||||
|
.content("{\"text\":\"someTextHere<script>webgoat.customjs.phoneHome()</script>MoreTextHere\"}")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON));
|
||||||
|
|
||||||
|
results.andExpect(status().isOk());
|
||||||
|
results.andExpect(jsonPath("$.lessonCompleted",CoreMatchers.is(true)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void failure() throws Exception {
|
||||||
|
ResultActions results = mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScripting/stored-xss")
|
||||||
|
.content("{\"text\":\"someTextHere<script>alert('Xss')</script>MoreTextHere\"}")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON));
|
||||||
|
|
||||||
|
results.andExpect(status().isOk());
|
||||||
|
results.andExpect(jsonPath("$.lessonCompleted",CoreMatchers.is(false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For the next two tests there is a comment seeded ...
|
||||||
|
comments.add(new Comment("secUriTy", DateTime.now().toString(fmt), "<script>console.warn('unit test me')</script>Comment for Unit Testing"));
|
||||||
|
... the isEncoded method will remain commented out as it will fail (because WebGoat isn't supposed to be secure)
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Ensures it is vulnerable
|
||||||
|
@Test
|
||||||
|
public void isNotEncoded() throws Exception {
|
||||||
|
//do get to get comments after posting xss payload
|
||||||
|
ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScripting/stored-xss"));
|
||||||
|
taintedResults.andExpect(jsonPath("$[0].text",CoreMatchers.is(CoreMatchers.containsString("<script>console.warn('unit test me')</script>"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Could be used to test an encoding solution ... commented out so build will pass. Uncommenting will fail build, but leaving in as positive Security Unit Test
|
||||||
|
// @Test
|
||||||
|
// public void isEncoded() throws Exception {
|
||||||
|
// //do get to get comments after posting xss payload
|
||||||
|
// ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScripting/stored-xss"));
|
||||||
|
// taintedResults.andExpect(jsonPath("$[0].text",CoreMatchers.is(CoreMatchers.containsString("<scriptgt;"))));
|
||||||
|
// }
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 17 KiB |
Binary file not shown.
After Width: | Height: | Size: 186 KiB |
@ -17,3 +17,19 @@ When ZAP starts, you will be presented with a dialog such as the one below ...
|
|||||||
|
|
||||||
image::images/zap-start.png[ZAP Start,548,256,style="lesson-image"]
|
image::images/zap-start.png[ZAP Start,548,256,style="lesson-image"]
|
||||||
|
|
||||||
|
=== Set ZAP's port (if running WebGoat locally)
|
||||||
|
|
||||||
|
*NOTE*: The following proxy set up is only needed if you are running WebGoat locally. If it's on a remote server, or you are running on
|
||||||
|
WebGoat (or any application) that is not using port 8080 locally, you can leave ZAP at it's default. and use 8080, instead of
|
||||||
|
8090 when setting up your browser to proxy (next page).
|
||||||
|
|
||||||
|
If you are setting up ZAP while running WebGoat locally ...
|
||||||
|
|
||||||
|
* Open ZAP
|
||||||
|
* Go to Tools >> Options in the menu
|
||||||
|
* Select 'Local Proxy' on the left
|
||||||
|
* Input 8090 for the 'Port'
|
||||||
|
|
||||||
|
*Remember*: If you are not running WebGoat locally, leave this setting along, skip to the next page and use 8080 instead of 8090
|
||||||
|
|
||||||
|
image::images/zap-local-proxy-8090.png[ZAP Proxy Config,750,587,style="lesson-image"]
|
@ -11,7 +11,7 @@ This will send all of your traffic to the proxy. Since we haven't set up a trust
|
|||||||
. Click _Settings_
|
. Click _Settings_
|
||||||
. Select _Manual proxy configuration_
|
. Select _Manual proxy configuration_
|
||||||
.. input *127.0.0.1* as the Proxy
|
.. input *127.0.0.1* as the Proxy
|
||||||
.. input *8080* as the port
|
.. input *8090* as the port if running WebGoat locally and you updated ZAP to 8090 (otherwise, use *8080*)
|
||||||
.. check the _Use this proxy server for all protocols_ checkbox
|
.. check the _Use this proxy server for all protocols_ checkbox
|
||||||
|
|
||||||
image::images/firefox-proxy-config.png[Firefox Proxy Config,510,634,style="lesson-image"]
|
image::images/firefox-proxy-config.png[Firefox Proxy Config,510,634,style="lesson-image"]
|
||||||
@ -23,7 +23,7 @@ image::images/firefox-proxy-config.png[Firefox Proxy Config,510,634,style="lesso
|
|||||||
. Click the _Change proxy settings_ button
|
. Click the _Change proxy settings_ button
|
||||||
. Select the _proxies_ tab
|
. Select the _proxies_ tab
|
||||||
. Select Web Proxy (HTTP)
|
. Select Web Proxy (HTTP)
|
||||||
. Input 127.0.0.1 in the first box under _Web Proxy Server_ and your port # (8080 is what used earlier) in the second box (to the right)
|
. Input 127.0.0.1 in the first box under _Web Proxy Server_ and your port # (8090 if running WebGoat locally, otherwise 8080) in the second box (to the right)
|
||||||
. You may also want to clear the _Bypass proxy settings for these Hosts & Domains_ text input at the bottom, but shouldn't need to
|
. You may also want to clear the _Bypass proxy settings for these Hosts & Domains_ text input at the bottom, but shouldn't need to
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +37,8 @@ image::images/chrome-manual-proxy-win.png[Chrome Proxy, 394,346,style="lesson-im
|
|||||||
|
|
||||||
(Win config image above)
|
(Win config image above)
|
||||||
|
|
||||||
|
*Remember*: If running WebGoat locally, you can use ZAP's default port of 8080 instead of 8090 (or whatever number you prefer to use)
|
||||||
|
|
||||||
=== Other Proxy Configuration Options
|
=== Other Proxy Configuration Options
|
||||||
|
|
||||||
If you don't want to manage the proxy manually, there are extensions or plugins that can help you to do so without digging through as much config,
|
If you don't want to manage the proxy manually, there are extensions or plugins that can help you to do so without digging through as much config,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.owasp.webgoat.plugin;
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||||
import org.owasp.webgoat.assignments.AttackResult;
|
import org.owasp.webgoat.assignments.AttackResult;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@ -42,6 +43,7 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@AssignmentPath("IDOR/diff-attributes")
|
@AssignmentPath("IDOR/diff-attributes")
|
||||||
|
@AssignmentHints({"idor.hints.idorDiffAttributes1","idor.hints.idorDiffAttributes2","idor.hints.idorDiffAttributes3"})
|
||||||
public class IDORDiffAttributes extends AssignmentEndpoint {
|
public class IDORDiffAttributes extends AssignmentEndpoint {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST)
|
@RequestMapping(method = RequestMethod.POST)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.owasp.webgoat.plugin;
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||||
import org.owasp.webgoat.assignments.AttackResult;
|
import org.owasp.webgoat.assignments.AttackResult;
|
||||||
import org.owasp.webgoat.session.UserSessionData;
|
import org.owasp.webgoat.session.UserSessionData;
|
||||||
@ -38,6 +39,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@AssignmentPath("IDOR/profile/{userId}")
|
@AssignmentPath("IDOR/profile/{userId}")
|
||||||
|
@AssignmentHints({"idor.hints.otherProfile1","idor.hints.otherProfile2","idor.hints.otherProfile3","idor.hints.otherProfile4","idor.hints.otherProfile5","idor.hints.otherProfile6","idor.hints.otherProfile7","idor.hints.otherProfile8","idor.hints.otherProfile9"})
|
||||||
public class IDOREditOtherProfiile extends AssignmentEndpoint {
|
public class IDOREditOtherProfiile extends AssignmentEndpoint {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -2,6 +2,7 @@ package org.owasp.webgoat.plugin;
|
|||||||
|
|
||||||
|
|
||||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||||
import org.owasp.webgoat.assignments.AttackResult;
|
import org.owasp.webgoat.assignments.AttackResult;
|
||||||
import org.owasp.webgoat.session.UserSessionData;
|
import org.owasp.webgoat.session.UserSessionData;
|
||||||
@ -46,6 +47,7 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@AssignmentPath("IDOR/profile/{userId}")
|
@AssignmentPath("IDOR/profile/{userId}")
|
||||||
|
@AssignmentHints({"idor.hints.otherProfile1","idor.hints.otherProfile2","idor.hints.otherProfile3","idor.hints.otherProfile4","idor.hints.otherProfile5","idor.hints.otherProfile6","idor.hints.otherProfile7","idor.hints.otherProfile8","idor.hints.otherProfile9"})
|
||||||
public class IDORViewOtherProfile extends AssignmentEndpoint{
|
public class IDORViewOtherProfile extends AssignmentEndpoint{
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -2,6 +2,7 @@ package org.owasp.webgoat.plugin;
|
|||||||
|
|
||||||
|
|
||||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||||
import org.owasp.webgoat.assignments.AttackResult;
|
import org.owasp.webgoat.assignments.AttackResult;
|
||||||
import org.owasp.webgoat.session.UserSessionData;
|
import org.owasp.webgoat.session.UserSessionData;
|
||||||
@ -46,6 +47,7 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@AssignmentPath("IDOR/profile/alt-path")
|
@AssignmentPath("IDOR/profile/alt-path")
|
||||||
|
@AssignmentHints({"idor.hints.ownProfileAltUrl1","idor.hints.ownProfileAltUrl2","idor.hints.ownProfileAltUrl3"})
|
||||||
public class IDORViewOwnProfileAltUrl extends AssignmentEndpoint{
|
public class IDORViewOwnProfileAltUrl extends AssignmentEndpoint{
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -1,64 +1,66 @@
|
|||||||
package org.owasp.webgoat.plugin;
|
//package org.owasp.webgoat.plugin;
|
||||||
|
//
|
||||||
import com.google.common.collect.Lists;
|
//import com.google.common.collect.Lists;
|
||||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
//import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
//import org.owasp.webgoat.assignments.AssignmentHints;
|
||||||
import org.owasp.webgoat.assignments.AttackResult;
|
//import org.owasp.webgoat.assignments.AssignmentPath;
|
||||||
import org.owasp.webgoat.session.UserSessionData;
|
//import org.owasp.webgoat.assignments.AttackResult;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
//import org.owasp.webgoat.session.UserSessionData;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
//import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
//import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
//import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
//import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import javax.servlet.ServletException;
|
//
|
||||||
import javax.servlet.http.HttpServletRequest;
|
//import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
//import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
//import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.HashMap;
|
//import java.io.IOException;
|
||||||
import java.util.List;
|
//import java.util.HashMap;
|
||||||
import java.util.Map;
|
//import java.util.List;
|
||||||
|
//import java.util.Map;
|
||||||
/**
|
//
|
||||||
* Created by jason on 1/5/17.
|
///**
|
||||||
*/
|
// * Created by jason on 1/5/17.
|
||||||
|
// */
|
||||||
@AssignmentPath("/IDOR/viewprofile/{id}")
|
//
|
||||||
public class ViewOtherUserProfile extends AssignmentEndpoint {
|
//@AssignmentPath("/IDOR/viewprofile/{id}")
|
||||||
|
//@AssignmentHints({"idor.hints.otherProfile1","idor.hints.otherProfile2","idor.hints.otherProfile3"})
|
||||||
private String color;
|
//public class ViewOtherUserProfile extends AssignmentEndpoint {
|
||||||
private String size;
|
//
|
||||||
private boolean isAdmin;
|
// private String color;
|
||||||
|
// private String size;
|
||||||
@Autowired
|
// private boolean isAdmin;
|
||||||
UserSessionData userSessionData;
|
//
|
||||||
|
// @Autowired
|
||||||
@RequestMapping(produces = {"application/json"})
|
// UserSessionData userSessionData;
|
||||||
public @ResponseBody
|
//
|
||||||
AttackResult completed(@PathVariable String userId, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
// @RequestMapping(produces = {"application/json"})
|
||||||
List json = Lists.newArrayList();
|
// public @ResponseBody
|
||||||
// can be re-used
|
// AttackResult completed(@PathVariable String userId, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
Map<String, Object> errorMap = new HashMap();
|
// List json = Lists.newArrayList();
|
||||||
errorMap.put("error","not logged in, go back and log in first");
|
// // can be re-used
|
||||||
|
// Map<String, Object> errorMap = new HashMap();
|
||||||
if (userSessionData.getValue("idor-authenticated-as") == null) {
|
// errorMap.put("error","not logged in, go back and log in first");
|
||||||
json.add(errorMap);
|
//
|
||||||
return trackProgress(failed().feedback("idor.view.other.profile.failure1").build());
|
// if (userSessionData.getValue("idor-authenticated-as") == null) {
|
||||||
} else {
|
// json.add(errorMap);
|
||||||
if (userSessionData.getValue("idor-authenticated-as").equals("bill") || userSessionData.getValue("idor-authenticated-as").equals("tom")) {
|
// return trackProgress(failed().feedback("idor.view.other.profile.failure1").build());
|
||||||
System.out.println("**** authenticated as " + userSessionData.getValue("idor-authenticated-as"));
|
// } else {
|
||||||
//logged in
|
// if (userSessionData.getValue("idor-authenticated-as").equals("bill") || userSessionData.getValue("idor-authenticated-as").equals("tom")) {
|
||||||
String authUserId = (String)userSessionData.getValue("idor-authenticated-user-id");
|
// System.out.println("**** authenticated as " + userSessionData.getValue("idor-authenticated-as"));
|
||||||
//secure code would check to make sure authUserId matches userId or some similar access control
|
// //logged in
|
||||||
// ... and in this endpoint, we won't bother with that
|
// String authUserId = (String)userSessionData.getValue("idor-authenticated-user-id");
|
||||||
UserProfile userProfile = new UserProfile(userId);
|
// //secure code would check to make sure authUserId matches userId or some similar access control
|
||||||
return trackProgress(failed().feedback("idor.view.other.profile.failure2").build());
|
// // ... and in this endpoint, we won't bother with that
|
||||||
}
|
// UserProfile userProfile = new UserProfile(userId);
|
||||||
}
|
// return trackProgress(failed().feedback("idor.view.other.profile.failure2").build());
|
||||||
// else
|
// }
|
||||||
return trackProgress(failed().build());
|
// }
|
||||||
}
|
// // else
|
||||||
|
// return trackProgress(failed().build());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
}
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
@ -138,7 +138,7 @@
|
|||||||
<!-- modify the action to point to the intended endpoint -->
|
<!-- modify the action to point to the intended endpoint -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" id="view-other"
|
<form class="attack-form" accept-charset="UNKNOWN" id="view-other"
|
||||||
method="GET" name="view-other-profile"
|
method="GET" name="view-other-profile"
|
||||||
action="/WebGoat/IDOR/profile"
|
action="/WebGoat/IDOR/profile/{userId}"
|
||||||
enctype="application/json;charset=UTF-8">
|
enctype="application/json;charset=UTF-8">
|
||||||
<script th:src="@{/lesson_js/idor.js}" />
|
<script th:src="@{/lesson_js/idor.js}" />
|
||||||
|
|
||||||
@ -163,7 +163,7 @@
|
|||||||
<!-- modify the action to point to the intended endpoint -->
|
<!-- modify the action to point to the intended endpoint -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" id="edit-other"
|
<form class="attack-form" accept-charset="UNKNOWN" id="edit-other"
|
||||||
method="GET" name="edit-other-profile"
|
method="GET" name="edit-other-profile"
|
||||||
action="/WebGoat/IDOR/profile"
|
action="/WebGoat/IDOR/profile/{userId}"
|
||||||
enctype="application/json;charset=UTF-8">
|
enctype="application/json;charset=UTF-8">
|
||||||
<script th:src="@{/lesson_js/idor.js}" />
|
<script th:src="@{/lesson_js/idor.js}" />
|
||||||
|
|
||||||
|
@ -1,7 +1,24 @@
|
|||||||
idor.title=Insecure Direct Object References
|
idor.title=Insecure Direct Object References
|
||||||
|
|
||||||
idor.hints.idor_login=Log in first
|
idor.hints.idor_login=Log in first. User Name is tom, password is cat.
|
||||||
|
|
||||||
|
idor.hints.idorDiffAttributes1=Make sure you have logged in on the previous step/page
|
||||||
|
idor.hints.idorDiffAttributes2=View the response using developer tools or a proxy.
|
||||||
|
idor.hints.idorDiffAttributes3=The attributes are not visible and have nothing to do with size, color or name
|
||||||
|
|
||||||
|
idor.hints.ownProfileAltUrl1=Look at the previous request for profile, this is similar
|
||||||
|
idor.hints.ownProfileAltUrl2=You will need data from the previous request for your own profile
|
||||||
|
idor.hints.ownProfileAltUrl3=Append your id to the previous request (i.e. .../profile/{yourId})
|
||||||
|
|
||||||
|
idor.hints.otherProfile1=The default request here won't work at all, so you will need to manually craft the request or tamper it with a proxy
|
||||||
|
idor.hints.otherProfile2=You will likely need to 'fuzz' to try different values for the userId at the end of the Url
|
||||||
|
idor.hints.otherProfile3=Try incrementing the id value. It's not a simple +1, but it's also not too far off
|
||||||
|
idor.hints.otherProfile4=For editing the other user's profile, you will need to use the proxy or manually craft the request again
|
||||||
|
idor.hints.otherProfile5=To edit the other user's profile, you will use the same Url you did to view the other user's profile
|
||||||
|
idor.hints.otherProfile6=To edit, You will need to change the method, what is the RESTful method used for 'update' or 'edit'?
|
||||||
|
idor.hints.otherProfile7=You will also need the body of the request (will look something like the profile)
|
||||||
|
idor.hints.otherProfile8=The request should go to ... /WebGoat/IDOR/profile/{Buffalo Bills Id}
|
||||||
|
idor.hints.otherProfile9={\"role\" : 1,\"color\" : \"red\",\"size\" : \"small\",\"name\" : \"Tom Cat\",\"userId\" : \"2342388\"}
|
||||||
|
|
||||||
idor.diff.attributes.missing=You did not list two attributes, comma delimited
|
idor.diff.attributes.missing=You did not list two attributes, comma delimited
|
||||||
idor.diff.success=Correct, the two attributes not displayed are userId & role. Keep those in mind
|
idor.diff.success=Correct, the two attributes not displayed are userId & role. Keep those in mind
|
||||||
|
@ -1,10 +1,58 @@
|
|||||||
== Secure Object References
|
== Secure Object References
|
||||||
|
|
||||||
|
=== Start with the end in mind
|
||||||
|
Do you have your access control documented? If you don't, how can you enforce it? Access control is defined
|
||||||
|
by the business logic that guides the application and/or privacy and other laws.
|
||||||
|
|
||||||
|
==== Horizontal and Vertical Access Control
|
||||||
|
Often times we think of access control in terms of 'roles' (user, power-user, admin, etc.).
|
||||||
|
However, as noted in the previous exercises, users with the same 'role' can access each other's data. This is
|
||||||
|
horizontal access control. Both should be enforced.
|
||||||
|
|
||||||
|
.Access Control Matrix Example
|
||||||
|
|===
|
||||||
|
|Endpoint | Method | Description | Roles, Access Rules | Notes, Caveats
|
||||||
|
|
||||||
|
| /profile
|
||||||
|
| GET
|
||||||
|
| view user profile
|
||||||
|
| Logged in User, can only view their own role
|
||||||
|
| Admin roles must use diff Url to view others' profiles (see below)
|
||||||
|
|
||||||
|
| /profile/{id}
|
||||||
|
| GET
|
||||||
|
| view user profile of a given user
|
||||||
|
| Logged in User can view their own profile by {id}, admins can also view
|
||||||
|
| n/a
|
||||||
|
|
||||||
|
| /profile/{id}
|
||||||
|
| PUT
|
||||||
|
| edit user profile. profile object submitted from client with request
|
||||||
|
| Logged in User can edit their own profile by {id}, admins can also edit.
|
||||||
|
| Admin edit must be logged
|
||||||
|
|===
|
||||||
|
|
||||||
|
==== Audit Access
|
||||||
|
As displayed in the above example, your access control rules should include provisions of what access is logged.
|
||||||
|
For example, if a super-user or admin can edit other's profiles ... That is something that should be logged. Other
|
||||||
|
examples would include detected violations or attempts to violate access control mechanisms.
|
||||||
|
|
||||||
=== Using Indrect References
|
=== Using Indrect References
|
||||||
In some cases, using an indirect reference may help. This of course may make the application harder to trouble shoot and may also affect performance.
|
Not many applications employ it, but you can use *indirect* refrences. In this case you can run your references across a hahsing,
|
||||||
|
encoding or other function on the server so that the id that the client sees is not the actual reference
|
||||||
|
which the server handles. This will reduce efficiency some (a common trade-off for security) and is still subject to being
|
||||||
|
guessed, brute-forced or reverse engineered.
|
||||||
|
|
||||||
=== Access Controls
|
This approach should not be the only protection used. It can be used as an additional layer. Your server must
|
||||||
Since the root of 'Insecure' of IDOR's s really in controlling access to the objects referenced, the key to making them secure is implementing vertical and horizontal access control.
|
implement the logic of mapping client (indirect) to server (direct) references.
|
||||||
|
|
||||||
==== Knowing How Things Should be Secured
|
=== Access Control & APIs
|
||||||
|
Many time, APIs or RESTFul endpoints rely on obscurity , a static 'key', or lack of imagination on the user's part to control access.
|
||||||
|
Good options such as digitally signed JSON Web Tokens (https://jwt.io) are a good option for API authentication & access control using a
|
||||||
|
combination of the claims and a digital/cryptographic signature to validate the consumer. Other emerging standards such as
|
||||||
|
Secure Token Binding promise a 'cryptographic state' for web services in the request headers ...
|
||||||
|
https://tools.ietf.org/html/draft-ietf-tokbind-protocol-10
|
||||||
|
|
||||||
|
https://tools.ietf.org/html/draft-ietf-tokbind-negotiation-05
|
||||||
|
|
||||||
|
https://tools.ietf.org/html/draft-ietf-tokbind-https-06
|
||||||
|
@ -3,6 +3,9 @@ Basic
|
|||||||
Smith - to show it returns smith's records
|
Smith - to show it returns smith's records
|
||||||
Smith' or '1'='1 - to show exploit; 1=1 can be any true clause
|
Smith' or '1'='1 - to show exploit; 1=1 can be any true clause
|
||||||
|
|
||||||
|
**Bender Login
|
||||||
|
bender@juice-sh.op' --
|
||||||
|
|
||||||
[2:19 PM]
|
[2:19 PM]
|
||||||
101
|
101
|
||||||
101 or 1=1
|
101 or 1=1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user