Compare commits

..

25 Commits

Author SHA1 Message Date
d3ee9431d8 Tagging latest Docker build with Travis as well 2017-12-30 14:13:34 +01:00
4811a9d563 Removed Mongodb, so we do not have issues with downloading the embedded Mongodb. Moved back to JPA and use HSQLDB for storing user information.
WebWolf now has its own user management (will move to separate Github repo)
2017-12-29 22:20:52 +01:00
c6e86861fe Removed Mongodb, so we do not have issues with downloading the embedded Mongodb. Moved back to JPA and use HSQLDB for storing user information. 2017-12-29 22:12:21 +01:00
b64aa43760 Updated bootstrap script to use webgoat-server for starting spring-boot 2017-12-28 00:27:25 +01:00
dd7f4074cd Added encoding for asciidoc 2017-12-28 00:16:16 +01:00
8c10000e4e Updating documentation for run of the sources 2017-11-23 03:01:09 +01:00
43b82027f5 Added more content for CSRF lesson 2017-11-22 01:34:05 +01:00
5eed385d5d When an adoc file cannot be found the complete lesson crashed, made it failsafe with a logging statement. 2017-11-17 07:08:24 +01:00
75d0405da1 Fixed XXE lesson the posting of the comments did not show up directly only after page refresh 2017-11-17 07:07:43 +01:00
157b982394 successFunction and failureFunction were selected by using the main form (so the succesFunction of the first assignment was used for the next assignment) not the currentForm we determined in onFormSubmit() function. 2017-11-17 07:06:56 +01:00
99048d6d9d Fixing failing Travis script 2017-11-16 06:00:11 +01:00
971f11534d Debugging failing Travis script 2017-11-16 05:56:13 +01:00
c06e4d462b Error in travis.yml 2017-11-16 05:32:42 +01:00
39029f604f Travis sets version 2017-11-16 05:29:26 +01:00
36fcb58caa Endpoints async for posting mail and landingpage 2017-11-16 04:43:14 +01:00
6c91e7dc8a Fixed WebWolf issues with sending e-mails 2017-11-15 11:58:31 +01:00
a543deca04 Travis without output 2017-11-02 22:27:07 +01:00
f91f77708a New version 2017-11-02 21:44:30 +01:00
100876ad6c Changed introduction 2017-11-02 20:44:21 +01:00
56fc0fce05 Added test for XXE 2017-11-02 20:41:30 +01:00
fc1353b2f1 Pom cleanup 2017-11-02 16:14:44 +01:00
1e9f92220d Removed unnecessary JPA libraries 2017-11-02 15:44:45 +01:00
a11d3d0b1b - Made movie little bit shorter because webgoat-server.jar was over 200Mb
- Movie was copy and pasted to csrf and auth lesson removed it from those lessons
- Made jars which are not necessary in the webgoat-server.jar optional
2017-11-02 15:39:49 +01:00
87a7521dcd Adding introduction to WebGoat as the web interface opens with WebWolf which is confusing because people thought you needed to download WebWolf and start it directly. Feedback received during workshops 2017-11-02 14:28:20 +01:00
8729d9bfcf Fixed minor issues for properties and starting WebGoat 2017-11-02 12:42:19 +01:00
113 changed files with 1380 additions and 1052 deletions

5
.gitignore vendored
View File

@ -14,7 +14,8 @@
/.settings/org.eclipse.wst.validation.prefs /.settings/org.eclipse.wst.validation.prefs
/.externalToolBuilders/ /.externalToolBuilders/
.project .project
/target */target/*
mongo-data/*
.classpath .classpath
.idea/ .idea/
.settings/ .settings/
@ -29,6 +30,7 @@ src/main/webapp/plugin_lessons/*.jar
src/main/webapp/users/*.props src/main/webapp/users/*.props
classes/* classes/*
*.iml *.iml
pom.xml.versionsBackup
/*.iml /*.iml
.extract/* .extract/*
@ -39,3 +41,4 @@ webgoat-lessons/**/target
**/*.jar **/*.jar
**/.DS_Store **/.DS_Store
webgoat-server/mongo-data/* webgoat-server/mongo-data/*
webgoat-lessons/vulnerable-components/dependency-reduced-pom.xml

View File

@ -7,6 +7,7 @@ install: "/bin/true"
script: script:
- export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi) - export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)
- echo "TRAVIS_BRANCH=$TRAVIS_BRANCH, PR=$PR, BRANCH=$BRANCH" - echo "TRAVIS_BRANCH=$TRAVIS_BRANCH, PR=$PR, BRANCH=$BRANCH"
- if [ ! -z "${TRAVIS_TAG}" ]; then mvn versions:set -DnewVersion=${TRAVIS_TAG:1}; fi
- mvn clean install -q - mvn clean install -q
cache: cache:
directories: directories:
@ -35,6 +36,7 @@ deploy:
branch: develop branch: develop
- provider: releases - provider: releases
skip_cleanup: true skip_cleanup: true
overwrite: true
api_key: api_key:
#api-key from webgoat-github user #api-key from webgoat-github user
secure: pJOLBnl6427PcVg/tVy/qB18JC7b8cKpffau+IP0pjdSt7KUfBdBY3QuJ7mrM65zRoVILzggLckaew2PlRmYQRdumyWlyRn44XiJ9KO4n6Bsufbz+ictB4ggtozpp9+I9IIUh1TmqypL9lhkX2ONM9dSHmyblYpAAgMuYSK8FYc= secure: pJOLBnl6427PcVg/tVy/qB18JC7b8cKpffau+IP0pjdSt7KUfBdBY3QuJ7mrM65zRoVILzggLckaew2PlRmYQRdumyWlyRn44XiJ9KO4n6Bsufbz+ictB4ggtozpp9+I9IIUh1TmqypL9lhkX2ONM9dSHmyblYpAAgMuYSK8FYc=

29
CREATE_RELEASE.MD Normal file
View File

@ -0,0 +1,29 @@
## Release WebGoat
### Version numbers
For WebGoat we use milestone releases first before we release the official version, we use `v8.0.0.M3` while tagging
and 8.0.0.M3 in the `pom.xml`. When we create the final release we remove the milestone release and use
`v8.0.0` and 8.0.0 in the `pom.xml`
At the moment we use Gitflow, for a release you create a new release branch and take the following steps:
```
git checkout develop
git flow release start <version>
mvn versions:set <<version>
git commit -am "New release, updaing pom.xml"
git flow release publish
```
Now we can make a new release, be sure you committed all your changes.
```
git tag v8.0.0.M3
git push origin v8.0.0.M3
```
Now Travis takes over and will create the release in Github and on Docker Hub.

View File

@ -1,4 +1,4 @@
# WebGoat: A deliberately insecure Web Application # WebGoat 8: A deliberately insecure Web Application
[![Build Status](https://travis-ci.org/WebGoat/WebGoat.svg?branch=develop)](https://travis-ci.org/WebGoat/WebGoat) [![Build Status](https://travis-ci.org/WebGoat/WebGoat.svg?branch=develop)](https://travis-ci.org/WebGoat/WebGoat)
[![Coverage Status](https://coveralls.io/repos/WebGoat/WebGoat/badge.svg?branch=develop&service=github)](https://coveralls.io/github/WebGoat/WebGoat?branch=master) [![Coverage Status](https://coveralls.io/repos/WebGoat/WebGoat/badge.svg?branch=develop&service=github)](https://coveralls.io/github/WebGoat/WebGoat?branch=master)
@ -6,10 +6,6 @@
[![Dependency Status](https://www.versioneye.com/user/projects/562da95ae346d7000e0369aa/badge.svg?style=flat)](https://www.versioneye.com/user/projects/562da95ae346d7000e0369aa) [![Dependency Status](https://www.versioneye.com/user/projects/562da95ae346d7000e0369aa/badge.svg?style=flat)](https://www.versioneye.com/user/projects/562da95ae346d7000e0369aa)
[![OWASP Labs](https://img.shields.io/badge/owasp-labs-orange.svg)](https://www.owasp.org/index.php/OWASP_Project_Inventory#tab=Labs_Projects) [![OWASP Labs](https://img.shields.io/badge/owasp-labs-orange.svg)](https://www.owasp.org/index.php/OWASP_Project_Inventory#tab=Labs_Projects)
# Important
This is the development version of WebGoat 8, if you are looking for a released stable version please go to: https://github.com/WebGoat/WebGoat/wiki/Running-WebGoat
# Introduction # Introduction
@ -65,9 +61,14 @@ _Please note: this version may not be completely in sync with the develop branch
Download the latest WebWolf release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases) Download the latest WebWolf release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases)
```Shell ```Shell
java -jar webwolf-<<version>>.jar java -jar webgoat-server-<<version>>.jar
``` ```
By default WebGoat starts at port 8080 in order to change this use the following property:
```Shell
java -jar webgoat-server-<<version>>.jar --server.port=9090
```
## 3. Run from the sources ## 3. Run from the sources
@ -88,20 +89,22 @@ Now let's start by compiling the project.
```Shell ```Shell
cd WebGoat cd WebGoat
git checkout develop git checkout <<branch_name>>
mvn clean install mvn clean install
``` ```
Now we are ready to run the project. WebGoat 8.x is using Spring-Boot. Now we are ready to run the project. WebGoat 8.x is using Spring-Boot.
```Shell ```Shell
mvn -pl webwolf spring-boot:run mvn -pl webgoat-server spring-boot:run
``` ```
... you should be running webgoat on localhost:8080/WebGoat momentarily ... you should be running webgoat on localhost:8080/WebGoat momentarily
To change IP addresss add the following variable to WebGoat/webgoat-container/src/main/resources/application.properties file To change IP addresss add the following variable to WebGoat/webgoat-container/src/main/resources/application.properties file
```server.address=x.x.x.x ```
server.address=x.x.x.x
``` ```
# Vagrant # Vagrant

View File

@ -1,31 +1,11 @@
version: '2.0' version: '2.0'
services: services:
activemq:
image: webcenter/activemq:latest
ports:
- 8161:8161
- 61616:61616
- 61613:61613
mongo:
image: mongo:latest
expose:
- "27017"
volumes:
- './mongo-data:/data/db'
webgoat: webgoat:
build: webgoat-server/ build: webgoat-server/
command: "sh /home/webgoat/start.sh" command: "sh /home/webgoat/start.sh"
ports: ports:
- "8080:8080" - "8080:8080"
depends_on:
[mongo, activemq]
environment:
WG_MONGO_PORT: 27017
WG_MONGO_HOST: mongo
WG_MQ_HOST: activemq
WG_MQ_PORT: 61616
WG_INTERNAL_MONGO: "false"
webwolf: webwolf:
build: webwolf/ build: webwolf/
command: "sh /home/webwolf/start.sh" command: "sh /home/webwolf/start.sh"
@ -33,8 +13,3 @@ services:
- webgoat - webgoat
ports: ports:
- "8081:8081" - "8081:8081"
environment:
WG_MONGO_PORT: 27017
WG_MONGO_HOST: mongo
WG_MQ_HOST: activemq
WG_MQ_PORT: 61616

View File

@ -5,7 +5,7 @@
<groupId>org.owasp.webgoat</groupId> <groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-parent</artifactId> <artifactId>webgoat-parent</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
<name>WebGoat Parent Pom</name> <name>WebGoat Parent Pom</name>
<description>Parent Pom for the WebGoat Project. A deliberately insecure Web Application</description> <description>Parent Pom for the WebGoat Project. A deliberately insecure Web Application</description>
@ -142,7 +142,6 @@
<javaee-api.version>6.0</javaee-api.version> <javaee-api.version>6.0</javaee-api.version>
<javax.transaction-api.version>1.2</javax.transaction-api.version> <javax.transaction-api.version>1.2</javax.transaction-api.version>
<jcl-over-slf4j.version>1.7.12</jcl-over-slf4j.version> <jcl-over-slf4j.version>1.7.12</jcl-over-slf4j.version>
<jstl.version>1.2</jstl.version>
<jtds.version>1.3.1</jtds.version> <jtds.version>1.3.1</jtds.version>
<junit.version>4.12</junit.version> <junit.version>4.12</junit.version>
<mail-api.version>1.5.4</mail-api.version> <mail-api.version>1.5.4</mail-api.version>
@ -296,8 +295,8 @@
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope> <scope>provided</scope>
<optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>

View File

@ -4,6 +4,7 @@ docker login -u $DOCKER_USER -p $DOCKER_PASS
export REPO=webgoat/webgoat-8.0 export REPO=webgoat/webgoat-8.0
cd webgoat-server cd webgoat-server
ls target/
if [ "${BRANCH}" == "master" ] && [ ! -z "${TRAVIS_TAG}" ]; then if [ "${BRANCH}" == "master" ] && [ ! -z "${TRAVIS_TAG}" ]; then
# If we push a tag to master this will update the LATEST Docker image and tag with the version number # If we push a tag to master this will update the LATEST Docker image and tag with the version number
@ -11,7 +12,7 @@ if [ "${BRANCH}" == "master" ] && [ ! -z "${TRAVIS_TAG}" ]; then
docker push $REPO docker push $REPO
elif [ ! -z "${TRAVIS_TAG}" ]; then elif [ ! -z "${TRAVIS_TAG}" ]; then
# Creating a tag build we push it to Docker with that tag # Creating a tag build we push it to Docker with that tag
docker build --build-arg webgoat_version=${TRAVIS_TAG:1} -f Dockerfile -t $REPO:${TRAVIS_TAG} . docker build --build-arg webgoat_version=${TRAVIS_TAG:1} -f Dockerfile -t $REPO:${TRAVIS_TAG} -t $REPO:latest .
docker push $REPO docker push $REPO
elif [ "${BRANCH}" == "develop" ]; then elif [ "${BRANCH}" == "develop" ]; then
docker build -f Dockerfile -t $REPO:snapshot . docker build -f Dockerfile -t $REPO:snapshot .

View File

@ -10,7 +10,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat</groupId> <groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-parent</artifactId> <artifactId>webgoat-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
<profiles> <profiles>
@ -36,16 +36,6 @@
</profiles> </profiles>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<build> <build>
<resources> <resources>
<resource> <resource>
@ -92,29 +82,6 @@
<forkMode>never</forkMode> <forkMode>never</forkMode>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<filesets>
<fileset>
<directory>${project.basedir}/src/main/resources/plugin_lessons</directory>
<includes>
<include>**/*.jar</include>
<include>**/*.pom</include>
</includes>
</fileset>
<fileset>
<directory>${user.home}/.webgoat/</directory>
<includes>
<include>**/*.jar</include>
<include>**/org/**</include>
<include>**/plugin/**</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
@ -135,14 +102,6 @@
<groupId>com.fasterxml.jackson.datatype</groupId> <groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId> <artifactId>jackson-datatype-jsr310</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
@ -152,41 +111,32 @@
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.asciidoctor</groupId> <groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj</artifactId> <artifactId>asciidoctorj</artifactId>
<version>1.5.4</version> <version>1.5.4</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId> <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version> <version>${commons-lang3.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency> <dependency>
<groupId>io.gatling.highcharts</groupId> <groupId>io.gatling.highcharts</groupId>
<artifactId>gatling-charts-highcharts</artifactId> <artifactId>gatling-charts-highcharts</artifactId>
<version>${gatling.version}</version> <version>${gatling.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId> <artifactId>spring-boot-starter-security</artifactId>
@ -205,11 +155,6 @@
<artifactId>activation</artifactId> <artifactId>activation</artifactId>
<version>${activation.version}</version> <version>${activation.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.hsqldb</groupId> <groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId> <artifactId>hsqldb</artifactId>
@ -224,19 +169,7 @@
<groupId>org.scala-lang</groupId> <groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId> <artifactId>scala-compiler</artifactId>
<version>${scala.version}</version> <version>${scala.version}</version>
</dependency> <scope>test</scope>
<!-- Apache Commons Upload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency> </dependency>
@ -259,12 +192,6 @@
<version>${junit.version}</version> <version>${junit.version}</version>
<type>jar</type> <type>jar</type>
</dependency> </dependency>
<dependency>
<groupId>com.github.fakemongo</groupId>
<artifactId>fongo</artifactId>
<version>2.1.0</version>
<scope>test</scope>
</dependency>
<!-- ************* END: Dependencies for Unit and Integration Testing ************** --> <!-- ************* END: Dependencies for Unit and Integration Testing ************** -->
<!-- ************* END: <dependencies> ************** --> <!-- ************* END: <dependencies> ************** -->
</dependencies> </dependencies>

View File

@ -32,6 +32,7 @@ package org.owasp.webgoat;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.asciidoctor.Asciidoctor; import org.asciidoctor.Asciidoctor;
import org.owasp.webgoat.i18n.Language; import org.owasp.webgoat.i18n.Language;
import org.thymeleaf.TemplateProcessingParameters; import org.thymeleaf.TemplateProcessingParameters;
@ -41,6 +42,7 @@ import org.thymeleaf.templateresolver.TemplateResolver;
import java.io.*; import java.io.*;
import java.util.Map; import java.util.Map;
import static org.apache.commons.lang3.CharEncoding.UTF_8;
import static org.asciidoctor.Asciidoctor.Factory.create; import static org.asciidoctor.Asciidoctor.Factory.create;
/** /**
@ -50,6 +52,7 @@ import static org.asciidoctor.Asciidoctor.Factory.create;
* <div th:replace="doc:AccessControlMatrix_plan.adoc"></div> * <div th:replace="doc:AccessControlMatrix_plan.adoc"></div>
* </code> * </code>
*/ */
@Slf4j
public class AsciiDoctorTemplateResolver extends TemplateResolver { public class AsciiDoctorTemplateResolver extends TemplateResolver {
private static final Asciidoctor asciidoctor = create(); private static final Asciidoctor asciidoctor = create();
@ -73,11 +76,15 @@ public class AsciiDoctorTemplateResolver extends TemplateResolver {
@Override @Override
public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) { public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) {
InputStream is = readInputStreamOrFallbackToEnglish(resourceName, language); try (InputStream is = readInputStreamOrFallbackToEnglish(resourceName, language)) {
try { if (is == null) {
StringWriter writer = new StringWriter(); log.warn("Resource name: {} not found, did you add the adoc file?", resourceName);
asciidoctor.convert(new InputStreamReader(is), writer, createAttributes()); return new ByteArrayInputStream(new byte[0]);
return new ByteArrayInputStream(writer.getBuffer().toString().getBytes()); } else {
StringWriter writer = new StringWriter();
asciidoctor.convert(new InputStreamReader(is), writer, createAttributes());
return new ByteArrayInputStream(writer.getBuffer().toString().getBytes(UTF_8));
}
} catch (IOException e) { } catch (IOException e) {
//no html yet //no html yet
return new ByteArrayInputStream(new byte[0]); return new ByteArrayInputStream(new byte[0]);

View File

@ -23,11 +23,5 @@ public class CleanupLocalProgressFiles {
@PostConstruct @PostConstruct
public void clean() { public void clean() {
File dir = new File(webgoatHome);
//do it safe, check whether the subdir mongodb is available as subdirectory
File[] mongoDir = dir.listFiles(f -> f.isDirectory() && f.getName().contains("mongodb"));
if (mongoDir != null && mongoDir.length == 1) {
FileSystemUtils.deleteRecursively(dir);
}
} }
} }

View File

@ -2,6 +2,10 @@ package org.owasp.webgoat.lessons;
import lombok.*; import lombok.*;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import java.util.List; import java.util.List;
/** /**
@ -38,11 +42,14 @@ import java.util.List;
@NoArgsConstructor @NoArgsConstructor
@Getter @Getter
@EqualsAndHashCode @EqualsAndHashCode
@Entity
public class Assignment { public class Assignment {
@NonNull @NonNull
@Id
private String name; private String name;
@NonNull @NonNull
private String path; private String path;
@Transient
private List<String> hints; private List<String> hints;
} }

View File

@ -1,66 +0,0 @@
/**
* *************************************************************************************************
* <p>
* <p>
* 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 - 20014 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.
*/
package org.owasp.webgoat.service;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* <p>SolutionService class.</p>
*
* @author rlawson
* @version $Id: $Id
*/
@Controller
public class SolutionService {
/**
* Returns solution for current attack
*
* @return a {@link java.lang.String} object.
*/
@RequestMapping(path = "/service/solution.mvc", produces = "text/html")
public
@ResponseBody
String showSolution() {
//// TODO: 11/6/2016 to decide not sure about the role in WebGoat 8
String source = getSolution();
return source;
}
/**
* <p>getSolution.</p>
*
* @return a {@link java.lang.String} object.
*/
protected String getSolution() {
return "Solution is not available";
}
}

View File

@ -1,82 +0,0 @@
/**
* *************************************************************************************************
* <p>
* <p>
* 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 - 20014 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.
*/
package org.owasp.webgoat.service;
import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpSession;
/**
* <p>SourceService class.</p>
*
* @author rlawson
* @version $Id: $Id
*/
@Controller
//TODO REMOVE!
public class SourceService {
/**
* Description of the Field
*/
public final static String START_SOURCE_SKIP = "START_OMIT_SOURCE";
/** Constant <code>END_SOURCE_SKIP="END_OMIT_SOURCE"</code> */
public final static String END_SOURCE_SKIP = "END_OMIT_SOURCE";
/**
* Returns source for current attack
*
* @param session a {@link javax.servlet.http.HttpSession} object.
* @return a {@link java.lang.String} object.
*/
@RequestMapping(path = "/service/source.mvc", produces = "application/text")
public
@ResponseBody
String showSource(HttpSession session) {
//// TODO: 11/6/2016 to decide not sure about the role in WebGoat 8
String source = getSource();
if (source == null) {
source = "No source listing found";
}
return StringEscapeUtils.escapeHtml4(source);
}
/**
* Description of the Method
*
* @return Description of the Return Value
*/
protected String getSource() {
return "Source code is not available for this lesson.";
}
}

View File

@ -7,6 +7,7 @@ import lombok.Getter;
import org.owasp.webgoat.lessons.AbstractLesson; import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Assignment; import org.owasp.webgoat.lessons.Assignment;
import javax.persistence.*;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -44,16 +45,20 @@ import java.util.stream.Collectors;
* @version $Id: $Id * @version $Id: $Id
* @since October 29, 2003 * @since October 29, 2003
*/ */
@Entity
public class LessonTracker { public class LessonTracker {
@Getter @Getter
@Id
private String lessonName; private String lessonName;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private final Set<Assignment> solvedAssignments = Sets.newHashSet(); private final Set<Assignment> solvedAssignments = Sets.newHashSet();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private final List<Assignment> allAssignments = Lists.newArrayList(); private final List<Assignment> allAssignments = Lists.newArrayList();
@Getter @Getter
private int numberOfAttempts = 0; private int numberOfAttempts = 0;
protected LessonTracker() { private LessonTracker() {
//Mongo //JPA
} }
public LessonTracker(AbstractLesson lesson) { public LessonTracker(AbstractLesson lesson) {

View File

@ -15,7 +15,7 @@ import javax.validation.constraints.Size;
public class UserForm { public class UserForm {
@NotNull @NotNull
@Size(min=6, max=10) @Size(min=6, max=20)
private String username; private String username;
@NotNull @NotNull
@Size(min=6, max=10) @Size(min=6, max=10)

View File

@ -1,6 +1,6 @@
package org.owasp.webgoat.users; package org.owasp.webgoat.users;
import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List; import java.util.List;
@ -8,7 +8,7 @@ import java.util.List;
* @author nbaars * @author nbaars
* @since 3/19/17. * @since 3/19/17.
*/ */
public interface UserRepository extends MongoRepository<WebGoatUser, String> { public interface UserRepository extends JpaRepository<WebGoatUser, String> {
WebGoatUser findByUsername(String username); WebGoatUser findByUsername(String username);

View File

@ -5,8 +5,8 @@ import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.lessons.AbstractLesson; import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Assignment; import org.owasp.webgoat.lessons.Assignment;
import org.springframework.data.annotation.Id;
import javax.persistence.*;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -44,12 +44,16 @@ import java.util.stream.Collectors;
* @since October 29, 2003 * @since October 29, 2003
*/ */
@Slf4j @Slf4j
@Entity
public class UserTracker { public class UserTracker {
@Id @Id
private final String user; private String user;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<LessonTracker> lessonTrackers = Lists.newArrayList(); private List<LessonTracker> lessonTrackers = Lists.newArrayList();
private UserTracker() {}
public UserTracker(final String user) { public UserTracker(final String user) {
this.user = user; this.user = user;
} }

View File

@ -1,12 +1,12 @@
package org.owasp.webgoat.users; package org.owasp.webgoat.users;
import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.jpa.repository.JpaRepository;
/** /**
* @author nbaars * @author nbaars
* @since 4/30/17. * @since 4/30/17.
*/ */
public interface UserTrackerRepository extends MongoRepository<UserTracker, String> { public interface UserTrackerRepository extends JpaRepository<UserTracker, String> {
} }

View File

@ -1,13 +1,14 @@
package org.owasp.webgoat.users; package org.owasp.webgoat.users;
import lombok.Getter; import lombok.Getter;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -16,6 +17,7 @@ import java.util.Collections;
* @since 3/19/17. * @since 3/19/17.
*/ */
@Getter @Getter
@Entity
public class WebGoatUser implements UserDetails { public class WebGoatUser implements UserDetails {
public static final String ROLE_USER = "WEBGOAT_USER"; public static final String ROLE_USER = "WEBGOAT_USER";

View File

@ -4,6 +4,9 @@ server.session.timeout=600
server.contextPath=/WebGoat server.contextPath=/WebGoat
server.port=8080 server.port=8080
spring.datasource.url=jdbc:hsqldb:file:${webgoat.server.directory}/data/webgoat
spring.jpa.hibernate.ddl-auto=update
logging.level.org.springframework=WARN logging.level.org.springframework=WARN
logging.level.org.springframework.boot.devtools=WARN logging.level.org.springframework.boot.devtools=WARN
@ -28,22 +31,15 @@ webgoat.feedback.address.html=<A HREF=mailto:webgoat@owasp.org>webgoat@owasp.org
webgoat.database.driver=org.hsqldb.jdbcDriver webgoat.database.driver=org.hsqldb.jdbcDriver
webgoat.database.connection.string=jdbc:hsqldb:mem:{USER} webgoat.database.connection.string=jdbc:hsqldb:mem:{USER}
webgoat.default.language=en webgoat.default.language=en
webgoat.embedded.mongo=${WG_INTERNAL_MONGO:true}
webwolf.port=8081 webwolf.host=${WEBWOLF_HOST:localhost}
webwolf.url=http://localhost:${webwolf.port}/WebWolf webwolf.port=${WEBWOLF_PORT:8081}
webworf.url.landingpage=http://localhost:${webwolf.port}/landing webwolf.url=http://${webwolf.host}:${webwolf.port}/WebWolf
webworf.url.mail=http://localhost:${webwolf.port}/mail webworf.url.landingpage=http://${webwolf.host}:${webwolf.port}/landing
webwolf.url.mail=http://${webwolf.host}:${webwolf.port}/mail
spring.jackson.serialization.indent_output=true spring.jackson.serialization.indent_output=true
spring.jackson.serialization.write-dates-as-timestamps=false spring.jackson.serialization.write-dates-as-timestamps=false
spring.activemq.brokerUrl=tcp://${WG_MQ_HOST:localhost}:${WG_MQ_PORT:61616}
spring.data.mongodb.host=${WG_MONGO_HOST:localhost}
spring.data.mongodb.port=${WG_MONGO_PORT:27017}
spring.data.mongodb.database=webgoat
spring.mongodb.embedded.storage.databaseDir=${webgoat.user.directory}/mongodb/
#For static file refresh ... and faster dev :D #For static file refresh ... and faster dev :D
spring.devtools.restart.additional-paths=webgoat-container/src/main/resources/static/js,webgoat-container/src/main/resources/static/css spring.devtools.restart.additional-paths=webgoat-container/src/main/resources/static/js,webgoat-container/src/main/resources/static/css

View File

@ -45,7 +45,6 @@ define(['jquery',
this.$el.find('.attack-feedback').hide(); this.$el.find('.attack-feedback').hide();
this.$el.find('.attack-output').hide(); this.$el.find('.attack-output').hide();
this.makeFormsAjax(); this.makeFormsAjax();
//this.ajaxifyAttackHref();
$(window).scrollTop(0); //work-around til we get the scroll down sorted out $(window).scrollTop(0); //work-around til we get the scroll down sorted out
var startPageNum = this.model.get('pageNum'); var startPageNum = this.model.get('pageNum');
this.initPagination(startPageNum); this.initPagination(startPageNum);
@ -86,6 +85,8 @@ define(['jquery',
var prepareDataFunctionName = $(curForm).attr('prepareData'); var prepareDataFunctionName = $(curForm).attr('prepareData');
var callbackFunctionName = $(curForm).attr('callback'); var callbackFunctionName = $(curForm).attr('callback');
var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize(); var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize();
var successCallBackFunctionName = $(curForm).attr('successCallback');
var failureCallbackFunctionName = $(curForm).attr('failureCallback');
var callbackFunction = (typeof webgoat.customjs[callbackFunctionName] === 'function') ? webgoat.customjs[callbackFunctionName] : function() {}; var callbackFunction = (typeof webgoat.customjs[callbackFunctionName] === 'function') ? webgoat.customjs[callbackFunctionName] : function() {};
// var submitData = this.$form.serialize(); // var submitData = this.$form.serialize();
this.curForm = curForm; this.curForm = curForm;
@ -104,19 +105,18 @@ define(['jquery',
//complete: function (data) { //complete: function (data) {
//callbackFunction(data); //callbackFunction(data);
//} //}
}).then(self.onSuccessResponse.bind(self), self.onErrorResponse.bind(self)); }).then(function(data){
self.onSuccessResponse(data, failureCallbackFunctionName, successCallBackFunctionName)}, self.onErrorResponse.bind(self));
return false; return false;
}, },
onSuccessResponse: function(data) { onSuccessResponse: function(data, failureCallbackFunctionName, successCallBackFunctionName) {
this.renderFeedback(data.feedback); this.renderFeedback(data.feedback);
this.renderOutput(data.output || ""); this.renderOutput(data.output || "");
var successCallBackFunctionName = this.$form.attr('successCallback');
var failureCallbackFunctionName = this.$form.attr('failureCallback');
//var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize(); //var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize();
successCallbackFunction = (typeof webgoat.customjs[successCallBackFunctionName] === 'function') ? webgoat.customjs[successCallBackFunctionName] : function() {}; var successCallbackFunction = (typeof webgoat.customjs[successCallBackFunctionName] === 'function') ? webgoat.customjs[successCallBackFunctionName] : function() {};
failureCallbackFunction = (typeof webgoat.customjs[failureCallbackFunctionName] === 'function') ? webgoat.customjs[failureCallbackFunctionName] : function() {}; var failureCallbackFunction = (typeof webgoat.customjs[failureCallbackFunctionName] === 'function') ? webgoat.customjs[failureCallbackFunctionName] : function() {};
//TODO: refactor back assignmentCompleted in Java //TODO: refactor back assignmentCompleted in Java
if (data.lessonCompleted || data.assignmentCompleted) { if (data.lessonCompleted || data.assignmentCompleted) {
this.markAssignmentComplete(); this.markAssignmentComplete();
@ -146,14 +146,6 @@ define(['jquery',
return false; return false;
}, },
ajaxifyAttackHref: function() { // rewrite any links with hrefs point to relative attack URLs
var self = this;
// instruct in template to have links returned with the attack-link class
$('a.attack-link').submit(function(event){
$.get(this.action, "json").then(self.onSuccessResponse, self.onErrorResponse);
});
},
renderFeedback: function(feedback) { renderFeedback: function(feedback) {
this.$curFeedback.html(polyglot.t(feedback) || ""); this.$curFeedback.html(polyglot.t(feedback) || "");
this.$curFeedback.show(400) this.$curFeedback.show(400)

View File

@ -1,23 +0,0 @@
package org.owasp.webgoat.plugins;
import com.github.fakemongo.Fongo;
import com.mongodb.MongoClient;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
/**
* Using Fongo for embedded in memory MongoDB testing
*/
@Configuration
public class TestConfig extends AbstractMongoConfiguration {
@Override
protected String getDatabaseName() {
return "test";
}
@Override
public MongoClient mongo() throws Exception {
return new Fongo(getDatabaseName()).getMongo();
}
}

View File

@ -0,0 +1,29 @@
package org.owasp.webgoat.users;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;
@DataJpaTest
@RunWith(SpringRunner.class)
public class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
public void userShouldBeSaved() {
WebGoatUser user = new WebGoatUser("test", "password");
userRepository.saveAndFlush(user);
user = userRepository.findByUsername("test");
Assertions.assertThat(user.getUsername()).isEqualTo("test");
Assertions.assertThat(user.getPassword()).isEqualTo("password");
}
}

View File

@ -0,0 +1,101 @@
package org.owasp.webgoat.users;
import org.assertj.core.api.Assertions;
import org.assertj.core.util.Lists;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@DataJpaTest
@RunWith(SpringRunner.class)
public class UserTrackerRepositoryTest {
private class TestLesson extends NewLesson {
@Override
public Category getDefaultCategory() {
return Category.AJAX_SECURITY;
}
@Override
public List<String> getHints() {
return Lists.newArrayList();
}
@Override
public Integer getDefaultRanking() {
return 12;
}
@Override
public String getTitle() {
return "test";
}
@Override
public String getId() {
return "test";
}
@Override
public List<Assignment> getAssignments() {
Assignment assignment = new Assignment("test", "test", Lists.newArrayList());
return Lists.newArrayList(assignment);
}
}
@Autowired
private UserTrackerRepository userTrackerRepository;
@Test
public void saveUserTracker() {
UserTracker userTracker = new UserTracker("test");
LessonTracker lessonTracker = userTracker.getLessonTracker(new TestLesson());
userTrackerRepository.save(userTracker);
userTracker = userTrackerRepository.findOne("test");
Assertions.assertThat(userTracker.getLessonTracker("test")).isNotNull();
}
@Test
public void solvedAssignmentsShouldBeSaved() {
UserTracker userTracker = new UserTracker("test");
TestLesson lesson = new TestLesson();
userTracker.getLessonTracker(lesson);
userTracker.assignmentFailed(lesson);
userTracker.assignmentFailed(lesson);
userTracker.assignmentSolved(lesson, "test");
userTrackerRepository.saveAndFlush(userTracker);
userTracker = userTrackerRepository.findOne("test");
Assertions.assertThat(userTracker.numberOfAssignmentsSolved()).isEqualTo(1);
}
@Test
public void saveAndLoadShouldHaveCorrectNumberOfAttemtps() {
UserTracker userTracker = new UserTracker("test");
TestLesson lesson = new TestLesson();
userTracker.getLessonTracker(lesson);
userTracker.assignmentFailed(lesson);
userTracker.assignmentFailed(lesson);
userTrackerRepository.saveAndFlush(userTracker);
userTracker = userTrackerRepository.findOne("test");
userTracker.assignmentFailed(lesson);
userTracker.assignmentFailed(lesson);
userTrackerRepository.saveAndFlush(userTracker);
Assertions.assertThat(userTracker.getLessonTracker(lesson).getNumberOfAttempts()).isEqualTo(4);
}
}

View File

@ -1 +1,4 @@
webgoat.user.directory=${java.io.tmpdir} webgoat.user.directory=${java.io.tmpdir}
spring.datasource.url=jdbc:hsqldb:mem:test
spring.jpa.hibernate.ddl-auto=create-drop

View File

@ -0,0 +1,35 @@
# Setup a Linux box headless which will start WebGoat and WebWolf helpful image to give away during training
Vagrant.configure(2) do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.network :forwarded_port, guest: 8080, host: 8080
config.vm.network :forwarded_port, guest: 8081, host: 8081
config.vm.provider "virtualbox" do |vb|
vb.gui = false
vb.memory = "4096"
vb.cpus = 2
vb.name = "WebGoat-Training"
vb.customize ["modifyvm", :id, "--nictype1", "virtio"]
end
config.vm.provider "vmware_fusion" do |vf|
vf.gui = false
vf.vmx["memsize"] = 4096
vf.vmx["numvcpus"] = 2
vf.vmx["displayname"] = "WebGoat-Training"
end
config.vm.provision "shell", inline: <<-SHELL
wget https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M5/webgoat-server-8.0.0.M6.jar
wget https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M5/webwolf-8.0.0.M6.jar
sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt-get update
sudo apt-get install openjdk-8-jre -y
SHELL
config.vm.provision "shell", run: "always", privileged: false, inline: <<-SHELL
java -jar webgoat-server-8.0.0.M6.jar &
sleep 40s
java -jar webwolf-8.0.0.M6.jar
SHELL
end

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
</project> </project>

View File

@ -6,6 +6,6 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
</project> </project>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>

View File

@ -45,7 +45,7 @@ public class Assignment7 extends AssignmentEndpoint {
@Autowired @Autowired
private RestTemplate restTemplate; private RestTemplate restTemplate;
@Value("${webworf.url.mail}") @Value("${webwolf.url.mail}")
private String webWolfMailURL; private String webWolfMailURL;
@GetMapping("/reset-password/{link}") @GetMapping("/reset-password/{link}")

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
</project> </project>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
<build> <build>
<plugins> <plugins>

View File

@ -6,6 +6,6 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
</project> </project>

View File

@ -0,0 +1,88 @@
package org.owasp.webgoat.plugin;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.UserSessionData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
/**
* @author nbaars
* @since 11/17/17.
*/
@AssignmentPath("/csrf/feedback")
@AssignmentHints({"csrf-feedback-hint1", "csrf-feedback-hint2", "csrf-feedback-hint3"})
public class CSRFFeedback extends AssignmentEndpoint {
@Autowired
private UserSessionData userSessionData;
@Autowired
private ObjectMapper objectMapper;
@PostMapping(value = "/message", produces = {"application/json"})
@ResponseBody
public AttackResult completed(HttpServletRequest request, @RequestBody String feedback) {
try {
objectMapper.readValue(feedback.getBytes(), Map.class);
} catch (IOException e) {
return failed().feedback(ExceptionUtils.getStackTrace(e)).build();
}
boolean correctCSRF = requestContainsWebGoatCookie(request.getCookies()) && request.getContentType().equals(MediaType.TEXT_PLAIN_VALUE);
correctCSRF &= hostOrRefererDifferentHost(request);
if (correctCSRF) {
String flag = UUID.randomUUID().toString();
userSessionData.setValue("csrf-feedback", flag);
return success().feedback("csrf-feedback-success").feedbackArgs(flag).build();
}
return failed().build();
}
@PostMapping(produces = "application/json")
@ResponseBody
public AttackResult flag(@RequestParam("confirmFlagVal") String flag) {
if (flag.equals(userSessionData.getValue("csrf-feedback"))) {
return trackProgress(success().build());
} else {
return trackProgress(failed().build());
}
}
private boolean hostOrRefererDifferentHost(HttpServletRequest request) {
String referer = request.getHeader("referer");
String host = request.getHeader("host");
return !StringUtils.contains(referer, host);
}
private boolean requestContainsWebGoatCookie(Cookie[] cookies) {
if (cookies != null) {
for (Cookie c : cookies) {
if (c.getName().equals("JSESSIONID")) {
return true;
}
}
}
return false;
}
/** Solution
<form name="attack" enctype="text/plain" action="http://localhost:8080/WebGoat/csrf/feedback/message" METHOD="POST">
<input type="hidden" name='{"name": "Test", "email": "test1233@dfssdf.de", "subject": "service", "message":"dsaffd"}'>
</form>
<script>document.attack.submit();</script>
*/
}

View File

@ -0,0 +1,40 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.users.UserTracker;
import org.owasp.webgoat.users.UserTrackerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author nbaars
* @since 11/17/17.
*/
@AssignmentPath("/csrf/login")
@AssignmentHints({"csrf-login-hint1", "csrf-login-hint2", "csrf-login-hint3"})
public class CSRFLogin extends AssignmentEndpoint {
@Autowired
private UserTrackerRepository userTrackerRepository;
@PostMapping(produces = {"application/json"})
@ResponseBody
public AttackResult completed() {
String userName = getWebSession().getUserName();
if (userName.startsWith("csrf")) {
markAssignmentSolvedWithRealUser(userName.substring("csrf-".length()));
return trackProgress(success().feedback("csrf-login-success").build());
}
return trackProgress(failed().feedback("csrf-login-failed").feedbackArgs(userName).build());
}
private void markAssignmentSolvedWithRealUser(String username) {
UserTracker userTracker = userTrackerRepository.findOne(username);
userTracker.assignmentSolved(getWebSession().getCurrentLesson(), this.getClass().getSimpleName());
userTrackerRepository.save(userTracker);
}
}

View File

@ -2,62 +2,63 @@
<html xmlns:th="http://www.thymeleaf.org"> <html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:CSRF_intro.adoc"></div> <div class="adoc-content" th:replace="doc:CSRF_intro.adoc"></div>
</div> </div>
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:CSRF_GET.adoc"></div> <div class="adoc-content" th:replace="doc:CSRF_GET.adoc"></div>
</div> </div>
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:CSRF_Get_Flag.adoc"></div> <div class="adoc-content" th:replace="doc:CSRF_Get_Flag.adoc"></div>
<form accept-charset="UNKNOWN" id="basic-csrf-get" <form accept-charset="UNKNOWN" id="basic-csrf-get"
method="GET" name="form1" method="GET" name="form1"
successCallback=""
action="/WebGoat/csrf/basic-get-flag"
enctype="application/json;charset=UTF-8">
<input name="csrf" type="hidden" value="false"/>
<input type="submit" name="ubmit="/>
</form>
<div class="adoc-content" th:replace="doc:CSRF_Basic_Get-1.adoc"></div>
<div class="attack-container">
<div class="assignment-success">
<i class="fa fa-2 fa-check hidden" aria-hidden="true">
</i>
</div>
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-1"
method="POST" name="form2"
successCallback="" successCallback=""
action="/WebGoat/csrf/basic-get-flag" action="/WebGoat/csrf/confirm-flag-1"
enctype="application/json;charset=UTF-8"> enctype="application/json;charset=UTF-8">
<input name="csrf" type="hidden" value="false" />
<input type="submit" name="ubmit=" /> Confirm Flag Value:
<input type="text" length="6" name="confirmFlagVal" value=""/>
<input name="submit" value="Submit" type="submit"/>
</form> </form>
<div class="adoc-content" th:replace="doc:CSRF_Basic_Get-1.adoc"></div> <div class="attack-feedback"></div>
<div class="attack-output"></div>
<div class="attack-container">
<div class="assignment-success">
<i class="fa fa-2 fa-check hidden" aria-hidden="true">
</i>
</div>
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-1"
method="POST" name="form2"
successCallback=""
action="/WebGoat/csrf/confirm-flag-1"
enctype="application/json;charset=UTF-8">
Confirm Flag Value:
<input type="text" length="6" name="confirmFlagVal" value="" />
<input name="submit" value="Submit" type="submit"/>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div> </div>
</div>
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:CSRF_Reviews.adoc"></div> <div class="adoc-content" th:replace="doc:CSRF_Reviews.adoc"></div>
<!-- comment area --> <!-- comment area -->
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/reviews.css}"/> <link rel="stylesheet" type="text/css" th:href="@{/lesson_css/reviews.css}"/>
<script th:src="@{/lesson_js/csrf-review.js}" language="JavaScript"></script> <script th:src="@{/lesson_js/csrf-review.js}" language="JavaScript"></script>
<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>
<div class="attack-container">
<div class="container-fluid"> <div class="container-fluid">
<div class="panel post"> <div class="panel post">
<div class="post-heading"> <div class="post-heading">
@ -89,16 +90,17 @@
method="POST" name="review-form" method="POST" name="review-form"
successCallback="" successCallback=""
action="/WebGoat/csrf/review"> action="/WebGoat/csrf/review">
<input class="form-control" id="reviewText" name="reviewText" placeholder="Add a Review" type="text"/> <input class="form-control" id="reviewText" name="reviewText" placeholder="Add a Review"
<input class="form-control" id="reviewStars" name="stars" type="text" /> type="text"/>
<input type="hidden" name="validateReq" value="2aa14227b9a13d0bede0388a7fba9aa9" /> <input class="form-control" id="reviewStars" name="stars" type="text"/>
<input type="hidden" name="validateReq" value="2aa14227b9a13d0bede0388a7fba9aa9"/>
<input type="submit" name="submit" value="Submit review"/> <input type="submit" name="submit" value="Submit review"/>
</form> </form>
<div class="attack-feedback"></div> <div class="attack-feedback"></div>
<div class="attack-output"></div> <div class="attack-output"></div>
<!--<span class="input-group-addon">--> <!--<span class="input-group-addon">-->
<!--<i id="postReview" class="fa fa-edit" style="font-size: 20px"></i>--> <!--<i id="postReview" class="fa fa-edit" style="font-size: 20px"></i>-->
<!--</span>--> <!--</span>-->
</div> </div>
<ul class="comments-list"> <ul class="comments-list">
<div id="list"> <div id="list">
@ -108,14 +110,144 @@
</div> </div>
</div> </div>
</div> </div>
<!-- end comments --> </div>
<!-- end comments -->
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:CSRF_Frameworks.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:CSRF_JSON.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:CSRF_ContentType.adoc"></div>
<script th:src="@{/lesson_js/feedback.js}" language="JavaScript"></script>
<div style="container-fluid; background-color: #f1f1f1; border: 2px solid #a66;
border-radius: 12px;
padding: 7px;
margin-top:7px;
padding:5px;">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="container-fluid">
<div class="row">
<div class="col-md-8">
<div class="well well-sm">
<form class="attack-form" accept-charset="UNKNOWN" id="csrf-feedback"
method="POST"
prepareData="feedback"
action="/WebGoat/csrf/feedback/message"
contentType="application/json">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">
Name</label>
<input type="text" class="form-control" name="name" id="name"
placeholder="Enter name"
required="required"/>
</div>
<div class="form-group">
<label for="email">
Email Address</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-envelope"></span>
</span>
<input type="email" name="email" class="form-control" id="email"
placeholder="Enter email"
required="required"/></div>
</div>
<div class="form-group">
<label for="subject">
Subject</label>
<select id="subject" name="subject" class="form-control" required="required">
<option value="na" selected="">Choose One:</option>
<option value="service">General Customer Service</option>
<option value="suggestions">Suggestions</option>
<option value="product">Product Support</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="name">
Message</label>
<textarea name="message" id="message" class="form-control" rows="9" cols="25"
required="required"
placeholder="Message"></textarea>
</div>
</div>
<div class="col-md-12">
<button class="btn btn-primary pull-right" id="btnContactUs">
Send Message
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div> </div>
<div class="lesson-page-wrapper"> <div class="attack-container">
<div class="adoc-content" th:replace="doc:CSRF_Impact_Defense.adoc"></div> <div class="assignment-success">
<i class="fa fa-2 fa-check hidden" aria-hidden="true">
</i>
</div>
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-feedback"
method="POST" name="form2"
action="/WebGoat/csrf/feedback"
enctype="application/json;charset=UTF-8">
Confirm Flag Value:
<input type="text" length="6" name="confirmFlagVal" value=""/>
<input name="submit" value="Submit" type="submit"/>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div> </div>
<!--</div>-->
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:CSRF_Login.adoc"></div>
<div class="attack-container">
<div class="assignment-success">
<i class="fa fa-2 fa-check hidden" aria-hidden="true">
</i>
</div>
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-login"
method="POST" name="form2"
action="/WebGoat/csrf/login"
enctype="application/json;charset=UTF-8">
Press the button below when your are logged in as the other user<br/>
<input name="submit" value="Solved!" type="submit"/>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:CSRF_Impact_Defense.adoc"></div>
</div>
<!--</div>-->
</html> </html>

View File

@ -17,3 +17,16 @@ csrf-review.success=It appears you have submitted correctly from another site. G
csrf-review-hint1=Again, you will need to submit from an external domain/host to trigger this action. While CSRF can often be triggered from the same host (e.g. via persisted payload), this doesn't work that way. csrf-review-hint1=Again, you will need to submit from an external domain/host to trigger this action. While CSRF can often be triggered from the same host (e.g. via persisted payload), this doesn't work that way.
csrf-review-hint2=Remember, you need to mimic the existing workflow/form. csrf-review-hint2=Remember, you need to mimic the existing workflow/form.
csrf-review-hint3=This one has a weak anti-CSRF protection, but you do need to overcome (mimic) it csrf-review-hint3=This one has a weak anti-CSRF protection, but you do need to overcome (mimic) it
csrf-feedback-hint1=Look at the content-type.
csrf-feedback-hint2=Try to post the same message with content-type text/plain
csrf-feedback-hint3=The json can be put into a hidden field inside
csrf-feedback-invalid-json=Invalid JSON received.
csrf-feedback-success=Congratulations you have found the correct solution, the flag is: {0}
csrf-login-hint1=First create a new account with csrf-username
csrf-login-hint2=Create a form which will log you in as this user (hint 1) and upload it to WebWolf
csrf-login-hint3=Visit this assignment again
csrf-login-success=Congratulations, now log out and login with your normal user account within WebGoat, remember the attacker knows you solved this assignment
csrf-login-failed=The solution is not correct, you are clicking the button while logged in as {0}

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

View File

@ -0,0 +1,7 @@
webgoat.customjs.feedback = function() {
var data = {};
$('#csrf-feedback').find('input, textarea, select').each(function(i, field) {
data[field.name] = field.value;
});
return JSON.stringify(data);
}

View File

@ -0,0 +1,23 @@
== CSRF and content-type
In the previous section we saw how relying on the content-type is not a protection against
CSRF. In this section we will look into another way we can perform a CSRF attack against
a APIs which are not protected against CSRF.
In this assignment you need to achieve to POST the following JSON message to our endpoints:
[source]
----
POST /csrf/feedback HTTP/1.1
{
"name" : "WebGoat",
"email" : "webgoat@webgoat.org"
"content" : "WebGoat is the best!!"
}
----
More information can be found http://pentestmonkey.net/blog/csrf-xml-post-request[here]
Remember you need to make the call from another origin (WebWolf can help here) and you need to be logged in into
WebGoat.

View File

@ -0,0 +1,22 @@
=== Automatic support from frameworks
Most frameworks now have default support for preventing CSRF. For example with Angular an interceptor reads a token
from a cookie by default XSRF-TOKEN and sets it as an HTTP header, X-XSRF-TOKEN. Since only code that runs on your domain
could read the cookie, the backend can be certain that the HTTP request came from your client application and not an attacker.
In order for this to work the backend server sets the token in a cookie. As the value of the cookie should be read
by Angular (JavaScript) this cookie should not be marked with the http-only flag. On every request towards the server
Angular will put the token in the X-XSRF-TOKEN as a HTTP header. The server can validate whether those two tokens
match and this will ensure the server the request is running on the same domain.
*Important: DEFINE A SEPARATE COOKIE, DO NOT REUSE THE SESSION COOKIE*
Remember the session cookie should always be defined with http-only flag.
Another effective defense can be to add a custom request header to each call. This will work if all the interactions
with the server are performed with JavaScript. On the server side you only need to check the presence of this header
if this header is not present deny the request.

View File

@ -0,0 +1,46 @@
**But I only have JSON APIs and no CORS enabled, how can those be susceptible to CSRF?**
A lot of web applications implement no protection against CSRF they are somehow protected by the fact that
they only work with `application/json` as content type. The only way to make a request with this content-type from the
browser is with a XHR request. Before the browser can make such a request a preflight request will be made towards
the server (remember the CSRF request will be cross origin). If the preflight response does not allow the cross origin
request the browser will not make the call.
To make a long answer short: this is *not* a valid protection against CSRF.
One example why this protection is not enough can be found https://bugs.chromium.org/p/chromium/issues/detail?id=490015[here].
Turns out `Navigator.sendBeacon()` was allowed to send POST request with an arbitrary content-type.
[qoute, developer.mozilla.org]
____
The navigator.sendBeacon() method can be used to asynchronously transfer a small amount of
data over HTTP to a web server. This method addresses the needs of analytics and diagnostics
code that typically attempts to send data to a web server prior to the unloading of the
document. Sending the data any sooner may result in a missed opportunity to gather data..."
____
{nbsp} +
For example:
[source]
----
function postBeacon() {
var data= new Blob([JSON.stringify({"author" :"WebGoat"})], {type : 'application/json'});
navigator.sendBeacon("http://localhost:8083", data)
}
----
[quote, Eduardo Vela]
____
I think Content-Type restrictions are useful for websites that are accidentally safe against CSRF. They are not meant to be, but they are because they happen to only accept XML or JSON payloads.
That said, it's somewhat obvious the websites depending on this behavior should be fixed, and any reputable pentesters will point that out. The issue is whether it's the browser responsibility to act as a nanny to weak websites, or we should leave weak websites as sacrifice for great justice. Survival of the fittest.
IMHO, the answer is somewhere in between, and a good first step would be to document all these Same Origin Policy gotchas that websites might depend upon for security.
But wrt to this bug in specific, if it never got fixed, I don't think it would be the end of the world. But then again, on this day and age, maybe there's a way to launch nuclear missiles with a XML RPC interface, so maybe it would be the end of the world.
____
{nbsp} +
Both Firefox and Chrome fixed this issue, but it shows why you should implement a CSRF protection instead
of relying on the content-type of your APIs.

View File

@ -0,0 +1,24 @@
:blank: pass:[ +]
== Login CSRF attack
In a login CSRF attack, the attacker forges a login request to an honest site using the attackers username
and password at that site. If the forgery succeeds, the honest server responds with a `Set-Cookie` header
that instructs the browser to mutate its state by storing a session cookie, logging the user into
the honest site as the attacker. This session cookie is used to bind subsequent requests to the users session and hence
to the attackers authentication credentials. Login CSRF attacks can have serious consequences, for example
see the picture below where an attacker created an account at google.com the victim visits the malicious
website and the user is logged in as the attacker. The attacker could then later on gather information about
the activities of the user.
{blank}
image::images/login-csrf.png[caption="Figure: ", title="Login CSRF from Robust Defenses for Cross-Site Request Forgery", width="800", height="500", style="lesson-image" link="http://seclab.stanford.edu/websec/csrf/csrf.pdf"]
{blank}
For more information read the following http://seclab.stanford.edu/websec/csrf/csrf.pdf[paper]
In this assignment try to see if WebGoat is also vulnerable for a login CSRF attack. First create a user
based on your own username prefixed with csrf. So if your username is `tom` you must create
a new user called `csrf-tom`

View File

@ -1,9 +1,9 @@
== Post a review on someone else's behalf == Post a review on someone else's behalf
The page below simulates a comment/review page. The difference here is that you have to inititate the submission elsewhere as you might The page below simulates a comment/review page. The difference here is that you have to initiate the submission elsewhere as you might
with a CSRF attack and like the previous exercise. It's easier than you think. In most cases, the trickier part is with a CSRF attack and like the previous exercise. It's easier than you think. In most cases, the trickier part is
finding somewhere that you want to execute the CSRF attack. The classic example is account/wire transfers in someone's bank account. finding somewhere that you want to execute the CSRF attack. The classic example is account/wire transfers in someone's bank account.
But we're keepoing it simple here. In this case, you just need to trigger a review submission on behalf of the currently But we're keeping it simple here. In this case, you just need to trigger a review submission on behalf of the currently
logged in user. logged in user.

View File

@ -0,0 +1,58 @@
package org.owasp.webgoat.plugin;
import org.hamcrest.core.StringContains;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import javax.servlet.http.Cookie;
import static org.hamcrest.core.Is.is;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author nbaars
* @since 11/17/17.
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class CSRFFeedbackTest extends LessonTest {
@Before
public void setup() throws Exception {
CSRF csrf = new CSRF();
when(webSession.getCurrentLesson()).thenReturn(csrf);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
when(webSession.getUserName()).thenReturn("unit-test");
}
@Test
public void postingJsonMessageThroughWebGoatShouldWork() throws Exception {
mockMvc.perform(post("/csrf/feedback/message")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\": \"Test\", \"email\": \"test1233@dfssdf.de\", \"subject\": \"service\", \"message\":\"dsaffd\"}"))
.andExpect(status().isOk());
}
@Test
public void csrfAttack() throws Exception {
mockMvc.perform(post("/csrf/feedback/message")
.contentType(MediaType.TEXT_PLAIN)
.cookie(new Cookie("JSESSIONID", "test"))
.header("host", "localhost:8080")
.header("referer", "webgoat.org")
.content("{\"name\": \"Test\", \"email\": \"test1233@dfssdf.de\", \"subject\": \"service\", \"message\":\"dsaffd\"}"))
.andExpect(jsonPath("lessonCompleted", is(true)))
.andExpect(jsonPath("feedback", StringContains.containsString("the flag is: ")));
}
}

View File

@ -1,55 +0,0 @@
##### To include lesson template in build #####
1. edit theh webgoat-server/pom.xml file and uncomment the section under ...
<!--uncommment below to run/include lesson template in WebGoat Build-->
2. Also uncomment in webgoat-lessons/pom.xml where it says ...
<!-- uncomment below to include lesson template in build, also uncomment the dependency in webgoat-server/pom.xml-->
##### To add a lesson to WebGoat #####
There are a number of moving parts and this sample lesson will help you navigate those parts. Most of your work will be done in two directories. To start though, you can copy this directory with the name of your-lesson in the webgoat-lessons directory.
0. The POM file
a. change the ...
<artifactId>webgoat-lesson-template</artifactId>
... line to give your lesson its own artifactId.That should be all you need to do there
1. The Base Class ...
In webgoat-lessons/{your-lesson}/src/main/java, refactor the LessonTemplate.java class, changing ...
a. the category in which you want your lesson to be in. You can create a new category if you want, or put in an issue to have one added
b. The 'defaultRanking' will move your lesson up or down in the categories list
c. implement a new key name pair "lesson-template.title" (the key) and update the same key/value pair (your.key=your value) in src/main/resources/i18n/WebGoatLabels.properties
d. Implement a new value for the getId method, which leads us to ...
2. The HTML content framing ...
a. Rename the provided file in src/main/resources/html using your value from the getId method in your lesson's base class (e.g. public String getId() { return "your-lesson"; } >> "your-lesson.html")
b. Modify that file following the commented instructions in there
c. In conjunction with this file you
3. Assignment Endpoints
a. In the above html file, you will see an example of an 'attack form'. You can create endpoints to handle these attacks and provide the user feedback and simulated output. See the example file here as well as other existing lessons for ways to extend these. You will extend the AssignmentEndpoint as the example will show
b. You can also create supporting (non-assignment) endpoints, that are not evaluated/graded.
c. See other lesson examples for creating unit/integration tests for your project as well
4. Getting your lesson to show up
a. modify the webgoat-lessons/pom.xml to include your project in the <modules> section
<modules>
<!-- ... -->
<module>webgoat-lesson-template</module>
<!-- ... -->
</modules>
b. modify the webgoat-server/pom.xml to add your project as a dependency in the <dependencies> section ...
<dependencies>
<!-- .... >
<dependency>
<groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>your-artfifact-id-here</artifactId>
<version>${project.version}</version>
</dependency>
<!-- .... >
<dependencies>
5. You should be ready to run and test your project. Please create issues at https://github.com/WebGoat/WebGoat if there errors or confusion with this documentation/template

View File

@ -1,62 +0,0 @@
package org.owasp.webgoat.plugin;
import com.google.common.collect.Lists;
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.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by jason on 1/5/17.
*/
@AssignmentPath("/lesson-template/sample-attack")
public class SampleAttack extends AssignmentEndpoint {
String secretValue = "secr37Value";
//UserSessionData is bound to session and can be used to persist data across multiple assignments
@Autowired
UserSessionData userSessionData;
@GetMapping(produces = {"application/json"})
public @ResponseBody
AttackResult completed(String param1, String param2, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (userSessionData.getValue("some-value") != null) {
// do any session updating you want here ... or not, just comment/example here
//return trackProgress(failed().feedback("lesson-template.sample-attack.failure-2").build());
}
//overly simple example for success. See other existing lesssons for ways to detect 'success' or 'failure'
if (secretValue.equals(param1)) {
return trackProgress(success()
.output("Custom Output ...if you want, for success")
.feedback("lesson-template.sample-attack.success")
.build());
//lesson-template.sample-attack.success is defined in src/main/resources/i18n/WebGoatLabels.properties
}
// else
return trackProgress(failed()
.feedback("lesson-template.sample-attack.failure-2")
.output("Custom output for this failure scenario, usually html that will get rendered directly ... yes, you can self-xss if you want")
.build());
}
}

View File

@ -1,54 +0,0 @@
<html xmlns:th="http://www.thymeleaf.org">
<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 go in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:lesson-template-intro.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<!-- reuse the above 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:lesson-template-video.adoc"></div>
<!-- can use multiple adoc's in a page-wrapper if you want ... or not-->
<div class="adoc-content" th:replace="doc:lesson-template-attack.adoc"></div>
<!-- WebGoat will automatically style and scaffold some functionality by using the div.attack-container as below -->
<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 -->
<!-- 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 -->
<!-- modify the action to point to the intended endpoint and set other attributes as desired -->
<script th:src="@{/lesson_js/idor.js}" />
<form class="attack-form" accept-charset="UNKNOWN"
method="GET" name="form"
action="/WebGoat/lesson-template/sample-attack"
enctype="application/json;charset=UTF-8">
<table>
<tr>
<td>two random params</td>
<td>parameter 1:<input name="param1" value="" type="TEXT" /></td>
<td>parameter 2:<input name="param2" value="" type="TEXT" /></td>
<td>
<input
name="submit" value="Submit" type="SUBMIT"/>
</td>
</tr>
</table>
</form>
<!-- do not remove the two following div's, this is where your feedback/output will land -->
<!-- the attack response will include a 'feedback' and that will automatically go here -->
<div class="attack-feedback"></div>
<!-- output is intended to be a simulation of what the screen would display in an attack -->
<div class="attack-output"></div>
</div>
</div>
<!-- repeat and mix-and-match the lesson-page-wrappers with or wihtout the attack-containers as you like ...
see other lessons for other more complex examples -->
</html>

View File

@ -1,7 +0,0 @@
lesson-template.title=Lesson Template
lesson-template.sample-attack.failure-1=Sample failure message
lesson-template.sample-attack.failure-2=Sample failure message 2
lesson-template.sample-attack.success=Sample success message

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

View File

@ -1,18 +0,0 @@
// need custom js for this?
webgoat.customjs.idorViewProfile = function(data) {
webgoat.customjs.jquery('#idor-profile').html(
'name:' + data.name + '<br/>'+
'color:' + data.color + '<br/>'+
'size:' + data.size + '<br/>'
);
}
var onViewProfile = function () {
console.warn("on view profile activated")
webgoat.customjs.jquery.ajax({
method: "GET",
url: "/WebGoat/IDOR/profile",
contentType: 'application/json; charset=UTF-8'
}).then(webgoat.customjs.idorViewProfile);
}

View File

@ -1,3 +0,0 @@
=== Attack Explanation
Explanation of attack here ... Instructions etc.

View File

@ -1,19 +0,0 @@
== Lesson Template Intro
This is the lesson template intro.
=== Sub-heading
Check asciidoc for syntax, but more = means smaller headings. You can *bold* text and other things.
=== Structuring files
You should set up all content so that it is these *.adoc files.
=== Images
Images can be refereneced as below including setting style (recommended to use lesson-image as the style). The root is {lesson}/src/main/resources
image::images/firefox-proxy-config.png[Firefox Proxy Config,510,634,style="lesson-image"]

View File

@ -1,7 +0,0 @@
=== More Content, Video too ...
You can structure and format the content however you like. You can even include video if you like (but may be subject to browser support). You may want to make it more pertinent to web application security than this though.
video::video/sample-video.m4v[width=480,start=5]
see http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/#videos for more detail on video syntax

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
<dependencies> <dependencies>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
</project> </project>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
<dependencies> <dependencies>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
</project> </project>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
<dependencies> <dependencies>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
</project> </project>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
</project> </project>

View File

@ -5,12 +5,12 @@
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
<parent> <parent>
<groupId>org.owasp.webgoat</groupId> <groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-parent</artifactId> <artifactId>webgoat-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
<modules> <modules>
@ -27,6 +27,7 @@
<module>xxe</module> <module>xxe</module>
<module>idor</module> <module>idor</module>
<module>vulnerable-components</module> <module>vulnerable-components</module>
<module>webgoat-introduction</module>
<module>webwolf-introduction</module> <module>webwolf-introduction</module>
<module>auth-bypass</module> <module>auth-bypass</module>
<module>missing-function-ac</module> <module>missing-function-ac</module>
@ -42,34 +43,13 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>provided</scope>
<type>jar</type> <type>jar</type>
<!-- Exclude Mongo embedded so testcases do not start it automatically, seems to be
the easiest way to stop the autoconfiguration of Spring Boot -->
<exclusions>
<exclusion>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!--<dependency>-->
<!--<groupId>org.apache.commons</groupId>-->
<!--<artifactId>commons-exec</artifactId>-->
<!--<version>1.3</version>-->
<!--</dependency>-->
<dependency> <dependency>
<groupId>org.owasp.webgoat</groupId> <groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-container</artifactId> <artifactId>webgoat-container</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<classifier>tests</classifier> <classifier>tests</classifier>
<scope>test</scope> <scope>test</scope>
<!-- Exclude Mongo embedded so testcases do not start it automatically, seems to be
the easiest way to stop the autoconfiguration of Spring Boot -->
<exclusions>
<exclusion>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
@ -95,12 +75,6 @@
<version>4.1.3.RELEASE</version> <version>4.1.3.RELEASE</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.github.fakemongo</groupId>
<artifactId>fongo</artifactId>
<version>2.1.0</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.owasp.encoder</groupId> <groupId>org.owasp.encoder</groupId>
<artifactId>encoder</artifactId> <artifactId>encoder</artifactId>

View File

@ -11,6 +11,7 @@ bender@juice-sh.op' --
101 or 1=1 101 or 1=1
Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data -- Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data --
Smith' union select all 1, '2' ,user_name,password, 'MC', cookie, 2 from user_system_data --
## XXE ## ## XXE ##

View File

@ -6,6 +6,6 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
</project> </project>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
<dependencies> <dependencies>
<dependency> <dependency>

View File

@ -1,12 +1,11 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>webgoat-lesson-template</artifactId> <artifactId>webgoat-introduction</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0-SNAPSHOT</version> <version>8.0.0.M3</version>
</parent> </parent>
</project> </project>

View File

@ -0,0 +1,11 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>webwolf-introduction</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId>
<version>8.0-SNAPSHOT</version>
</parent>
</project>

View File

@ -1,9 +1,9 @@
package org.owasp.webgoat.plugin; package org.owasp.webgoat.plugin;
import com.beust.jcommander.internal.Lists;
import org.owasp.webgoat.lessons.Category; import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson; import org.owasp.webgoat.lessons.NewLesson;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@ -31,35 +31,33 @@ import java.util.List;
* projects. * projects.
* <p> * <p>
* *
* @author misfir3 * @author WebGoat
* @version $Id: $Id * @version $Id: $Id
* @since January 3, 2017 * @since October 12, 2016
*/ */
public class LessonTemplate extends NewLesson { public class WebGoatIntroduction extends NewLesson {
@Override @Override
public Category getDefaultCategory() { public Category getDefaultCategory() {
return Category.GENERAL; return Category.INTRODUCTION;
} }
@Override @Override
public List<String> getHints() { public List<String> getHints() {
return Lists.newArrayList(); return new ArrayList();
} }
@Override @Override
public Integer getDefaultRanking() { public Integer getDefaultRanking() {
return 30; return 1;
} }
@Override @Override
public String getTitle() { public String getTitle() {
return "lesson-template.title"; return "webgoat.title";
} }
@Override @Override
public String getId() { public String getId() {
return "LessonTemplate"; return "WebGoatIntroduction";
} }
} }

View File

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Introduction.adoc"></div>
</div>
</html>

View File

@ -0,0 +1 @@
webgoat.title=WebGoat

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -0,0 +1,18 @@
== What is WebGoat?
---
WebGoat is a deliberately insecure application that allows interested developers just like you to _test vulnerabilities_
commonly found in Java-based applications that use common and popular open source components.
Now, while we in no way condone causing intentional harm to any animal, goat or otherwise, we think learning everything
you can about security vulnerabilities is essential to understanding just what happens when even a small bit of
unintended code gets into your applications.
What better way to do that than with your very own scapegoat?
Feel free to do what you will with Hack. Poke, prod and if it makes you feel better, scare him until your hearts content.
Go ahead, and Hack the goat. We promise he likes it.
Thanks for your interest!
*The WebGoat Team*

View File

@ -6,6 +6,6 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
</project> </project>

View File

@ -22,7 +22,7 @@ public class MailAssignment extends AssignmentEndpoint {
private final String webWolfURL; private final String webWolfURL;
private RestTemplate restTemplate; private RestTemplate restTemplate;
public MailAssignment(RestTemplate restTemplate, @Value("${webwolf.url}") String webWolfURL) { public MailAssignment(RestTemplate restTemplate, @Value("${webwolf.url.mail}") String webWolfURL) {
this.restTemplate = restTemplate; this.restTemplate = restTemplate;
this.webWolfURL = webWolfURL; this.webWolfURL = webWolfURL;
} }
@ -36,10 +36,10 @@ public class MailAssignment extends AssignmentEndpoint {
.recipient(username) .recipient(username)
.title("Test messages from WebWolf") .title("Test messages from WebWolf")
.time(LocalDateTime.now()) .time(LocalDateTime.now())
.contents("This is a test message from WebWolf, your unique code is" + StringUtils.reverse(username)) .contents("This is a test message from WebWolf, your unique code is: " + StringUtils.reverse(username))
.sender("webgoat@owasp.org") .sender("webgoat@owasp.org")
.build(); .build();
restTemplate.postForEntity(webWolfURL + "/WebWolf/mail", mailEvent, Object.class); restTemplate.postForEntity(webWolfURL, mailEvent, Object.class);
return informationMessage().feedback("webwolf.email_send").feedbackArgs(email).build(); return informationMessage().feedback("webwolf.email_send").feedbackArgs(email).build();
} else { } else {
return informationMessage().feedback("webwolf.email_mismatch").feedbackArgs(username).build(); return informationMessage().feedback("webwolf.email_mismatch").feedbackArgs(username).build();

View File

@ -2,7 +2,7 @@
<html xmlns:th="http://www.thymeleaf.org"> <html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Introduction.adoc"></div> <div class="adoc-content" th:replace="doc:IntroductionWebWolf.adoc"></div>
</div> </div>
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
@ -12,9 +12,10 @@
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Receiving_mail.adoc"></div> <div class="adoc-content" th:replace="doc:Receiving_mail.adoc"></div>
<div class="attack-container"> <div class="attack-container">
<form accept-charset="UNKNOWN" <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/WebWolf/send" action="/WebGoat/WebWolf/mail/send"
enctype="application/json;charset=UTF-8"> enctype="application/json;charset=UTF-8">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">

View File

@ -1,5 +1,8 @@
== Introducing WebWolf == Introducing WebWolf
NOTE: You only need WebWolf if you a lesson specifies you can use it. For a lot of lessons you use WebGoat without
starting WebWolf.
WebWolf is a separate web application which simulates an attackers machine. It makes it possible for us to WebWolf is a separate web application which simulates an attackers machine. It makes it possible for us to
make a clear distinction between what takes place on the attacked website and the actions you need to do as make a clear distinction between what takes place on the attacked website and the actions you need to do as
an "attacker". WebWolf was introduced after a couple of workshops where we received feedback about the fact there an "attacker". WebWolf was introduced after a couple of workshops where we received feedback about the fact there

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId> <artifactId>webgoat-lessons-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
<dependencies> <dependencies>

View File

@ -1,7 +1,8 @@
package org.owasp.webgoat.plugin; package org.owasp.webgoat.plugin;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.apache.commons.io.FileUtils;
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;
@ -63,7 +64,7 @@ public class BlindSendFileAssignment extends AssignmentEndpoint {
if (!targetDirectory.exists()) { if (!targetDirectory.exists()) {
targetDirectory.mkdir(); targetDirectory.mkdir();
} }
FileUtils.write(new File(targetDirectory, "secret.txt"), CONTENTS); Files.write(CONTENTS, new File(targetDirectory, "secret.txt"), Charsets.UTF_8);
} }
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.ALL_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(method = RequestMethod.POST, consumes = MediaType.ALL_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)

View File

@ -19,7 +19,13 @@ import javax.xml.stream.XMLStreamReader;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.util.Collection; import java.util.Collection;
import java.util.Comparator;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import static java.util.Optional.empty;
import static java.util.Optional.of;
/** /**
* @author nbaars * @author nbaars
@ -50,7 +56,7 @@ public class Comments {
allComments.addAll(xmlComments); allComments.addAll(xmlComments);
} }
allComments.addAll(comments); allComments.addAll(comments);
return allComments; return allComments.stream().sorted(Comparator.comparing(Comment::getDateTime).reversed()).collect(Collectors.toList());
} }
protected Comment parseXml(String xml) throws Exception { protected Comment parseXml(String xml) throws Exception {
@ -67,12 +73,12 @@ public class Comments {
return (Comment) unmarshaller.unmarshal(xsr); return (Comment) unmarshaller.unmarshal(xsr);
} }
protected Comment parseJson(String comment) { protected Optional<Comment> parseJson(String comment) {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
try { try {
return mapper.readValue(comment, Comment.class); return of(mapper.readValue(comment, Comment.class));
} catch (IOException e) { } catch (IOException e) {
return new Comment(); return empty();
} }
} }

View File

@ -61,27 +61,26 @@ public class ContentTypeAssignment extends AssignmentEndpoint {
@ResponseBody @ResponseBody
public AttackResult createNewUser(@RequestBody String commentStr, @RequestHeader("Content-Type") String contentType) throws Exception { public AttackResult createNewUser(@RequestBody String commentStr, @RequestHeader("Content-Type") String contentType) throws Exception {
AttackResult attackResult = failed().build(); AttackResult attackResult = failed().build();
Comment comment = null;
if (APPLICATION_JSON_VALUE.equals(contentType)) { if (APPLICATION_JSON_VALUE.equals(contentType)) {
comment = comments.parseJson(commentStr); comments.parseJson(commentStr).ifPresent(c -> comments.addComment(c, true));
comments.addComment(comment, true);
attackResult = failed().feedback("xxe.content.type.feedback.json").build(); attackResult = failed().feedback("xxe.content.type.feedback.json").build();
} }
if (MediaType.APPLICATION_XML_VALUE.equals(contentType)) { if (MediaType.APPLICATION_XML_VALUE.equals(contentType)) {
String error = ""; String error = "";
try { try {
comment = comments.parseXml(commentStr); Comment comment = comments.parseXml(commentStr);
comments.addComment(comment, false); comments.addComment(comment, false);
if (checkSolution(comment)) {
attackResult = success().build();
}
} catch (Exception e) { } catch (Exception e) {
error = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); error = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e);
attackResult = failed().feedback("xxe.content.type.feedback.xml").output(error).build();
} }
attackResult = failed().feedback("xxe.content.type.feedback.xml").output(error).build();
} }
if (checkSolution(comment)) {
attackResult = success().build();
}
return trackProgress(attackResult); return trackProgress(attackResult);
} }
@ -89,7 +88,7 @@ public class ContentTypeAssignment extends AssignmentEndpoint {
String[] directoriesToCheck = OS.isFamilyUnix() ? DEFAULT_LINUX_DIRECTORIES : DEFAULT_WINDOWS_DIRECTORIES; String[] directoriesToCheck = OS.isFamilyUnix() ? DEFAULT_LINUX_DIRECTORIES : DEFAULT_WINDOWS_DIRECTORIES;
boolean success = true; boolean success = true;
for (String directory : directoriesToCheck) { for (String directory : directoriesToCheck) {
success &= comment.getText().contains(directory); success &= org.apache.commons.lang3.StringUtils.contains(comment.getText(), directory);
} }
return success; return success;
} }

View File

@ -26,6 +26,7 @@
method="POST" name="form" method="POST" name="form"
prepareData="simpleXXE" prepareData="simpleXXE"
successCallback="simpleXXECallback" successCallback="simpleXXECallback"
failureCallback="simpleXXECallback"
contentType="application/xml" contentType="application/xml"
action="/WebGoat/xxe/simple"> action="/WebGoat/xxe/simple">
<div class="container-fluid"> <div class="container-fluid">
@ -82,6 +83,7 @@
method="POST" name="form" method="POST" name="form"
prepareData="contentTypeXXE" prepareData="contentTypeXXE"
successCallback="contentTypeXXECallback" successCallback="contentTypeXXECallback"
failureCallback="contentTypeXXECallback"
action="xxe/content-type" action="xxe/content-type"
contentType="application/json"> contentType="application/json">
<div class="container-fluid"> <div class="container-fluid">
@ -147,6 +149,7 @@
method="POST" name="form" method="POST" name="form"
prepareData="blindXXE" prepareData="blindXXE"
successCallback="blindXXECallback" successCallback="blindXXECallback"
failureCallback="blindXXECallback"
action="/WebGoat/xxe/blind" action="/WebGoat/xxe/blind"
contentType="application/xml"> contentType="application/xml">
<div class="container-fluid"> <div class="container-fluid">

View File

@ -8,7 +8,7 @@ webgoat.customjs.simpleXXE = function () {
} }
webgoat.customjs.simpleXXECallback = function() { webgoat.customjs.simpleXXECallback = function() {
$("#commentInputBlind").val(''); $("#commentInputSimple").val('');
getComments('#commentsListSimple'); getComments('#commentsListSimple');
} }
@ -16,6 +16,25 @@ $(document).ready(function () {
getComments('#commentsListSimple'); getComments('#commentsListSimple');
}); });
//// Content-type
webgoat.customjs.contentTypeXXE = function() {
var commentInput = $("#commentInputContentType").val();
return JSON.stringify({text: commentInput});
}
webgoat.customjs.contentTypeXXECallback = function() {
$("#commentInputContentType").val('');
getComments('#commentsListContentType');
}
$(document).ready(function () {
getComments('#commentsListContentType');
});
//// Blind
webgoat.customjs.blindXXE = function() { webgoat.customjs.blindXXE = function() {
var commentInput = $("#commentInputBlind").val(); var commentInput = $("#commentInputBlind").val();
var xml = '<?xml version="1.0"?>' + var xml = '<?xml version="1.0"?>' +
@ -34,19 +53,7 @@ $(document).ready(function () {
getComments('#commentsListBlind'); getComments('#commentsListBlind');
}); });
webgoat.customjs.contentTypeXXE = function() {
var commentInput = $("#commentInputContentType").val();
return JSON.stringify({text: commentInput});
}
webgoat.customjs.contentTypeXXECallback = function() {
$("#commentInputContentType").val('');
getComments('#commentsListContentType');
}
$(document).ready(function () {
getComments('#commentsListContentType');
});
var html = '<li class="comment">' + var html = '<li class="comment">' +
'<div class="pull-left">' + '<div class="pull-left">' +

View File

@ -0,0 +1,75 @@
package org.owasp.webgoat.plugin;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author nbaars
* @since 11/2/17.
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class ContentTypeAssignmentTest extends LessonTest {
@Autowired
private Comments comments;
@Before
public void setup() throws Exception {
XXE xxe = new XXE();
when(webSession.getCurrentLesson()).thenReturn(xxe);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
when(webSession.getUserName()).thenReturn("unit-test");
}
@Test
public void sendingXmlButContentTypeIsJson() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/content-type")
.contentType(MediaType.APPLICATION_JSON)
.content("<?xml version=\"1.0\" standalone=\"yes\" ?><!DOCTYPE user [<!ENTITY root SYSTEM \"file:///\"> ]><comment><text>&root;</text></comment>"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("xxe.content.type.feedback.json"))));
}
@Test
public void workingAttack() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/content-type")
.contentType(MediaType.APPLICATION_XML)
.content("<?xml version=\"1.0\" standalone=\"yes\" ?><!DOCTYPE user [<!ENTITY root SYSTEM \"file:///\"> ]><comment><text>&root;</text></comment>"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.solved"))));
}
@Test
public void postingJsonShouldAddComment() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/content-type")
.contentType(MediaType.APPLICATION_JSON)
.content("{ \"text\" : \"Hello World\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("xxe.content.type.feedback.json"))));
assertThat(comments.getComments().stream().filter(c -> c.getText().equals("Hello World")).count()).isEqualTo(1);
}
@Test
public void postingInvalidJsonShouldAddComment() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/content-type")
.contentType(MediaType.APPLICATION_JSON)
.content("{ 'text' : 'Wrong'"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("xxe.content.type.feedback.json"))));
assertThat(comments.getComments().stream().filter(c -> c.getText().equals("Wrong")).count()).isEqualTo(0);
}
}

View File

@ -0,0 +1,66 @@
package org.owasp.webgoat.plugin;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author nbaars
* @since 11/2/17.
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class SimpleXXETest extends LessonTest {
@Before
public void setup() throws Exception {
XXE xxe = new XXE();
when(webSession.getCurrentLesson()).thenReturn(xxe);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
when(webSession.getUserName()).thenReturn("unit-test");
}
@Test
public void workingAttack() throws Exception {
//Call with XXE injection
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/simple")
.content("<?xml version=\"1.0\" standalone=\"yes\" ?><!DOCTYPE user [<!ENTITY root SYSTEM \"file:///\"> ]><comment><text>&root;</text></comment>"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.solved"))));
}
@Test
public void postingJsonCommentShouldNotSolveAssignment() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/simple")
.content("<comment><text>test</ext></comment>"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved"))));
}
@Test
public void postingXmlCommentWithoutXXEShouldNotSolveAssignment() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/simple")
.content("<?xml version=\"1.0\" standalone=\"yes\" ?><comment><text>&root;</text></comment>"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved"))));
}
@Test
public void postingPlainTextShouldShwoException() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/simple")
.content("test"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.output", CoreMatchers.startsWith("javax.xml.bind.UnmarshalException\\n - with linked exception")))
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved"))));
}
}

View File

@ -10,7 +10,5 @@ COPY start.sh /home/webgoat/start.sh
RUN chmod +x /home/webgoat/start.sh RUN chmod +x /home/webgoat/start.sh
USER webgoat USER webgoat
RUN mkdir -p /home/webgoat/.embedmongo/linux
RUN curl -o /home/webgoat/.embedmongo/linux/mongodb-linux-x86_64-3.2.2.tgz https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.2.2.tgz
RUN cd /home/webgoat/; mkdir -p .webgoat RUN cd /home/webgoat/; mkdir -p .webgoat
COPY target/webgoat-server-${webgoat_version}.jar /home/webgoat/webgoat.jar COPY target/webgoat-server-${webgoat_version}.jar /home/webgoat/webgoat.jar

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat</groupId> <groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-parent</artifactId> <artifactId>webgoat-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
<properties> <properties>
@ -87,12 +87,8 @@
<groupId>com.spotify</groupId> <groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId> <artifactId>docker-maven-plugin</artifactId>
<version>0.4.10</version> <version>0.4.10</version>
<scope>compile</scope> <scope>test</scope>
</dependency> <optional>true</optional>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<version>2.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.owasp.webgoat</groupId> <groupId>org.owasp.webgoat</groupId>
@ -174,6 +170,11 @@
<artifactId>auth-bypass</artifactId> <artifactId>auth-bypass</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-introduction</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.owasp.webgoat.lesson</groupId> <groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webwolf-introduction</artifactId> <artifactId>webwolf-introduction</artifactId>
@ -205,6 +206,7 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <configuration>
<excludeDevtools>true</excludeDevtools>
<!-- See http://docs.spring.io/spring-boot/docs/current/reference/html/howto-build.html#howto-extract-specific-libraries-when-an-executable-jar-runs --> <!-- See http://docs.spring.io/spring-boot/docs/current/reference/html/howto-build.html#howto-extract-specific-libraries-when-an-executable-jar-runs -->
<requiresUnpack> <requiresUnpack>
<dependency> <dependency>

View File

@ -1,40 +0,0 @@
package org.owasp.webgoat;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import de.flapdoodle.embed.mongo.MongodExecutable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import java.io.IOException;
/**
* If we run
*/
@Configuration
@ConditionalOnProperty(value = "webgoat.embedded.mongo", havingValue = "false")
public class ExternalMongoConfiguration {
@Autowired
private MongoProperties properties;
@Autowired(required = false)
private MongoClientOptions options;
@Bean
public MongodExecutable mongodExecutable() throws IOException {
return null;
}
@Bean
public MongoDbFactory mongoDbFactory(Environment env) throws Exception {
MongoClient client = properties.createMongoClient(this.options, env);
return new SimpleMongoDbFactory(client, properties.getDatabase());
}
}

View File

@ -1,4 +0,0 @@
WG_MONGO_PORT=27017
WG_MONGO_HOST=mongo
WG_MQ_HOST=activemq
WG_MQ_PORT=61616

View File

@ -1,146 +0,0 @@
#!/bin/bash
# Bootstrap the setup of WebGoat for developer use in Linux and Mac machines
# This script will clone the necessary git repositories, call the maven goals
# in the order the are needed and launch tomcat listening on localhost:8080
# Happy hacking !
# Find out what is our terminal size
COLS="$(tput cols)"
if (( COLS <= 0 )) ; then
COLS="${COLUMNS:-80}"
fi
# Colors
ESC_SEQ="\x1b["
COL_RESET=$ESC_SEQ"39;49;00m"
COL_RED=$ESC_SEQ"31;01m"
COL_GREEN=$ESC_SEQ"32;01m"
COL_YELLOW=$ESC_SEQ"33;01m"
COL_BLUE=$ESC_SEQ"34;01m"
COL_MAGENTA=$ESC_SEQ"35;01m"
COL_CYAN=$ESC_SEQ"36;01m"
# Horizontal Rule function
horizontal_rule() {
local WORD
for WORD in "#"
do
hr "$WORD"
done
}
hr() {
local WORD="$1"
if [[ -n "$WORD" ]] ; then
local LINE=''
while (( ${#LINE} < COLS ))
do
LINE="$LINE$WORD"
done
echo -e "${LINE:0:$COLS}"
fi
}
## test if command exists
ftest() {
echo -e "$COL_CYAN info: Checking if ${1} is installed $COL_RESET"
if ! type "${1}" > /dev/null 2>&1; then
return 1
else
return 0
fi
}
## feature tests
features() {
for f in "${@}"; do
ftest "${f}" || {
echo -e >&2 "***$COL_RED ERROR: Missing \`${f}'! Make sure it exists and try again. $COL_RESET"
return 1
}
done
return 0
}
tomcat_started () {
STAT=`netstat -na | grep 8080 | awk '{print $6}'`
if [ "$STAT" = "LISTEN" ]; then
echo -e "$COL_GREEN WebGoat has started successfully! Browse to the following address. $COL_RESET"
echo -e "$COL_CYAN Happy Hacking! $COL_RESET"
return 0
elif [ "$STAT" = "" ]; then
echo -e "$COL_RED WebGoat failed to start up.... please wait run the following command for debugging : $COL_RESET"
echo -e "$COL_MAGENTA mvn -q -file WebGoat/pom.xml -pl webgoat-container tomcat7:run-war"
fi
return 1
}
## main setup
developer_bootstrap() {
horizontal_rule
echo -e "$COL_RED
██╗ ██╗███████╗██████╗ ██████╗ ██████╗ █████╗ ████████╗
██║ ██║██╔════╝██╔══██╗██╔════╝ ██╔═══██╗██╔══██╗╚══██╔══╝
██║ █╗ ██║█████╗ ██████╔╝██║ ███╗██║ ██║███████║ ██║
██║███╗██║██╔══╝ ██╔══██╗██║ ██║██║ ██║██╔══██║ ██║
╚███╔███╔╝███████╗██████╔╝╚██████╔╝╚██████╔╝██║ ██║ ██║
╚══╝╚══╝ ╚══════╝╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
$COL_RESET"
horizontal_rule
echo -e "Welcome to the WebGoat Developer Bootstrap script for Linux/Mac."
echo -e "Now checking if all the required software to run WebGoat is already installed."
echo -e "FYI: This Developer Bootstrap Script for WebGoat requires: Git, Java JDK and Maven accessible on the path"
## test for require features
features git mvn java || return $?
# Clone WebGoat from github
if [ ! -d "WebGoat" ]; then
echo -e "Cloning the WebGoat container repository"
git clone https://github.com/WebGoat/WebGoat.git
else
horizontal_rule
(
echo -e "$COL_YELLOW The WebGoat container repo has already been clonned before, pulling upstream changes. $COL_RESET"
cd WebGoat || {
echo -e >&2 "$COL_RED *** ERROR: Could not cd into the WebGoat Directory. $COL_RESET"
return 1
}
git pull origin develop
)
fi
# Start the embedded Tomcat server
echo -e "$COL_MAGENTA"
horizontal_rule
horizontal_rule
horizontal_rule
horizontal_rule
echo "$COL_MAGENTA"
echo "$COL_CYAN ***** Starting WebGoat using the embedded Tomcat ***** $COL_RESET"
echo " Please be patient.... The startup of the server takes about 5 seconds..."
echo " WebGoat will be ready for you when you see the following message on the command prompt:"
echo "$COL_YELLOW INFO: Starting ProtocolHandler ["http-bio-8080"] $COL_RESET"
echo "$COL_CYAN When you see the message above, open a web browser and navigate to http://localhost:8080/WebGoat/ $COL_RESET"
echo " To stop the WebGoat and Tomcat Execution execution, press CTRL + C"
echo "$COL_RED If you close this terminal window, Tomcat and WebGoat will stop running $COL_RESET"
echo "$COL_MAGENTA"
horizontal_rule
horizontal_rule
horizontal_rule
horizontal_rule
echo -e "$COL_RESET"
sleep 5
# Starting WebGoat
mvn -q -pl webgoat-container spring-boot:run
}
# Start main script
developer_bootstrap

View File

@ -1,8 +1,13 @@
FROM openjdk:8-jre-slim FROM openjdk:8-jre-slim
ARG webwolf_version=8.0-SNAPSHOT
RUN useradd --home-dir /home/webwolf --create-home -U webwolf RUN useradd --home-dir /home/webwolf --create-home -U webwolf
USER webwolf RUN apt-get update; apt-get install curl -y
RUN cd /home/webwolf/
COPY target/webwolf-8.0-SNAPSHOT.jar /home/webwolf/webwolf.jar
COPY start.sh /home/webwolf/start.sh COPY start.sh /home/webwolf/start.sh
RUN chmod +x /home/webwolf/start.sh
USER webwolf
COPY target/webwolf-${webwolf_version}.jar /home/webwolf/webwolf.jar

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.owasp.webgoat</groupId> <groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-parent</artifactId> <artifactId>webgoat-parent</artifactId>
<version>8.0.0.M2</version> <version>8.0.0.M3</version>
</parent> </parent>
<dependencies> <dependencies>
@ -55,7 +55,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId> <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@ -73,6 +73,11 @@
<artifactId>jquery</artifactId> <artifactId>jquery</artifactId>
<version>3.2.1</version> <version>3.2.1</version>
</dependency> </dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>${hsqldb.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -2,8 +2,6 @@ package org.owasp.webwolf;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.owasp.webwolf.requests.WebWolfTraceRepository; import org.owasp.webwolf.requests.WebWolfTraceRepository;
import org.owasp.webwolf.user.UserRepository;
import org.owasp.webwolf.user.WebGoatUserToCookieRepository;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@ -16,8 +14,8 @@ import org.springframework.context.annotation.Bean;
public class WebWolf extends SpringBootServletInitializer { public class WebWolf extends SpringBootServletInitializer {
@Bean @Bean
public TraceRepository traceRepository(WebGoatUserToCookieRepository repository, UserRepository userRepository) { public TraceRepository traceRepository() {
return new WebWolfTraceRepository(repository, userRepository); return new WebWolfTraceRepository();
} }
@Override @Override

View File

@ -4,10 +4,9 @@ import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -18,7 +17,7 @@ import java.time.format.DateTimeFormatter;
*/ */
@Builder @Builder
@Data @Data
@Document @Entity
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class Email implements Serializable { public class Email implements Serializable {
@ -29,7 +28,6 @@ public class Email implements Serializable {
private String contents; private String contents;
private String sender; private String sender;
private String title; private String title;
@Indexed
private String recipient; private String recipient;
public String getSummary() { public String getSummary() {

View File

@ -5,11 +5,16 @@ import lombok.extern.slf4j.Slf4j;
import org.owasp.webwolf.user.UserRepository; import org.owasp.webwolf.user.UserRepository;
import org.owasp.webwolf.user.WebGoatUser; import org.owasp.webwolf.user.WebGoatUser;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable;
/** /**
* @author nbaars * @author nbaars
@ -37,13 +42,16 @@ public class MailboxController {
} }
@PostMapping(value = "/mail") @PostMapping(value = "/mail")
@ResponseStatus(HttpStatus.CREATED) public Callable<ResponseEntity<?>> sendEmail(@RequestBody Email email) {
public void sendEmail(@RequestBody Email email) { return () -> {
if (userRepository.findByUsername(email.getRecipient()) != null) { if (userRepository.findByUsername(email.getRecipient()) != null) {
mailboxRepository.save(email); mailboxRepository.save(email);
} else { return ResponseEntity.status(HttpStatus.CREATED).build();
log.trace("Mail received for unknown user: {}", email.getRecipient()); } else {
} log.trace("Mail received for unknown user: {}", email.getRecipient());
return ResponseEntity.notFound().build();
}
};
} }
} }

View File

@ -1,7 +1,6 @@
package org.owasp.webwolf.mailbox; package org.owasp.webwolf.mailbox;
import org.bson.types.ObjectId; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List; import java.util.List;
@ -9,7 +8,7 @@ import java.util.List;
* @author nbaars * @author nbaars
* @since 8/17/17. * @since 8/17/17.
*/ */
public interface MailboxRepository extends MongoRepository<Email, ObjectId> { public interface MailboxRepository extends JpaRepository<Email, String> {
List<Email> findByRecipientOrderByTimeDesc(String recipient); List<Email> findByRecipientOrderByTimeDesc(String recipient);

View File

@ -2,23 +2,25 @@ package org.owasp.webwolf.requests;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
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.ResponseStatus;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.Callable;
@Controller @Controller
@Slf4j @Slf4j
@RequestMapping("/landing/**") @RequestMapping("/landing/**")
public class LandingPage { public class LandingPage {
@RequestMapping(method = { RequestMethod.POST, RequestMethod.GET, RequestMethod.DELETE, RequestMethod.PATCH, RequestMethod.PUT}) @RequestMapping(method = {RequestMethod.POST, RequestMethod.GET, RequestMethod.DELETE, RequestMethod.PATCH, RequestMethod.PUT})
@ResponseStatus(HttpStatus.OK) public Callable<ResponseEntity<?>> ok(HttpServletRequest request) {
public void ok(HttpServletRequest request) { return () -> {
log.trace("Incoming request for: {}", request.getRequestURL()); log.trace("Incoming request for: {}", request.getRequestURL());
return ResponseEntity.ok().build();
};
} }
} }

View File

@ -5,9 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.owasp.webwolf.user.WebGoatUser;
import org.springframework.boot.actuate.trace.Trace; import org.springframework.boot.actuate.trace.Trace;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -46,8 +44,7 @@ public class Requests {
@GetMapping @GetMapping
public ModelAndView get(HttpServletRequest request) { public ModelAndView get(HttpServletRequest request) {
ModelAndView m = new ModelAndView("requests"); ModelAndView m = new ModelAndView("requests");
WebGoatUser user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); List<Tracert> traces = traceRepository.findAllTraces().stream()
List<Tracert> traces = traceRepository.findTraceForUser(user.getUsername()).stream()
.map(t -> new Tracert(t.getTimestamp(), path(t), toJsonString(t))).collect(toList()); .map(t -> new Tracert(t.getTimestamp(), path(t), toJsonString(t))).collect(toList());
m.addObject("traces", traces); m.addObject("traces", traces);

Some files were not shown because too many files have changed in this diff Show More