Compare commits
126 Commits
Author | SHA1 | Date | |
---|---|---|---|
985148ede3 | |||
9587550bc5 | |||
9a0995dae5 | |||
4e07e0ebfa | |||
6e95fdfe56 | |||
e045bc692d | |||
589872ad47 | |||
5f4889cefe | |||
55793dd153 | |||
1edceb0aa8 | |||
d2b6725f3b | |||
6e003bc088 | |||
f8a7a61e85 | |||
eaf68d38c5 | |||
8d7ecb19d7 | |||
e0cf5b4a84 | |||
5b524d3a94 | |||
dda6f674a3 | |||
e06d4642eb | |||
4a8fdcf887 | |||
fd96ba18f1 | |||
60ef35e241 | |||
9d7886d572 | |||
7a0820bf89 | |||
ea9c1a453d | |||
63ca11a1bb | |||
5378d72600 | |||
93d6d0e6b7 | |||
84860e65f6 | |||
a73bf58d36 | |||
0ff6000511 | |||
91d9db5f80 | |||
ac1b9e8311 | |||
9d49373486 | |||
ead78d40e6 | |||
7b5bb6d6f1 | |||
408a637649 | |||
6cf96f971d | |||
0b9a027c19 | |||
6a5ca43e7e | |||
5d28ef9fbe | |||
9aa674e326 | |||
84e3fcde07 | |||
6209b3fe8d | |||
a1db8e8bd9 | |||
6b4a488c8c | |||
0e160c19f5 | |||
8050a2b56d | |||
11ffa5702c | |||
32927c8109 | |||
8b8a89a8ab | |||
e4ca0c4836 | |||
e422da4c64 | |||
76daac0db5 | |||
245ba2c3d1 | |||
672d78eebc | |||
f4eb96fc6a | |||
46fedf3764 | |||
f30db3abfc | |||
58d4b81df2 | |||
2ae1b4955f | |||
13a4b69cbe | |||
98efc1235f | |||
b99b554522 | |||
04ccf9a422 | |||
ee11381a63 | |||
2cc6c232e2 | |||
dec55d52ca | |||
568fa82270 | |||
bad60c43c0 | |||
a6b9235711 | |||
253a2f16ed | |||
e801b0917d | |||
ae92ac6808 | |||
a9ac00a075 | |||
0120c7c3a6 | |||
5bbdb8893c | |||
e3e7ed004f | |||
05d8b590f3 | |||
114fbc5760 | |||
32311a80da | |||
d3ee9431d8 | |||
4811a9d563 | |||
c6e86861fe | |||
b64aa43760 | |||
dd7f4074cd | |||
8c10000e4e | |||
43b82027f5 | |||
5eed385d5d | |||
75d0405da1 | |||
157b982394 | |||
99048d6d9d | |||
971f11534d | |||
c06e4d462b | |||
39029f604f | |||
36fcb58caa | |||
6c91e7dc8a | |||
a543deca04 | |||
f91f77708a | |||
100876ad6c | |||
56fc0fce05 | |||
fc1353b2f1 | |||
1e9f92220d | |||
a11d3d0b1b | |||
87a7521dcd | |||
a11e6911cd | |||
5614cda0bf | |||
69d44aed5b | |||
8729d9bfcf | |||
f6911b49a7 | |||
24cf806787 | |||
1ac305e9b9 | |||
c6f1c5cd2a | |||
74218de135 | |||
1f6d7fdc39 | |||
cce1945f23 | |||
bb3bc9b883 | |||
bb5e0c06dd | |||
0508859cf5 | |||
738b2d8054 | |||
0c88dcf463 | |||
d1729e8f3c | |||
1ecb43092d | |||
904a6b363d | |||
45d48a8776 | |||
50904cf69b |
9
.gitignore
vendored
9
.gitignore
vendored
@ -14,7 +14,8 @@
|
||||
/.settings/org.eclipse.wst.validation.prefs
|
||||
/.externalToolBuilders/
|
||||
.project
|
||||
/target
|
||||
*/target/*
|
||||
mongo-data/*
|
||||
.classpath
|
||||
.idea/
|
||||
.settings/
|
||||
@ -29,6 +30,7 @@ src/main/webapp/plugin_lessons/*.jar
|
||||
src/main/webapp/users/*.props
|
||||
classes/*
|
||||
*.iml
|
||||
pom.xml.versionsBackup
|
||||
|
||||
/*.iml
|
||||
.extract/*
|
||||
@ -39,3 +41,8 @@ webgoat-lessons/**/target
|
||||
**/*.jar
|
||||
**/.DS_Store
|
||||
webgoat-server/mongo-data/*
|
||||
webgoat-lessons/vulnerable-components/dependency-reduced-pom.xml
|
||||
**/.sts4-cache/*
|
||||
**/.vscode/*
|
||||
|
||||
/.sonatype
|
15
.travis.yml
15
.travis.yml
@ -7,10 +7,20 @@ install: "/bin/true"
|
||||
script:
|
||||
- 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"
|
||||
- if [ ! -z "${TRAVIS_TAG}" ]; then mvn versions:set -DnewVersion=${TRAVIS_TAG:1}; fi
|
||||
- mvn clean install -q
|
||||
cache:
|
||||
directories:
|
||||
- "$HOME/.m2"
|
||||
before_deploy:
|
||||
- export WEBGOAT_SERVER_TARGET_DIR=$HOME/build/$TRAVIS_REPO_SLUG/webgoat-server/target
|
||||
- export WEBWOLF_TARGET_DIR=$HOME/build/$TRAVIS_REPO_SLUG/webwolf/target
|
||||
- export WEBGOAT_ARTIFACTS_FOLDER=$HOME/build/$TRAVIS_REPO_SLUG/Deployable_Artifacts/
|
||||
- mkdir -p $WEBGOAT_ARTIFACTS_FOLDER
|
||||
- cp -fa $WEBGOAT_SERVER_TARGET_DIR/*.jar $WEBGOAT_ARTIFACTS_FOLDER/
|
||||
- cp -fa $WEBWOLF_TARGET_DIR/*.jar $WEBGOAT_ARTIFACTS_FOLDER/
|
||||
- echo "Contents of artifacts folder:"
|
||||
- ls $WEBGOAT_ARTIFACTS_FOLDER
|
||||
deploy:
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
@ -25,10 +35,13 @@ deploy:
|
||||
repo: WebGoat/WebGoat
|
||||
branch: develop
|
||||
- provider: releases
|
||||
skip_cleanup: true
|
||||
overwrite: true
|
||||
api_key:
|
||||
#api-key from webgoat-github user
|
||||
secure: pJOLBnl6427PcVg/tVy/qB18JC7b8cKpffau+IP0pjdSt7KUfBdBY3QuJ7mrM65zRoVILzggLckaew2PlRmYQRdumyWlyRn44XiJ9KO4n6Bsufbz+ictB4ggtozpp9+I9IIUh1TmqypL9lhkX2ONM9dSHmyblYpAAgMuYSK8FYc=
|
||||
file: "webgoat-server/target/webgoat-server*.jar"
|
||||
file_glob: true
|
||||
file: $WEBGOAT_ARTIFACTS_FOLDER/*
|
||||
on:
|
||||
repo: WebGoat/WebGoat
|
||||
tags: true
|
||||
|
29
CREATE_RELEASE.MD
Normal file
29
CREATE_RELEASE.MD
Normal 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.M15
|
||||
git push origin v8.0.0.M15
|
||||
```
|
||||
|
||||
Now Travis takes over and will create the release in Github and on Docker Hub.
|
||||
|
||||
|
51
README.MD
51
README.MD
@ -1,15 +1,11 @@
|
||||
# WebGoat: A deliberately insecure Web Application
|
||||
# WebGoat 8: A deliberately insecure Web Application
|
||||
|
||||
[](https://travis-ci.org/WebGoat/WebGoat)
|
||||
[](https://coveralls.io/github/WebGoat/WebGoat?branch=master)
|
||||
[](https://www.codacy.com/app/dm/WebGoat)
|
||||
[](https://www.versioneye.com/user/projects/562da95ae346d7000e0369aa)
|
||||
[](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
|
||||
|
||||
[](https://www.owasp.org/index.php/OWASP_Project_Inventory#tab=Labs_Projects)
|
||||
[](https://github.com/WebGoat/WebGoat/releases/latest)
|
||||
|
||||
# Introduction
|
||||
|
||||
@ -44,6 +40,15 @@ docker pull webgoat/webgoat-8.0
|
||||
docker run -p 8080:8080 -it webgoat/webgoat-8.0 /home/webgoat/start.sh
|
||||
```
|
||||
|
||||
If you want to keep the database between Docker sessions you need to map the WebGoat data directory to a
|
||||
folder on the host system as follows:
|
||||
|
||||
```Shell
|
||||
docker run -p 8080:8080 -it -v /tmp/webgoat-data:/home/webgoat/.webgoat-${VERSION} webgoat/webgoat-8.0 /home/webgoat/start.sh
|
||||
```
|
||||
|
||||
where `${VERSION}` is for example `v8.0.0.M14`. The data will now be stored in `/tmp/webgoat-data` on your host system.
|
||||
|
||||
Wait for the Docker container to start, and run `docker ps` to verify it's running.
|
||||
|
||||
- If you are using `docker-machine`, verify the machine IP using `docker-machine env`
|
||||
@ -62,12 +67,26 @@ _Please note: this version may not be completely in sync with the develop branch
|
||||
|
||||
## 2. Standalone
|
||||
|
||||
Download the latest WebWolf release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases)
|
||||
Download the latest WebGoat release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases)
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
You can specify one of the following arguments when starting WebGoat:
|
||||
|
||||
```Shell
|
||||
java -jar webgoat-server-<<version>>.jar --server.port=9090 --server.address=x.x.x.x
|
||||
```
|
||||
|
||||
This will start WebGoat on a different port and/or different address.
|
||||
|
||||
|
||||
## 3. Run from the sources
|
||||
|
||||
@ -88,20 +107,22 @@ Now let's start by compiling the project.
|
||||
|
||||
```Shell
|
||||
cd WebGoat
|
||||
git checkout develop
|
||||
git checkout <<branch_name>>
|
||||
mvn clean install
|
||||
```
|
||||
|
||||
Now we are ready to run the project. WebGoat 8.x is using Spring-Boot.
|
||||
|
||||
```Shell
|
||||
mvn -pl webwolf spring-boot:run
|
||||
mvn -pl webgoat-server spring-boot:run
|
||||
```
|
||||
... 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
|
||||
|
||||
```server.address=x.x.x.x
|
||||
To change IP address add the following variable to WebGoat/webgoat-container/src/main/resources/application.properties file
|
||||
|
||||
```
|
||||
server.address=x.x.x.x
|
||||
```
|
||||
|
||||
# Vagrant
|
||||
@ -109,7 +130,7 @@ To change IP addresss add the following variable to WebGoat/webgoat-container/sr
|
||||
We supply a complete development environment using Vagrant, to run WebGoat with Vagrant you must first have Vagrant and Virtualbox installed.
|
||||
|
||||
```shell
|
||||
$ cd WebGoat/webgoat-images/vagrant-users
|
||||
$ cd WebGoat/webgoat-images/vagrant-training
|
||||
$ vagrant up
|
||||
```
|
||||
|
||||
@ -119,6 +140,8 @@ The source code will be available in the home directory.
|
||||
|
||||
# Building a new Docker image
|
||||
|
||||
NOTE: Travis will create a new Docker image automatically when making a new release.
|
||||
|
||||
WebGoat now has Docker support for x86 and ARM (raspberry pi).
|
||||
### Docker on x86
|
||||
On x86 you can build a container with the following commands:
|
||||
|
35
docker-compose-postgres.yml
Normal file
35
docker-compose-postgres.yml
Normal file
@ -0,0 +1,35 @@
|
||||
version: '2.0'
|
||||
|
||||
services:
|
||||
webgoat:
|
||||
image: webgoat/webgoat-8.0
|
||||
user: webgoat
|
||||
environment:
|
||||
- WEBWOLF_HOST=webwolf
|
||||
- spring.datasource.url=jdbc:postgresql://webgoat_db:5432/webgoat
|
||||
- spring.datasource.username=webgoat
|
||||
- spring.datasource.password=webgoat
|
||||
- spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
- spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL94Dialect
|
||||
ports:
|
||||
- "8080:8080"
|
||||
webwolf:
|
||||
image: webgoat/webwolf
|
||||
environment:
|
||||
- spring.datasource.url=jdbc:postgresql://webgoat_db:5432/webgoat
|
||||
- spring.datasource.username=webgoat
|
||||
- spring.datasource.password=webgoat
|
||||
- spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
- spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL94Dialect
|
||||
ports:
|
||||
- "8081:8081"
|
||||
db:
|
||||
container_name: webgoat_db
|
||||
image: postgres:latest
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=webgoat
|
||||
- POSTGRES_USER=webgoat
|
||||
- POSTGRES_DB=webgoat
|
||||
ports:
|
||||
- "5432:5432"
|
||||
|
@ -1,40 +1,28 @@
|
||||
version: '2.0'
|
||||
version: '2.1'
|
||||
|
||||
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:
|
||||
build: webgoat-server/
|
||||
command: "sh /home/webgoat/start.sh"
|
||||
image: webgoat/webgoat-8.0
|
||||
environment:
|
||||
- WEBWOLF_HOST=webwolf
|
||||
- spring.datasource.url=jdbc:hsqldb:hsql://webgoat_db:9001/webgoat
|
||||
ports:
|
||||
- "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"
|
||||
- db
|
||||
webwolf:
|
||||
build: webwolf/
|
||||
command: "sh /home/webwolf/start.sh"
|
||||
depends_on:
|
||||
- webgoat
|
||||
image: webgoat/webwolf
|
||||
environment:
|
||||
- spring.datasource.url=jdbc:hsqldb:hsql://webgoat_db:9001/webgoat
|
||||
ports:
|
||||
- "8081:8081"
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
image: blacklabelops/hsqldb
|
||||
container_name: webgoat_db
|
||||
environment:
|
||||
WG_MONGO_PORT: 27017
|
||||
WG_MONGO_HOST: mongo
|
||||
WG_MQ_HOST: activemq
|
||||
WG_MQ_PORT: 61616
|
||||
- HSQLDB_TRACE=false
|
||||
- HSQLDB_SILENT=true
|
||||
- HSQLDB_DATABASE_NAME=webgoat
|
||||
- HSQLDB_DATABASE_ALIAS=webgoat
|
||||
|
9
pom.xml
9
pom.xml
@ -5,7 +5,7 @@
|
||||
<groupId>org.owasp.webgoat</groupId>
|
||||
<artifactId>webgoat-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>8.0.0.M1</version>
|
||||
<version>v8.0.0.M15</version>
|
||||
|
||||
<name>WebGoat Parent Pom</name>
|
||||
<description>Parent Pom for the WebGoat Project. A deliberately insecure Web Application</description>
|
||||
@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.5.RELEASE</version>
|
||||
<version>1.5.12.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<licenses>
|
||||
@ -135,14 +135,13 @@
|
||||
<gatling-plugin.version>2.2.4</gatling-plugin.version>
|
||||
<guava.version>18.0</guava.version>
|
||||
<h2.version>1.4.190</h2.version>
|
||||
<hsqldb.version>2.3.2</hsqldb.version>
|
||||
<hsqldb.version>2.3.4</hsqldb.version>
|
||||
<j2h.version>1.3.1</j2h.version>
|
||||
<jackson-core.version>2.6.3</jackson-core.version>
|
||||
<jackson-databind.version>2.6.3</jackson-databind.version>
|
||||
<javaee-api.version>6.0</javaee-api.version>
|
||||
<javax.transaction-api.version>1.2</javax.transaction-api.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>
|
||||
<junit.version>4.12</junit.version>
|
||||
<mail-api.version>1.5.4</mail-api.version>
|
||||
@ -296,8 +295,8 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.16.10</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
|
@ -4,19 +4,36 @@ docker login -u $DOCKER_USER -p $DOCKER_PASS
|
||||
export REPO=webgoat/webgoat-8.0
|
||||
|
||||
cd webgoat-server
|
||||
ls target/
|
||||
|
||||
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
|
||||
docker build -f Dockerfile -t $REPO:latest .
|
||||
docker tag $REPO:${TRAVIS_TAG}
|
||||
docker build --build-arg webgoat_version=${TRAVIS_TAG:1} -f Dockerfile -t $REPO:latest -t $REPO:${TRAVIS_TAG} .
|
||||
docker push $REPO
|
||||
elif [ ! -z "${TRAVIS_TAG}" ]; then
|
||||
# Creating a tag build we push it to Docker with that tag
|
||||
docker build -f Dockerfile -t $REPO:${TRAVIS_TAG} .
|
||||
docker tag $REPO:${TRAVIS_TAG}
|
||||
docker build --build-arg webgoat_version=${TRAVIS_TAG:1} -f Dockerfile -t $REPO:${TRAVIS_TAG} -t $REPO:latest .
|
||||
docker push $REPO
|
||||
elif [ "${BRANCH}" == "develop" ]; then
|
||||
docker build -f Dockerfile -t $REPO:snapshot .
|
||||
#elif [ "${BRANCH}" == "develop" ]; then
|
||||
# docker build -f Dockerfile -t $REPO:snapshot .
|
||||
# docker push $REPO
|
||||
else
|
||||
echo "Skipping releasing to DockerHub because it is a build of branch ${BRANCH}"
|
||||
fi
|
||||
|
||||
|
||||
export REPO=webgoat/webwolf
|
||||
cd ..
|
||||
cd webwolf
|
||||
ls target/
|
||||
|
||||
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
|
||||
docker build --build-arg webwolf_version=${TRAVIS_TAG:1} -f Dockerfile -t $REPO:latest -t $REPO:${TRAVIS_TAG} .
|
||||
docker push $REPO
|
||||
elif [ ! -z "${TRAVIS_TAG}" ]; then
|
||||
# Creating a tag build we push it to Docker with that tag
|
||||
docker build --build-arg webwolf_version=${TRAVIS_TAG:1} -f Dockerfile -t $REPO:${TRAVIS_TAG} -t $REPO:latest .
|
||||
docker push $REPO
|
||||
else
|
||||
echo "Skipping releasing to DockerHub because it is a build of branch ${BRANCH}"
|
||||
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
@ -10,7 +10,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat</groupId>
|
||||
<artifactId>webgoat-parent</artifactId>
|
||||
<version>8.0.0.M1</version>
|
||||
<version>v8.0.0.M15</version>
|
||||
</parent>
|
||||
|
||||
<profiles>
|
||||
@ -36,16 +36,6 @@
|
||||
|
||||
</profiles>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
@ -92,29 +82,6 @@
|
||||
<forkMode>never</forkMode>
|
||||
</configuration>
|
||||
</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>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
@ -135,14 +102,6 @@
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
@ -150,10 +109,6 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-cache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
@ -162,31 +117,26 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>io.gatling.highcharts</groupId>
|
||||
<artifactId>gatling-charts-highcharts</artifactId>
|
||||
<version>${gatling.version}</version>
|
||||
<scope>test</scope>
|
||||
</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>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
@ -205,11 +155,6 @@
|
||||
<artifactId>activation</artifactId>
|
||||
<version>${activation.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>${h2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
@ -224,19 +169,7 @@
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala-compiler</artifactId>
|
||||
<version>${scala.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 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>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@ -259,12 +192,6 @@
|
||||
<version>${junit.version}</version>
|
||||
<type>jar</type>
|
||||
</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> ************** -->
|
||||
</dependencies>
|
||||
|
@ -32,7 +32,11 @@ package org.owasp.webgoat;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.asciidoctor.Asciidoctor;
|
||||
import org.asciidoctor.extension.JavaExtensionRegistry;
|
||||
import org.owasp.webgoat.asciidoc.WebGoatVersionMacro;
|
||||
import org.owasp.webgoat.asciidoc.WebWolfMacro;
|
||||
import org.owasp.webgoat.i18n.Language;
|
||||
import org.thymeleaf.TemplateProcessingParameters;
|
||||
import org.thymeleaf.resourceresolver.IResourceResolver;
|
||||
@ -41,6 +45,7 @@ import org.thymeleaf.templateresolver.TemplateResolver;
|
||||
import java.io.*;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.commons.lang3.CharEncoding.UTF_8;
|
||||
import static org.asciidoctor.Asciidoctor.Factory.create;
|
||||
|
||||
/**
|
||||
@ -50,6 +55,7 @@ import static org.asciidoctor.Asciidoctor.Factory.create;
|
||||
* <div th:replace="doc:AccessControlMatrix_plan.adoc"></div>
|
||||
* </code>
|
||||
*/
|
||||
@Slf4j
|
||||
public class AsciiDoctorTemplateResolver extends TemplateResolver {
|
||||
|
||||
private static final Asciidoctor asciidoctor = create();
|
||||
@ -73,11 +79,19 @@ public class AsciiDoctorTemplateResolver extends TemplateResolver {
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) {
|
||||
InputStream is = readInputStreamOrFallbackToEnglish(resourceName, language);
|
||||
try {
|
||||
try (InputStream is = readInputStreamOrFallbackToEnglish(resourceName, language)) {
|
||||
if (is == null) {
|
||||
log.warn("Resource name: {} not found, did you add the adoc file?", resourceName);
|
||||
return new ByteArrayInputStream(new byte[0]);
|
||||
} else {
|
||||
StringWriter writer = new StringWriter();
|
||||
JavaExtensionRegistry extensionRegistry = asciidoctor.javaExtensionRegistry();
|
||||
extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class);
|
||||
extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class);
|
||||
|
||||
asciidoctor.convert(new InputStreamReader(is), writer, createAttributes());
|
||||
return new ByteArrayInputStream(writer.getBuffer().toString().getBytes());
|
||||
return new ByteArrayInputStream(writer.getBuffer().toString().getBytes(UTF_8));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
//no html yet
|
||||
return new ByteArrayInputStream(new byte[0]);
|
||||
|
@ -23,11 +23,5 @@ public class CleanupLocalProgressFiles {
|
||||
|
||||
@PostConstruct
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,6 +130,7 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
||||
@Bean
|
||||
public PluginMessages pluginMessages(Messages messages, Language language) {
|
||||
PluginMessages pluginMessages = new PluginMessages(messages, language);
|
||||
pluginMessages.setDefaultEncoding("UTF-8");
|
||||
pluginMessages.setBasenames("i18n/WebGoatLabels");
|
||||
return pluginMessages;
|
||||
}
|
||||
@ -142,6 +143,7 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
||||
@Bean
|
||||
public Messages messageSource(Language language) {
|
||||
Messages messages = new Messages(language);
|
||||
messages.setDefaultEncoding("UTF-8");
|
||||
messages.setBasename("classpath:i18n/messages");
|
||||
return messages;
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package org.owasp.webgoat.asciidoc;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Make environment available in the asciidoc code (which you cannot inject because it is handled by the framework)
|
||||
*/
|
||||
@Component
|
||||
public class EnvironmentExposure implements ApplicationContextAware {
|
||||
|
||||
private static ApplicationContext context;
|
||||
|
||||
public static Environment getEnv() {
|
||||
return context.getEnvironment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
context = applicationContext;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.owasp.webgoat.asciidoc;
|
||||
|
||||
import org.asciidoctor.ast.AbstractBlock;
|
||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Map;
|
||||
|
||||
public class WebGoatVersionMacro extends InlineMacroProcessor {
|
||||
|
||||
public WebGoatVersionMacro(String macroName, Map<String, Object> config) {
|
||||
super(macroName, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
|
||||
return EnvironmentExposure.getEnv().getProperty("webgoat.build.version");
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package org.owasp.webgoat.asciidoc;
|
||||
|
||||
import org.asciidoctor.ast.AbstractBlock;
|
||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Usage in asciidoc:
|
||||
* <p>
|
||||
* webWolfLink:here[] will display a href with here as text
|
||||
* webWolfLink:landing[noLink] will display the complete url, for example: http://WW_HOST:WW_PORT/landing
|
||||
*/
|
||||
public class WebWolfMacro extends InlineMacroProcessor {
|
||||
|
||||
public WebWolfMacro(String macroName, Map<String, Object> config) {
|
||||
super(macroName, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
|
||||
Environment env = EnvironmentExposure.getEnv();
|
||||
String hostname = determineHost(env.getProperty("webwolf.host"), env.getProperty("webwolf.port"));
|
||||
|
||||
if (displayCompleteLinkNoFormatting(attributes)) {
|
||||
return hostname + (hostname.endsWith("/") ? "" : "/") + target;
|
||||
}
|
||||
return "<a href=\"" + hostname + "\" target=\"_blank\">" + target + "</a>";
|
||||
}
|
||||
|
||||
private boolean displayCompleteLinkNoFormatting(Map<String, Object> attributes) {
|
||||
return attributes.values().stream().filter(a -> a.equals("noLink")).findFirst().isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at the remote address from received from the browser first. This way it will also work if you run
|
||||
* the browser in a Docker container and WebGoat on your local machine.
|
||||
*/
|
||||
private String determineHost(String host, String port) {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
|
||||
String ip = request.getRemoteAddr();
|
||||
String hostname = StringUtils.hasText(ip) ? ip : host;
|
||||
return "http://" + hostname + ":" + port + "/WebWolf";
|
||||
}
|
||||
}
|
@ -55,7 +55,7 @@ public abstract class AssignmentEndpoint extends Endpoint {
|
||||
|
||||
//// TODO: 11/13/2016 events better fit?
|
||||
protected AttackResult trackProgress(AttackResult attackResult) {
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||
if (userTracker == null) {
|
||||
userTracker = new UserTracker(webSession.getUserName());
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package org.owasp.webgoat.lessons;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -33,16 +35,30 @@ import java.util.List;
|
||||
* @version $Id: $Id
|
||||
* @since November 25, 2016
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@Entity
|
||||
public class Assignment {
|
||||
@NonNull
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
private String name;
|
||||
@NonNull
|
||||
private String path;
|
||||
@Transient
|
||||
private List<String> hints;
|
||||
|
||||
private Assignment() {
|
||||
//Hibernate
|
||||
}
|
||||
|
||||
public Assignment(String name, String path) {
|
||||
this(name, path, Lists.newArrayList());
|
||||
}
|
||||
|
||||
public Assignment(String name, String path, List<String> hints) {
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
this.hints = hints;
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ public enum Category {
|
||||
INSECURE_CONFIGURATION("Insecure Configuration", new Integer(600)),
|
||||
INSECURE_COMMUNICATION("Insecure Communication", new Integer(700)),
|
||||
INSECURE_STORAGE("Insecure Storage", new Integer(800)),
|
||||
INSECURE_DESERIALIZATION("Insecure Deserialization", new Integer(850)),
|
||||
REQUEST_FORGERIES("Request Forgeries", new Integer(900)),
|
||||
VULNERABLE_COMPONENTS("Vulnerable Components - A9", new Integer(950)),
|
||||
AJAX_SECURITY("AJAX Security", new Integer(1000)),
|
||||
|
@ -2,7 +2,6 @@ package org.owasp.webgoat.lessons;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
|
||||
/**
|
||||
* <p>LessonInfoModel class.</p>
|
||||
|
@ -73,7 +73,7 @@ public class LessonMenuService {
|
||||
List<LessonMenuItem> showLeftNav() {
|
||||
List<LessonMenuItem> menu = new ArrayList<>();
|
||||
List<Category> categories = course.getCategories();
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||
|
||||
for (Category category : categories) {
|
||||
LessonMenuItem categoryItem = new LessonMenuItem();
|
||||
|
@ -40,9 +40,10 @@ public class LessonProgressService {
|
||||
@RequestMapping(value = "/service/lessonprogress.mvc", produces = "application/json")
|
||||
@ResponseBody
|
||||
public Map getLessonInfo() {
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
LessonTracker lessonTracker = userTracker.getLessonTracker(webSession.getCurrentLesson());
|
||||
Map json = Maps.newHashMap();
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||
if (webSession.getCurrentLesson() != null) {
|
||||
LessonTracker lessonTracker = userTracker.getLessonTracker(webSession.getCurrentLesson());
|
||||
String successMessage = "";
|
||||
boolean lessonCompleted = false;
|
||||
if (lessonTracker != null) {
|
||||
@ -51,6 +52,7 @@ public class LessonProgressService {
|
||||
}
|
||||
json.put("lessonCompleted", lessonCompleted);
|
||||
json.put("successMessage", successMessage);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
@ -63,7 +65,7 @@ public class LessonProgressService {
|
||||
@RequestMapping(value = "/service/lessonoverview.mvc", produces = "application/json")
|
||||
@ResponseBody
|
||||
public List<LessonOverview> lessonOverview() {
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||
AbstractLesson currentLesson = webSession.getCurrentLesson();
|
||||
List<LessonOverview> result = Lists.newArrayList();
|
||||
if ( currentLesson != null ) {
|
||||
|
@ -32,6 +32,7 @@ import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.owasp.webgoat.i18n.PluginMessages;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.session.Course;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
@ -57,6 +58,7 @@ public class ReportCardService {
|
||||
private final WebSession webSession;
|
||||
private final UserTrackerRepository userTrackerRepository;
|
||||
private final Course course;
|
||||
private final PluginMessages pluginMessages;
|
||||
|
||||
/**
|
||||
* Endpoint which generates the report card for the current use to show the stats on the solved lessons
|
||||
@ -64,7 +66,7 @@ public class ReportCardService {
|
||||
@GetMapping(path = "/service/reportcard.mvc", produces = "application/json")
|
||||
@ResponseBody
|
||||
public ReportCard reportCard() {
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||
List<AbstractLesson> lessons = course.getLessons();
|
||||
ReportCard reportCard = new ReportCard();
|
||||
reportCard.setTotalNumberOfLessons(course.getTotalOfLessons());
|
||||
@ -74,7 +76,7 @@ public class ReportCardService {
|
||||
for (AbstractLesson lesson : lessons) {
|
||||
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
|
||||
LessonStatistics lessonStatistics = new LessonStatistics();
|
||||
lessonStatistics.setName(lesson.getTitle());
|
||||
lessonStatistics.setName(pluginMessages.getMessage(lesson.getTitle()));
|
||||
lessonStatistics.setNumberOfAttempts(lessonTracker.getNumberOfAttempts());
|
||||
lessonStatistics.setSolved(lessonTracker.isLessonSolved());
|
||||
reportCard.lessonStatistics.add(lessonStatistics);
|
||||
|
@ -59,7 +59,7 @@ public class RestartLessonService {
|
||||
AbstractLesson al = webSession.getCurrentLesson();
|
||||
log.debug("Restarting lesson: " + al);
|
||||
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||
userTracker.reset(al);
|
||||
userTrackerRepository.save(userTracker);
|
||||
}
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
@ -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.";
|
||||
}
|
||||
}
|
@ -81,6 +81,39 @@ public class CreateDB {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description of the Method
|
||||
*
|
||||
* @param connection Description of the Parameter
|
||||
* @throws SQLException Description of the Exception
|
||||
*/
|
||||
private void createJWTKeys(Connection connection) throws SQLException {
|
||||
Statement statement = connection.createStatement();
|
||||
|
||||
// Drop servers table
|
||||
try {
|
||||
String dropTable = "DROP TABLE jwt_keys";
|
||||
statement.executeUpdate(dropTable);
|
||||
} catch (SQLException e) {
|
||||
System.out.println("Info - Could not drop jwtkeys table");
|
||||
}
|
||||
|
||||
// Create the new table
|
||||
try {
|
||||
String createTableStatement = "CREATE TABLE jwt_keys"
|
||||
+ " (" + "id varchar(20),"
|
||||
+ "key varchar(20))";
|
||||
statement.executeUpdate(createTableStatement);
|
||||
|
||||
String insertData1 = "INSERT INTO jwt_keys VALUES ('webgoat_key', 'qwertyqwerty1234')";
|
||||
String insertData2 = "INSERT INTO jwt_keys VALUES ('webwolf_key', 'doesnotreallymatter')";
|
||||
statement.executeUpdate(insertData1);
|
||||
statement.executeUpdate(insertData2);
|
||||
} catch (SQLException e) {
|
||||
System.out.println("Error creating product table " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Description of the Method
|
||||
@ -975,6 +1008,7 @@ public class CreateDB {
|
||||
createTanTable(connection);
|
||||
createMFEImagesTable(connection);
|
||||
createModifyWithSQLLessonTable(connection);
|
||||
createJWTKeys(connection);
|
||||
System.out.println("Success: creating tables.");
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import lombok.Getter;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Assignment;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -44,16 +45,23 @@ import java.util.stream.Collectors;
|
||||
* @version $Id: $Id
|
||||
* @since October 29, 2003
|
||||
*/
|
||||
@Entity
|
||||
public class LessonTracker {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
@Getter
|
||||
private String lessonName;
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
private final Set<Assignment> solvedAssignments = Sets.newHashSet();
|
||||
private final List<Assignment> allAssignments = Lists.newArrayList();
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
private final Set<Assignment> allAssignments = Sets.newHashSet();
|
||||
@Getter
|
||||
private int numberOfAttempts = 0;
|
||||
|
||||
protected LessonTracker() {
|
||||
//Mongo
|
||||
private LessonTracker() {
|
||||
//JPA
|
||||
}
|
||||
|
||||
public LessonTracker(AbstractLesson lesson) {
|
||||
|
@ -38,7 +38,7 @@ public class Scoreboard {
|
||||
List<WebGoatUser> allUsers = userRepository.findAll();
|
||||
List<Ranking> rankings = Lists.newArrayList();
|
||||
for (WebGoatUser user : allUsers) {
|
||||
UserTracker userTracker = userTrackerRepository.findOne(user.getUsername());
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(user.getUsername());
|
||||
rankings.add(new Ranking(user.getUsername(), challengesSolved(userTracker)));
|
||||
}
|
||||
return rankings;
|
||||
|
@ -15,7 +15,7 @@ import javax.validation.constraints.Size;
|
||||
public class UserForm {
|
||||
|
||||
@NotNull
|
||||
@Size(min=6, max=10)
|
||||
@Size(min=6, max=20)
|
||||
private String username;
|
||||
@NotNull
|
||||
@Size(min=6, max=10)
|
||||
|
@ -1,6 +1,6 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -8,7 +8,7 @@ import java.util.List;
|
||||
* @author nbaars
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
public interface UserRepository extends MongoRepository<WebGoatUser, String> {
|
||||
public interface UserRepository extends JpaRepository<WebGoatUser, String> {
|
||||
|
||||
WebGoatUser findByUsername(String username);
|
||||
|
||||
|
@ -2,14 +2,16 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Assignment;
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@ -44,11 +46,18 @@ import java.util.stream.Collectors;
|
||||
* @since October 29, 2003
|
||||
*/
|
||||
@Slf4j
|
||||
@Entity
|
||||
public class UserTracker {
|
||||
|
||||
@Id
|
||||
private final String user;
|
||||
private List<LessonTracker> lessonTrackers = Lists.newArrayList();
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
@Column(name = "username")
|
||||
private String user;
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
private Set<LessonTracker> lessonTrackers = Sets.newHashSet();
|
||||
|
||||
private UserTracker() {}
|
||||
|
||||
public UserTracker(final String user) {
|
||||
this.user = user;
|
||||
|
@ -1,12 +1,13 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/30/17.
|
||||
*/
|
||||
public interface UserTrackerRepository extends MongoRepository<UserTracker, String> {
|
||||
public interface UserTrackerRepository extends JpaRepository<UserTracker, String> {
|
||||
|
||||
UserTracker findByUser(String user);
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
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.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
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.Collections;
|
||||
|
||||
@ -16,6 +17,7 @@ import java.util.Collections;
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
@Getter
|
||||
@Entity
|
||||
public class WebGoatUser implements UserDetails {
|
||||
|
||||
public static final String ROLE_USER = "WEBGOAT_USER";
|
||||
|
@ -3,10 +3,16 @@ server.error.path=/error.html
|
||||
server.session.timeout=600
|
||||
server.contextPath=/WebGoat
|
||||
server.port=8080
|
||||
server.address=127.0.0.1
|
||||
|
||||
spring.datasource.url=jdbc:hsqldb:hsql://localhost:9001/webgoat
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
|
||||
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
|
||||
|
||||
|
||||
logging.level.org.springframework=WARN
|
||||
logging.level.org.springframework.boot.devtools=WARN
|
||||
logging.level.org.springframework=INFO
|
||||
logging.level.org.springframework.boot.devtools=INFO
|
||||
logging.level.org.owasp=DEBUG
|
||||
logging.level.org.owasp.webgoat=TRACE
|
||||
|
||||
@ -16,9 +22,10 @@ security.enable-csrf=false
|
||||
spring.resources.cache-period=0
|
||||
spring.thymeleaf.cache=false
|
||||
|
||||
webgoat.start.hsqldb=true
|
||||
webgoat.clean=false
|
||||
webgoat.server.directory=${user.home}/.webgoat/
|
||||
webgoat.user.directory=${user.home}/.webgoat/
|
||||
webgoat.server.directory=${user.home}/.webgoat-${webgoat.build.version}/
|
||||
webgoat.user.directory=${user.home}/.webgoat-${webgoat.build.version}/
|
||||
webgoat.build.version=@project.version@
|
||||
webgoat.build.number=@build.number@
|
||||
webgoat.email=webgoat@owasp.org
|
||||
@ -28,22 +35,15 @@ webgoat.feedback.address.html=<A HREF=mailto:webgoat@owasp.org>webgoat@owasp.org
|
||||
webgoat.database.driver=org.hsqldb.jdbcDriver
|
||||
webgoat.database.connection.string=jdbc:hsqldb:mem:{USER}
|
||||
webgoat.default.language=en
|
||||
webgoat.embedded.mongo=${WG_INTERNAL_MONGO:true}
|
||||
|
||||
webwolf.port=8081
|
||||
webwolf.url=http://localhost:${webwolf.port}/WebWolf
|
||||
webworf.url.landingpage=http://localhost:${webwolf.port}/landing
|
||||
webworf.url.mail=http://localhost:${webwolf.port}/mail
|
||||
webwolf.host=${WEBWOLF_HOST:localhost}
|
||||
webwolf.port=${WEBWOLF_PORT:8081}
|
||||
webwolf.url=http://${webwolf.host}:${webwolf.port}/WebWolf
|
||||
webwolf.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.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
|
||||
spring.devtools.restart.additional-paths=webgoat-container/src/main/resources/static/js,webgoat-container/src/main/resources/static/css
|
||||
|
@ -1066,6 +1066,7 @@ span.show-next-page, span.show-prev-page {
|
||||
|
||||
/* ATTACK DISPLAY */
|
||||
.attack-container {
|
||||
position: relative;
|
||||
background-color: #f1f1f1;
|
||||
border: 2px solid #a66;
|
||||
border-radius: 12px;
|
||||
@ -1151,3 +1152,15 @@ div.captured-flag {
|
||||
width: 1268px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#content {
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.webwolf-enabled {
|
||||
position:absolute;
|
||||
top: 10px;
|
||||
right: 25px;
|
||||
width: 42px;
|
||||
height: 47px;
|
||||
}
|
@ -73,8 +73,9 @@ define(['jquery',
|
||||
}
|
||||
|
||||
this.loadLesson = function(name,pageNum) {
|
||||
|
||||
if (this.name === name) {
|
||||
this.listenTo(this.lessonHintView, 'hints:showButton', this.onShowHintsButton);
|
||||
this.listenToOnce(this.lessonHintView, 'hints:showButton', this.onShowHintsButton);
|
||||
this.listenTo(this.lessonHintView, 'hints:hideButton', this.onHideHintsButton);
|
||||
this.lessonContentView.navToPage(pageNum);
|
||||
this.lessonHintView.hideHints();
|
||||
@ -83,15 +84,15 @@ define(['jquery',
|
||||
return;
|
||||
}
|
||||
|
||||
if (pageNum && !this.name) {
|
||||
//placeholder
|
||||
}
|
||||
|
||||
this.helpsLoaded = {};
|
||||
if (typeof(name) === 'undefined' || name === null) {
|
||||
//TODO: implement lesson not found or return to welcome page?
|
||||
}
|
||||
this.lessonContent.loadData({'name':name});
|
||||
// this.planView = {};
|
||||
// this.solutionView = {};
|
||||
// this.sourceView = {};
|
||||
// this.lessonHintView = {};
|
||||
this.name = name;
|
||||
};
|
||||
|
||||
@ -102,12 +103,13 @@ define(['jquery',
|
||||
hasSource:this.lessonInfoModel.get('hasSource')
|
||||
});
|
||||
|
||||
this.listenTo(this.helpControlsView,'hints:show',this.showHints);
|
||||
this.listenTo(this.helpControlsView,'hints:show',this.showHintsView);
|
||||
|
||||
this.listenTo(this.helpControlsView,'lesson:restart',this.restartLesson);
|
||||
this.listenTo(this.developerControlsView, 'dev:labels', this.restartLesson);
|
||||
|
||||
this.helpControlsView.render();
|
||||
this.showHintsView();
|
||||
this.titleView.render(this.lessonInfoModel.get('lessonTitle'));
|
||||
};
|
||||
|
||||
@ -123,15 +125,8 @@ define(['jquery',
|
||||
this.helpControlsView = null;
|
||||
this.lessonContentView.model = this.lessonContent;
|
||||
this.lessonContentView.render();
|
||||
|
||||
//this.planView = new PlanView();
|
||||
//this.solutionView = new SolutionView();
|
||||
//this.sourceView = new SourceView();
|
||||
if (this.lessonHintView) {
|
||||
this.lessonHintView.stopListening();
|
||||
this.lessonHintView = null;
|
||||
}
|
||||
this.lessonHintView = new HintView();
|
||||
//TODO: consider moving hintView as child of lessonContentView ...
|
||||
this.createLessonHintView();
|
||||
|
||||
//TODO: instantiate model with values (not sure why was not working before)
|
||||
var paramModel = new ParamModel({});
|
||||
@ -147,41 +142,29 @@ define(['jquery',
|
||||
this.lessonProgressModel.completed();
|
||||
};
|
||||
|
||||
this.createLessonHintView = function () {
|
||||
if (this.lessonHintView) {
|
||||
this.lessonHintView.stopListening();
|
||||
this.lessonHintView = null;
|
||||
}
|
||||
this.lessonHintView = new HintView();
|
||||
}
|
||||
|
||||
this.addCurHelpState = function (curHelp) {
|
||||
this.helpsLoaded[curHelp.helpElement] = curHelp.value;
|
||||
};
|
||||
|
||||
// this.hideShowHelps = function(showHelp) {
|
||||
// var showId = '#lesson-' + showHelp + '-row';
|
||||
// var contentId = '#lesson-' + showHelp + '-content';
|
||||
// $('.lesson-help').not(showId).hide();
|
||||
// if (!showId) {
|
||||
// return;
|
||||
// }
|
||||
this.showHintsView = function() {
|
||||
if (!this.lessonHintView) {
|
||||
this.createLessonHintView();
|
||||
}
|
||||
//
|
||||
// if ($(showId).is(':visible')) {
|
||||
// $(showId).hide();
|
||||
// return;
|
||||
// } else {
|
||||
// //TODO: move individual .html operations into individual help views
|
||||
// switch(showHelp) {
|
||||
// case 'plan':
|
||||
// $(contentId).html(this.planView.model.get('content'));
|
||||
// break;
|
||||
// case 'solution':
|
||||
// $(showId).html(this.solutionView.model.get('content'));
|
||||
// break;
|
||||
// case 'source':
|
||||
// $(contentId).html('<pre>' + this.sourceView.model.get('content') + '</pre>');
|
||||
// break;
|
||||
// }
|
||||
// $(showId).show();
|
||||
// GoatUtils.scrollToHelp()
|
||||
// }
|
||||
// };
|
||||
|
||||
this.showHints = function() {
|
||||
this.lessonHintView.render();
|
||||
if (this.lessonHintView.getHintsCount > 0) {
|
||||
this.helpControlsView.showHintsButton();
|
||||
} else {
|
||||
this.helpControlsView.hideHintsButton();
|
||||
}
|
||||
};
|
||||
|
||||
this.restartLesson = function() {
|
||||
|
@ -7,9 +7,13 @@ define(['jquery',
|
||||
return Backbone.Collection.extend({
|
||||
model: MenuModel,
|
||||
url: 'service/lessonmenu.mvc',
|
||||
|
||||
initialize: function () {
|
||||
var self = this;
|
||||
this.fetch();
|
||||
setInterval(function () {
|
||||
this.fetch()
|
||||
}.bind(this), 5000);
|
||||
},
|
||||
|
||||
onDataLoaded: function () {
|
||||
|
@ -67,7 +67,7 @@ define(['jquery',
|
||||
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
success: function (data) {
|
||||
//devs leave stuff like this in all the time
|
||||
console.log('phone home said ' + data);
|
||||
console.log('phone home said ' + JSON.stringify(data));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -126,6 +126,10 @@ function($,
|
||||
} else {
|
||||
this.$el.find('#show-prev-hint').css('visibility','visible');
|
||||
}
|
||||
},
|
||||
|
||||
getHintsCount: function () {
|
||||
return this.collection.length;
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -25,6 +25,9 @@ define(['jquery',
|
||||
self.navToPage(page);
|
||||
}
|
||||
});
|
||||
setInterval(function () {
|
||||
this.updatePagination();
|
||||
}.bind(this), 5000);
|
||||
},
|
||||
|
||||
findPage: function(assignment) {
|
||||
@ -45,7 +48,6 @@ define(['jquery',
|
||||
this.$el.find('.attack-feedback').hide();
|
||||
this.$el.find('.attack-output').hide();
|
||||
this.makeFormsAjax();
|
||||
//this.ajaxifyAttackHref();
|
||||
$(window).scrollTop(0); //work-around til we get the scroll down sorted out
|
||||
var startPageNum = this.model.get('pageNum');
|
||||
this.initPagination(startPageNum);
|
||||
@ -57,11 +59,13 @@ define(['jquery',
|
||||
var currentPage = (!isNaN(startPageNum) && startPageNum && startPageNum < this.$contentPages) ? startPageNum : 0;
|
||||
//init views & pagination
|
||||
this.showCurContentPage(currentPage);
|
||||
this.paginationControlView = new PaginationControlView(this.$contentPages,this.model.get('lessonUrl'));
|
||||
this.paginationControlView = new PaginationControlView(this.$contentPages,this.model.get('lessonUrl'),startPageNum);
|
||||
},
|
||||
|
||||
updatePagination: function() {
|
||||
if ( this.paginationControlView != undefined ) {
|
||||
this.paginationControlView.updateCollection();
|
||||
}
|
||||
},
|
||||
|
||||
getCurrentPage: function () {
|
||||
@ -86,6 +90,10 @@ define(['jquery',
|
||||
var prepareDataFunctionName = $(curForm).attr('prepareData');
|
||||
var callbackFunctionName = $(curForm).attr('callback');
|
||||
var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize();
|
||||
var additionalHeadersFunctionName = $(curForm).attr('additionalHeaders');
|
||||
var additionalHeaders = (typeof webgoat.customjs[additionalHeadersFunctionName] === 'function') ? webgoat.customjs[additionalHeadersFunctionName]() : function() {};
|
||||
var successCallBackFunctionName = $(curForm).attr('successCallback');
|
||||
var failureCallbackFunctionName = $(curForm).attr('failureCallback');
|
||||
var callbackFunction = (typeof webgoat.customjs[callbackFunctionName] === 'function') ? webgoat.customjs[callbackFunctionName] : function() {};
|
||||
// var submitData = this.$form.serialize();
|
||||
this.curForm = curForm;
|
||||
@ -98,25 +106,25 @@ define(['jquery',
|
||||
$.ajax({
|
||||
//data:submitData,
|
||||
url:formUrl,
|
||||
headers: additionalHeaders,
|
||||
method:formMethod,
|
||||
contentType:contentType,
|
||||
data: submitData,
|
||||
//complete: function (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;
|
||||
},
|
||||
|
||||
onSuccessResponse: function(data) {
|
||||
onSuccessResponse: function(data, failureCallbackFunctionName, successCallBackFunctionName) {
|
||||
this.renderFeedback(data.feedback);
|
||||
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();
|
||||
successCallbackFunction = (typeof webgoat.customjs[successCallBackFunctionName] === 'function') ? webgoat.customjs[successCallBackFunctionName] : function() {};
|
||||
failureCallbackFunction = (typeof webgoat.customjs[failureCallbackFunctionName] === 'function') ? webgoat.customjs[failureCallbackFunctionName] : function() {};
|
||||
var successCallbackFunction = (typeof webgoat.customjs[successCallBackFunctionName] === 'function') ? webgoat.customjs[successCallBackFunctionName] : function() {};
|
||||
var failureCallbackFunction = (typeof webgoat.customjs[failureCallbackFunctionName] === 'function') ? webgoat.customjs[failureCallbackFunctionName] : function() {};
|
||||
//TODO: refactor back assignmentCompleted in Java
|
||||
if (data.lessonCompleted || data.assignmentCompleted) {
|
||||
this.markAssignmentComplete();
|
||||
@ -146,22 +154,23 @@ define(['jquery',
|
||||
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);
|
||||
});
|
||||
removeSlashesFromJSON: function(str) {
|
||||
// slashes are leftover escapes from JSON serialization by server
|
||||
// for every two char sequence starting with backslash,
|
||||
// replace them in the text with second char only
|
||||
return str.replace(/\\(.)/g, "$1");
|
||||
},
|
||||
|
||||
renderFeedback: function(feedback) {
|
||||
this.$curFeedback.html(polyglot.t(feedback) || "");
|
||||
var s = this.removeSlashesFromJSON(feedback);
|
||||
this.$curFeedback.html(polyglot.t(s) || "");
|
||||
this.$curFeedback.show(400)
|
||||
|
||||
},
|
||||
|
||||
renderOutput: function(output) {
|
||||
this.$curOutput.html(polyglot.t(output) || "");
|
||||
var s = this.removeSlashesFromJSON(output);
|
||||
this.$curOutput.html(polyglot.t(s) || "");
|
||||
this.$curOutput.show(400)
|
||||
},
|
||||
|
||||
@ -181,13 +190,19 @@ define(['jquery',
|
||||
return endpoints;
|
||||
},
|
||||
|
||||
onNavToPage: function(pageNum) {
|
||||
var assignmentPaths = this.findAssigmentEndpointsOnPage(pageNum);
|
||||
this.trigger('endpoints:filtered',assignmentPaths);
|
||||
},
|
||||
|
||||
navToPage: function (pageNum) {
|
||||
this.paginationControlView.setCurrentPage(pageNum);//provides validation
|
||||
this.showCurContentPage(this.paginationControlView.currentPage);
|
||||
this.paginationControlView.render();
|
||||
this.paginationControlView.hideShowNavButtons();
|
||||
var assignmentPaths = this.findAssigmentEndpointsOnPage(pageNum);
|
||||
this.trigger('endpoints:filtered',assignmentPaths);
|
||||
this.onNavToPage(pageNum);
|
||||
//var assignmentPaths = this.findAssigmentEndpointsOnPage(pageNum);
|
||||
//this.trigger('endpoints:filtered',assignmentPaths);
|
||||
},
|
||||
|
||||
/* for testing */
|
||||
|
@ -12,14 +12,14 @@ define(['jquery',
|
||||
template: PaginationTemplate,
|
||||
el: '#lesson-page-controls',
|
||||
|
||||
initialize: function ($contentPages,baseLessonUrl) {
|
||||
initialize: function ($contentPages,baseLessonUrl,initPageNum) {
|
||||
this.$contentPages = $contentPages;
|
||||
this.collection = new LessonOverviewCollection();
|
||||
this.listenTo(this.collection, 'reset', this.render);
|
||||
this.numPages = this.$contentPages.length;
|
||||
this.baseUrl = baseLessonUrl;
|
||||
this.collection.fetch({reset:true});
|
||||
this.initPagination();
|
||||
this.initPagination(initPageNum);
|
||||
//this.render();
|
||||
},
|
||||
|
||||
@ -117,9 +117,9 @@ define(['jquery',
|
||||
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').hide();
|
||||
},
|
||||
|
||||
initPagination: function() {
|
||||
//track pagination state in this view ... start at 0
|
||||
this.currentPage = 0;
|
||||
initPagination: function(initPageNum) {
|
||||
//track pagination state in this view ... start at 0 .. unless a pageNum was provided
|
||||
this.currentPage = !initPageNum ? 0 : initPageNum;
|
||||
},
|
||||
|
||||
setCurrentPage: function (pageNum) {
|
||||
|
@ -30,7 +30,7 @@ require.config({
|
||||
shim: {
|
||||
"jqueryui": {
|
||||
exports:"$",
|
||||
deps: ['jquery']
|
||||
deps: ['libs/jquery-2.1.4.min']
|
||||
},
|
||||
underscore: {
|
||||
exports: "_"
|
||||
|
@ -76,24 +76,25 @@
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation" class="divider"></li>
|
||||
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#"
|
||||
th:text="#{version}">Version: <span
|
||||
th:text="${@environment.getProperty('webgoat.build.version')}"></span></a>
|
||||
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">
|
||||
<span th:text="#{version}">Version:</span><span>: </span>
|
||||
<span th:text="${@environment.getProperty('webgoat.build.version')}"></span></a>
|
||||
</li>
|
||||
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#"
|
||||
th:text="#{build}">Build:
|
||||
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">
|
||||
<span th:text="#{build}">Build:</span><span>: </span>
|
||||
<span th:text="${@environment.getProperty('webgoat.build.number')}"></span></a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<div style="display:inline" id="settings">
|
||||
<!--<button type="button" id="admin-button" class="btn btn-default right_nav_button" title="Administrator">-->
|
||||
<!--<i class="fa fa-cog"></i>-->
|
||||
<!--</button>-->
|
||||
<a href="#reportCard">
|
||||
<button type="button" id="report-card-button" class="btn btn-default right_nav_button button-up"
|
||||
th:title="#{report.card}">
|
||||
<a href="#reportCard"><i class="fa fa-bar-chart-o"></i></a>
|
||||
<i class="fa fa-bar-chart-o"></i>
|
||||
</button>
|
||||
</a>
|
||||
<!--<button type="button" id="user-management" class="btn btn-default right_nav_button"-->
|
||||
<!--title="User management">-->
|
||||
<!--<i class="fa fa-users"></i>-->
|
||||
|
@ -62,7 +62,7 @@ public class AssignmentEndpointTest {
|
||||
|
||||
public void init(AssignmentEndpoint a) {
|
||||
messages.setBasenames("classpath:/i18n/messages", "classpath:/i18n/WebGoatLabels");
|
||||
when(userTrackerRepository.findOne(anyString())).thenReturn(userTracker);
|
||||
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
|
||||
ReflectionTestUtils.setField(a, "userTrackerRepository", userTrackerRepository);
|
||||
ReflectionTestUtils.setField(a, "userSessionData", userSessionData);
|
||||
ReflectionTestUtils.setField(a, "webSession", webSession);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -63,7 +63,7 @@ public class LessonMenuServiceTest {
|
||||
when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1, l2));
|
||||
when(course.getCategories()).thenReturn(Lists.newArrayList(Category.ACCESS_CONTROL));
|
||||
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
|
||||
when(userTrackerRepository.findOne(anyString())).thenReturn(userTracker);
|
||||
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC))
|
||||
.andExpect(status().isOk())
|
||||
@ -81,7 +81,7 @@ public class LessonMenuServiceTest {
|
||||
when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1));
|
||||
when(course.getCategories()).thenReturn(Lists.newArrayList(Category.ACCESS_CONTROL));
|
||||
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
|
||||
when(userTrackerRepository.findOne(anyString())).thenReturn(userTracker);
|
||||
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
|
||||
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC))
|
||||
|
@ -72,7 +72,7 @@ public class LessonProgressServiceTest {
|
||||
@Before
|
||||
public void setup() {
|
||||
Assignment assignment = new Assignment("test", "test");
|
||||
when(userTrackerRepository.findOne(anyString())).thenReturn(userTracker);
|
||||
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
|
||||
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
|
||||
when(websession.getCurrentLesson()).thenReturn(lesson);
|
||||
when(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true));
|
||||
|
@ -6,6 +6,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.owasp.webgoat.i18n.PluginMessages;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.session.Course;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
@ -40,10 +41,13 @@ public class ReportCardServiceTest {
|
||||
private UserTrackerRepository userTrackerRepository;
|
||||
@Mock
|
||||
private WebSession websession;
|
||||
@Mock
|
||||
private PluginMessages pluginMessages;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.mockMvc = standaloneSetup(new ReportCardService(websession, userTrackerRepository, course)).build();
|
||||
this.mockMvc = standaloneSetup(new ReportCardService(websession, userTrackerRepository, course, pluginMessages)).build();
|
||||
when(pluginMessages.getMessage(anyString())).thenReturn("Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -53,7 +57,7 @@ public class ReportCardServiceTest {
|
||||
when(course.getTotalOfLessons()).thenReturn(1);
|
||||
when(course.getTotalOfAssignments()).thenReturn(10);
|
||||
when(course.getLessons()).thenReturn(Lists.newArrayList(lesson));
|
||||
when(userTrackerRepository.findOne(anyString())).thenReturn(userTracker);
|
||||
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
|
||||
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/service/reportcard.mvc"))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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.findByUser("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.findByUser("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.findByUser("test");
|
||||
userTracker.assignmentFailed(lesson);
|
||||
userTracker.assignmentFailed(lesson);
|
||||
userTrackerRepository.saveAndFlush(userTracker);
|
||||
|
||||
Assertions.assertThat(userTracker.getLessonTracker(lesson).getNumberOfAttempts()).isEqualTo(4);
|
||||
}
|
||||
|
||||
}
|
@ -1 +1,4 @@
|
||||
webgoat.user.directory=${java.io.tmpdir}
|
||||
|
||||
spring.datasource.url=jdbc:hsqldb:mem:test
|
||||
spring.jpa.hibernate.ddl-auto=create-drop
|
@ -1 +1,15 @@
|
||||
<configuration />
|
||||
|
||||
<!--
|
||||
Enable below if you want to debug a unit test and see why the controller fails the configuration above is there
|
||||
to keep the Travis build going otherwise it fails with too much logging.
|
||||
//TODO we should use a different Spring profile for Travis
|
||||
-->
|
||||
|
||||
<!--
|
||||
<configuration>
|
||||
<include resource="org/springframework/boot/logging/logback/base.xml"/>
|
||||
<logger name="org.springframework.web" level="DEBUG"/>
|
||||
</configuration>
|
||||
|
||||
-->
|
32
webgoat-images/vagrant-developers/Vagrantfile
vendored
32
webgoat-images/vagrant-developers/Vagrantfile
vendored
@ -1,32 +0,0 @@
|
||||
Vagrant.configure(2) do |config|
|
||||
config.vm.box = "boxcutter/ubuntu1604-desktop"
|
||||
|
||||
|
||||
config.vm.provider "virtualbox" do |vb|
|
||||
vb.gui = true
|
||||
vb.memory = "4096"
|
||||
vb.cpus = 2
|
||||
vb.name = "WebGoat-Development"
|
||||
vb.customize ["modifyvm", :id, "--nictype1", "virtio"]
|
||||
end
|
||||
|
||||
config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'"
|
||||
|
||||
config.vm.provision 'shell' do |s|
|
||||
s.path = '../vagrant_provision.sh'
|
||||
s.privileged = true
|
||||
end
|
||||
|
||||
config.vm.provision :shell, privileged:false, inline: <<-SHELL
|
||||
echo -e "Cloning the WebGoat container repository"
|
||||
git clone -b master https://github.com/WebGoat/WebGoat.git
|
||||
echo -e "Cloning the WebGoat Lessons repository"
|
||||
git clone -b master https://github.com/WebGoat/WebGoat-Lessons.git
|
||||
SHELL
|
||||
|
||||
config.vm.provision 'shell' do |s|
|
||||
s.inline = "echo Finished provisioning, login with user vagrant pass vagrant"
|
||||
end
|
||||
|
||||
end
|
||||
|
35
webgoat-images/vagrant-training/Vagrantfile
vendored
Normal file
35
webgoat-images/vagrant-training/Vagrantfile
vendored
Normal 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.RELEASE/webgoat-server-8.0.0.RELEASE.jar
|
||||
wget https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.RELEASE/webwolf-8.0.0.RELEASE.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.RELEASE.jar &
|
||||
sleep 40s
|
||||
java -jar webwolf-8.0.0.RELEASE.jar
|
||||
SHELL
|
||||
|
||||
end
|
48
webgoat-images/vagrant-users/Vagrantfile
vendored
48
webgoat-images/vagrant-users/Vagrantfile
vendored
@ -1,48 +0,0 @@
|
||||
#For now use the same as for developers but start WebGoat
|
||||
#In the future we can add Docker as well and then Vagrant can start the
|
||||
#Docker container or Chef which setups the Tomcat
|
||||
|
||||
Vagrant.configure(2) do |config|
|
||||
config.vm.box = "boxcutter/ubuntu1604-desktop"
|
||||
config.vm.network :forwarded_port, guest: 8080, host: 9999
|
||||
config.vm.provider "virtualbox" do |vb|
|
||||
vb.gui = false
|
||||
vb.memory = "2048"
|
||||
vb.cpus = 2
|
||||
vb.name = "WebGoat-Users"
|
||||
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-Users"
|
||||
end
|
||||
|
||||
config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'"
|
||||
|
||||
config.vm.provision 'shell' do |s|
|
||||
s.path = '../vagrant_provision.sh'
|
||||
s.privileged = true
|
||||
end
|
||||
|
||||
config.vm.provision :shell, inline: <<-SHELL
|
||||
echo -e "Cloning the WebGoat container repository"
|
||||
git clone -b master https://github.com/WebGoat/WebGoat.git
|
||||
echo -e "Cloning the WebGoat Lessons repository"
|
||||
git clone -b master https://github.com/WebGoat/WebGoat-Lessons.git
|
||||
echo -e "Compiling and installing the WebGoat Container lesson server....."
|
||||
mvn -q -DskipTests -file WebGoat/pom.xml clean compile install
|
||||
echo -e "Compiling and installing the WebGoat Lessons $COL_RESET"
|
||||
mvn -q -DskipTests -file WebGoat-Lessons/pom.xml package
|
||||
echo -e "Copying the compiled lessons jars into the container so we can start the lesson server with some base lessons"
|
||||
cp -fa ./WebGoat-Lessons/target/plugins/*.jar ./WebGoat/webgoat-container/src/main/webapp/plugin_lessons/
|
||||
nohup mvn -q -DskipTests -file WebGoat/pom.xml -pl webgoat-container tomcat7:run-war 0<&- &>/dev/null &
|
||||
SHELL
|
||||
|
||||
config.vm.provision 'shell' do |s|
|
||||
s.inline = "echo Finished provisioning, open a browser and browse to http://localhost:9999/WebGoat/"
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,62 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
echo "Setting locale..."
|
||||
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
|
||||
|
||||
sudo kill -9 $(lsof -t /var/lib/dpkg/lock) || true
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y git
|
||||
|
||||
echo "Installing required packages..."
|
||||
sudo apt-get install -y -q build-essential autotools-dev automake pkg-config expect
|
||||
|
||||
|
||||
## Chrome
|
||||
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
|
||||
sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y google-chrome-stable
|
||||
|
||||
## Java 8
|
||||
echo "Provisioning Java 8..."
|
||||
mkdir -p /home/vagrant/java
|
||||
cd /home/vagrant/java
|
||||
test -f /tmp/jdk-8-linux-x64.tar.gz || curl -q -L --cookie "oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u101-b13/jdk-8u101-linux-x64.tar.gz -o /tmp/jdk-8-linux-x64.tar.gz
|
||||
|
||||
sudo mkdir -p /usr/lib/jvm
|
||||
sudo tar zxf /tmp/jdk-8-linux-x64.tar.gz -C /usr/lib/jvm
|
||||
|
||||
sudo update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk1.8.0_101/bin/java" 1
|
||||
sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk1.8.0_101/bin/javac" 1
|
||||
sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/lib/jvm/jdk1.8.0_101/bin/javaws" 1
|
||||
|
||||
sudo chmod a+x /usr/bin/java
|
||||
sudo chmod a+x /usr/bin/javac
|
||||
sudo chmod a+x /usr/bin/javaws
|
||||
sudo chown -R root:root /usr/lib/jvm/jdk1.8.0_101
|
||||
|
||||
echo "export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_101" >> /home/vagrant/.bashrc
|
||||
|
||||
## Maven
|
||||
echo "Installing Maven.."
|
||||
sudo apt-get install -y maven
|
||||
|
||||
## ZAP
|
||||
echo "Provisioning ZAP..."
|
||||
cd /home/vagrant
|
||||
mkdir tools
|
||||
cd tools
|
||||
wget https://github.com/zaproxy/zaproxy/releases/download/2.5.0/ZAP_2.5.0_Linux.tar.gz
|
||||
tar xvfx ZAP_2.5.0_Linux.tar.gz
|
||||
rm -rf ZAP_2.5.0_Linux.tar.gz
|
||||
|
||||
## IntelliJ
|
||||
cd /home/vagrant/tools
|
||||
wget https://download.jetbrains.com/idea/ideaIC-2016.1.4.tar.gz
|
||||
tar xvfz ideaIC-2016.1.4.tar.gz
|
||||
rm -rf ideaIC-2016.1.4.tar.gz
|
||||
|
||||
## Eclipse
|
||||
sudo apt-get -y install eclipse
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>8.0.0.M1</version>
|
||||
<version>v8.0.0.M15</version>
|
||||
</parent>
|
||||
|
||||
</project>
|
||||
|
@ -1,4 +1,4 @@
|
||||
== Authentication Bpasses
|
||||
== Authentication Bypasses
|
||||
|
||||
Authentication Bypasses happen in many ways, but usually take advantage of some flaw in the configuration or logic. Tampering to achieve the right conditions.
|
||||
|
||||
@ -12,4 +12,4 @@ Sometimes, if an attacker doesn't know the correct value of a parameter, they ma
|
||||
|
||||
=== Forced Browsing
|
||||
|
||||
If an area of a site is not protected properly by configuation, that area of the site may be accessed by guessing/brute-forcing.
|
||||
If an area of a site is not protected properly by configuration, that area of the site may be accessed by guessing/brute-forcing.
|
||||
|
Binary file not shown.
@ -6,6 +6,6 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>8.0.0.M1</version>
|
||||
<version>v8.0.0.M15</version>
|
||||
</parent>
|
||||
</project>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>8.0.0.M1</version>
|
||||
<version>v8.0.0.M15</version>
|
||||
</parent>
|
||||
|
||||
|
||||
|
@ -46,7 +46,6 @@ public class Flag extends Endpoint {
|
||||
@PostConstruct
|
||||
public void initFlags() {
|
||||
IntStream.range(1, 10).forEach(i -> FLAGS.put(i, UUID.randomUUID().toString()));
|
||||
FLAGS.entrySet().stream().forEach(e -> log.debug("Flag {} {}", e.getKey(), e.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -10,11 +10,8 @@ public interface SolutionConstants {
|
||||
|
||||
//TODO should be random generated when starting the server
|
||||
String PASSWORD = "!!webgoat_admin_1234!!";
|
||||
String SUPER_COUPON_CODE = "get_it_for_free";
|
||||
String PASSWORD_TOM = "thisisasecretfortomonly";
|
||||
String PASSWORD_LARRY = "larryknows";
|
||||
String JWT_PASSWORD = "victory";
|
||||
String ADMIN_PASSWORD_LINK = "375afe1104f4a487a73823c50a9292a2";
|
||||
String PASSWORD_TOM_9 = "somethingVeryRandomWhichNoOneWillEverTypeInAsPasswordForTom";
|
||||
String TOM_EMAIL = "tom@webgoat-cloud.org";
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
package org.owasp.webgoat.plugin.challenge2;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/21/17.
|
||||
*/
|
||||
public class Challenge2 extends NewLesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CHALLENGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHints() {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getDefaultRanking() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "challenge2.title";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "Challenge2";
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ public class Assignment7 extends AssignmentEndpoint {
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
@Value("${webworf.url.mail}")
|
||||
@Value("${webwolf.url.mail}")
|
||||
private String webWolfMailURL;
|
||||
|
||||
@GetMapping("/reset-password/{link}")
|
||||
|
@ -1,112 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:Challenge_2.adoc"></div>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/challenge2.css}"/>
|
||||
<script th:src="@{/lesson_js/challenge2.js}" language="JavaScript"></script>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/challenge/2"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
|
||||
<input id="discount" type="hidden" value="0"/>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xs-3 item-photo">
|
||||
<img style="max-width:100%;" th:src="@{/images/samsung-black.jpg}"/>
|
||||
</div>
|
||||
<div class="col-xs-5" style="border:0px solid gray">
|
||||
<h3>Samsung Galaxy S8</h3>
|
||||
<h5 style="color:#337ab7"><a href="http://www.samsung.com">Samsung</a> ·
|
||||
<small style="color:#337ab7">(124421 reviews)</small>
|
||||
</h5>
|
||||
|
||||
<h6 class="title-price">
|
||||
<small>PRICE</small>
|
||||
</h6>
|
||||
<h3 style="margin-top:0px;"><span>US $</span><span id="price">899</span></h3>
|
||||
|
||||
<div class="section">
|
||||
<h6 class="title-attr" style="margin-top:15px;">
|
||||
<small>COLOR</small>
|
||||
</h6>
|
||||
<div>
|
||||
<div class="attr" style="width:25px;background:lightgrey;"></div>
|
||||
<div class="attr" style="width:25px;background:black;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" style="padding-bottom:5px;">
|
||||
<h6 class="title-attr">
|
||||
<small>CAPACITY</small>
|
||||
</h6>
|
||||
<div>
|
||||
<div class="attr2">64 GB</div>
|
||||
<div class="attr2">128 GB</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" style="padding-bottom:5px;">
|
||||
<h6 class="title-attr">
|
||||
<small>QUANTITY</small>
|
||||
</h6>
|
||||
<div>
|
||||
<div class="btn-minus"><span class="glyphicon glyphicon-minus"></span></div>
|
||||
<input class="quantity" value="1"/>
|
||||
<div class="btn-plus"><span class="glyphicon glyphicon-plus"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section" style="padding-bottom:5px;">
|
||||
<h6 class="title-attr">
|
||||
<small>CHECKOUT CODE</small>
|
||||
</h6>
|
||||
<!--
|
||||
Checkout code: webgoat, owasp, owasp-webgoat
|
||||
-->
|
||||
<input name="checkoutCode" class="checkoutCode" value=""/>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section" style="padding-bottom:20px;">
|
||||
<button type="submit" class="btn btn-success"><span style="margin-right:20px"
|
||||
class="glyphicon glyphicon-shopping-cart"
|
||||
aria-hidden="true"></span>Buy
|
||||
</button>
|
||||
<h6><a href="#"><span class="glyphicon glyphicon-heart-empty"
|
||||
style="cursor:pointer;"></span>
|
||||
Like</a></h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<br/>
|
||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/challenge/flag">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
||||
style="font-size:20px"></i></div>
|
||||
<input type="text" class="form-control" id="flag" name="flag"
|
||||
placeholder="a7179f89-906b-4fec-9d99-f15b796e7208"/>
|
||||
</div>
|
||||
<div class="input-group" style="margin-top: 10px">
|
||||
<button type="submit" class="btn btn-primary">Submit flag</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<br/>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</html>
|
@ -1,109 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:Challenge_9.adoc"></div>
|
||||
<script th:src="@{/lesson_js/challenge9.js}" language="JavaScript"></script>
|
||||
|
||||
<div class="attack-container">
|
||||
<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-6">
|
||||
<h4 style="border-bottom: 1px solid #c5c5c5;">
|
||||
<i class="glyphicon glyphicon-user"></i>
|
||||
Account Access
|
||||
</h4>
|
||||
<div style="padding: 20px;" id="form-login">
|
||||
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/challenge/9/login"
|
||||
enctype="application/json;charset=UTF-8" role="form">
|
||||
<fieldset>
|
||||
<div class="form-group input-group">
|
||||
<span class="input-group-addon"> @ </span>
|
||||
<input class="form-control" placeholder="Email" name="email" type="email"
|
||||
required="" autofocus=""/>
|
||||
</div>
|
||||
<div class="form-group input-group">
|
||||
<span class="input-group-addon">
|
||||
<i class="glyphicon glyphicon-lock">
|
||||
</i>
|
||||
</span>
|
||||
<input class="form-control" placeholder="Password" name="password" type="password"
|
||||
value="" required=""/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-block">
|
||||
Access
|
||||
</button>
|
||||
<p class="help-block">
|
||||
<a class="pull-right text-muted" href="#" id="login">
|
||||
<small>Forgot your password?</small>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<div style="display: none;" id="form-login">
|
||||
<h4 class="">
|
||||
Forgot your password?
|
||||
</h4>
|
||||
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/challenge/9/create-password-reset-link"
|
||||
enctype="application/json;charset=UTF-8" role="form">
|
||||
<fieldset>
|
||||
<span class="help-block">
|
||||
Email address you use to log in to your account
|
||||
<br/>
|
||||
We'll send you an email with instructions to choose a new password.
|
||||
</span>
|
||||
<div class="form-group input-group">
|
||||
<span class="input-group-addon">
|
||||
@
|
||||
</span>
|
||||
<input class="form-control" placeholder="Email" name="email" type="email"
|
||||
required=""/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-block" id="btn-login">
|
||||
Continue
|
||||
</button>
|
||||
<p class="help-block">
|
||||
<a class="text-muted" href="#" id="forgot">
|
||||
<small>Account Access</small>
|
||||
</a>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/challenge/flag">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
||||
style="font-size:20px"></i></div>
|
||||
<input type="text" class="form-control" id="flag" name="flag"
|
||||
placeholder="a7179f89-906b-4fec-9d99-f15b796e7208"/>
|
||||
</div>
|
||||
<div class="input-group" style="margin-top: 10px">
|
||||
<button type="submit" class="btn btn-primary">Submit flag</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<br/>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</html>
|
@ -22,8 +22,7 @@ challenge.flag.incorrect=Sorry this is not the correct flag, please try again.
|
||||
|
||||
ip.address.unknown=IP address unknown, e-mail has been sent.
|
||||
|
||||
login_failed=Login failed
|
||||
login_failed.tom=Sorry only Tom can login at the moment
|
||||
|
||||
|
||||
required4=Missing username or password, please specify both.
|
||||
user.not.larry=Please try to log in as Larry not {0}.
|
@ -1,10 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
$('#login').click(function(e) {
|
||||
e.preventDefault();
|
||||
$('div#form-login').toggle('500');
|
||||
});
|
||||
$('#forgot').click(function(e) {
|
||||
e.preventDefault();
|
||||
$('div#form-login').toggle('500');
|
||||
});
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
Tom always resets his password immediately after receiving the email with the link.
|
||||
Try to reset the password of Tom (tom@webgoat-cloud.org) to your own choice and login as Tom with
|
||||
that password.
|
@ -1,49 +0,0 @@
|
||||
package org.owasp.webgoat.plugin.challenge2;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpointTest;
|
||||
import org.owasp.webgoat.plugin.Flag;
|
||||
import org.owasp.webgoat.plugin.SolutionConstants;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 5/2/17.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class Assignment2Test extends AssignmentEndpointTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
Assignment2 assignment2 = new Assignment2();
|
||||
init(assignment2);
|
||||
new Flag().initFlags();
|
||||
this.mockMvc = standaloneSetup(assignment2).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void success() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/challenge/2")
|
||||
.param("checkoutCode", SolutionConstants.SUPER_COUPON_CODE))
|
||||
.andExpect(jsonPath("$.feedback", CoreMatchers.containsString("flag: " + Flag.FLAGS.get(2))))
|
||||
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongCouponCode() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/challenge/2")
|
||||
.param("checkoutCode", "test"))
|
||||
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved"))))
|
||||
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>8.0.0.M1</version>
|
||||
<version>v8.0.0.M15</version>
|
||||
</parent>
|
||||
|
||||
</project>
|
||||
|
@ -56,7 +56,7 @@ public class ClientSideFiltering extends NewLesson {
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Client side filtering";
|
||||
return "client.side.filtering.title";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,9 +1,9 @@
|
||||
package org.owasp.webgoat.plugin.challenge2;
|
||||
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.plugin.Flag;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@ -11,22 +11,23 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.owasp.webgoat.plugin.SolutionConstants.SUPER_COUPON_CODE;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/6/17.
|
||||
*/
|
||||
@AssignmentPath("/challenge/2")
|
||||
public class Assignment2 extends AssignmentEndpoint {
|
||||
@AssignmentPath("/clientSideFiltering/getItForFree")
|
||||
@AssignmentHints({"client.side.filtering.free.hint1", "client.side.filtering.free.hint2", "client.side.filtering.free.hint3"})
|
||||
public class ClientSideFilteringFreeAssignment extends AssignmentEndpoint {
|
||||
|
||||
public static final String SUPER_COUPON_CODE = "get_it_for_free";
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public
|
||||
@ResponseBody
|
||||
AttackResult completed(@RequestParam String checkoutCode) throws IOException {
|
||||
AttackResult completed(@RequestParam String checkoutCode) {
|
||||
if (SUPER_COUPON_CODE.equals(checkoutCode)) {
|
||||
return success().feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(2)).build();
|
||||
return trackProgress(success().build());
|
||||
}
|
||||
return failed().build();
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.owasp.webgoat.plugin.challenge2;
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import com.beust.jcommander.internal.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
@ -12,21 +12,21 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.owasp.webgoat.plugin.SolutionConstants.SUPER_COUPON_CODE;
|
||||
import static org.owasp.webgoat.plugin.ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/6/17.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("challenge-store")
|
||||
@RequestMapping("/clientSideFiltering/challenge-store")
|
||||
public class ShopEndpoint {
|
||||
|
||||
@AllArgsConstructor
|
||||
private class CheckoutCodes {
|
||||
|
||||
@Getter
|
||||
private List<CheckoutCode> codes = Lists.newArrayList();
|
||||
private List<CheckoutCode> codes;
|
||||
|
||||
public Optional<CheckoutCode> get(String code) {
|
||||
return codes.stream().filter(c -> c.getCode().equals(code)).findFirst();
|
@ -73,7 +73,96 @@
|
||||
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:ClientSideFiltering_final.adoc"></div>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/clientSideFilteringFree.css}"/>
|
||||
<script th:src="@{/lesson_js/clientSideFilteringFree.js}" language="JavaScript"></script>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/clientSideFiltering/getItForFree"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
|
||||
<input id="discount" type="hidden" value="0"/>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xs-3 item-photo">
|
||||
<img style="max-width:100%;" th:src="@{/images/samsung-black.jpg}"/>
|
||||
</div>
|
||||
<div class="col-xs-5" style="border:0px solid gray">
|
||||
<h3>Samsung Galaxy S8</h3>
|
||||
<h5 style="color:#337ab7"><a href="http://www.samsung.com">Samsung</a> ·
|
||||
<small style="color:#337ab7">(124421 reviews)</small>
|
||||
</h5>
|
||||
|
||||
<h6 class="title-price">
|
||||
<small>PRICE</small>
|
||||
</h6>
|
||||
<h3 style="margin-top:0px;"><span>US $</span><span id="price">899</span></h3>
|
||||
|
||||
<div class="section">
|
||||
<h6 class="title-attr" style="margin-top:15px;">
|
||||
<small>COLOR</small>
|
||||
</h6>
|
||||
<div>
|
||||
<div class="attr" style="width:25px;background:lightgrey;"></div>
|
||||
<div class="attr" style="width:25px;background:black;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" style="padding-bottom:5px;">
|
||||
<h6 class="title-attr">
|
||||
<small>CAPACITY</small>
|
||||
</h6>
|
||||
<div>
|
||||
<div class="attr2">64 GB</div>
|
||||
<div class="attr2">128 GB</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" style="padding-bottom:5px;">
|
||||
<h6 class="title-attr">
|
||||
<small>QUANTITY</small>
|
||||
</h6>
|
||||
<div>
|
||||
<div class="btn-minus"><span class="glyphicon glyphicon-minus"></span></div>
|
||||
<input class="quantity" value="1"/>
|
||||
<div class="btn-plus"><span class="glyphicon glyphicon-plus"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section" style="padding-bottom:5px;">
|
||||
<h6 class="title-attr">
|
||||
<small>CHECKOUT CODE</small>
|
||||
</h6>
|
||||
<!--
|
||||
Checkout code: webgoat, owasp, owasp-webgoat
|
||||
-->
|
||||
<input name="checkoutCode" class="checkoutCode" value=""/>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section" style="padding-bottom:20px;">
|
||||
<button type="submit" class="btn btn-success"><span style="margin-right:20px"
|
||||
class="glyphicon glyphicon-shopping-cart"
|
||||
aria-hidden="true"></span>Buy
|
||||
</button>
|
||||
<h6><a href="#"><span class="glyphicon glyphicon-heart-empty"
|
||||
style="cursor:pointer;"></span>
|
||||
Like</a></h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</html>
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
client.side.filtering.title=Client side filtering
|
||||
ClientSideFilteringSelectUser=Select user:
|
||||
ClientSideFilteringUserID=User ID
|
||||
ClientSideFilteringFirstName=First Name
|
||||
@ -25,3 +26,7 @@ ClientSideFilteringHint10=Stage 2: Your filter operator should look something li
|
||||
ClientSideFilteringInstructions1=STAGE 1: You are logged in as Moe Stooge, CSO of Goat Hills Financial. You have access to everyone in the company's information, except the CEO, . Or at least you shouldn't have access to the CEO's information. For this exercise, examine the contents of the page to see what extra information you can find.
|
||||
ClientSideFilteringInstructions2=STAGE 2: Now, fix the problem. Modify the server to only return results that Moe Stooge is allowed to see.
|
||||
ClientSideFiltering.incorrect=This is not the salary from Neville Bartholomew...
|
||||
|
||||
client.side.filtering.free.hint1=Look through the webpage inspect the sources etc
|
||||
client.side.filtering.free.hint2=Try to see the flow of request from the page to the backend
|
||||
client.side.fiterling.free.hint3=One of the responses contains the answer
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
@ -38,7 +38,7 @@ $(document).ready(function () {
|
||||
})
|
||||
$(".checkoutCode").on("blur", function () {
|
||||
var checkoutCode = $(".checkoutCode").val();
|
||||
$.get("challenge-store/coupons/" + checkoutCode, function (result, status) {
|
||||
$.get("clientSideFiltering/challenge-store/coupons/" + checkoutCode, function (result, status) {
|
||||
var discount = result.discount;
|
||||
if (discount > 0) {
|
||||
$('#discount').text(discount);
|
@ -0,0 +1,49 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.owasp.webgoat.plugins.LessonTest;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
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.owasp.webgoat.plugin.ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 5/2/17.
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class ClientSideFilteringFreeAssignmentTest extends LessonTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
ClientSideFiltering clientSideFiltering = new ClientSideFiltering();
|
||||
when(webSession.getCurrentLesson()).thenReturn(clientSideFiltering);
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
when(webSession.getUserName()).thenReturn("unit-test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void success() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/clientSideFiltering/getItForFree")
|
||||
.param("checkoutCode", SUPER_COUPON_CODE))
|
||||
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongCouponCode() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/clientSideFiltering/getItForFree")
|
||||
.param("checkoutCode", "test"))
|
||||
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved"))))
|
||||
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.owasp.webgoat.plugin.challenge2;
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.Before;
|
||||
@ -9,7 +9,7 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.owasp.webgoat.plugin.SolutionConstants.SUPER_COUPON_CODE;
|
||||
import static org.owasp.webgoat.plugin.ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
|
||||
|
||||
@ -30,28 +30,28 @@ public class ShopEndpointTest {
|
||||
|
||||
@Test
|
||||
public void getSuperCoupon() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/" + SUPER_COUPON_CODE))
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/" + SUPER_COUPON_CODE))
|
||||
.andExpect(jsonPath("$.code", CoreMatchers.is(SUPER_COUPON_CODE)))
|
||||
.andExpect(jsonPath("$.discount", CoreMatchers.is(100)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCoupon() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/webgoat"))
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/webgoat"))
|
||||
.andExpect(jsonPath("$.code", CoreMatchers.is("webgoat")))
|
||||
.andExpect(jsonPath("$.discount", CoreMatchers.is(25)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void askForUnknownCouponCode() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/does-not-exists"))
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/does-not-exists"))
|
||||
.andExpect(jsonPath("$.code", CoreMatchers.is("no")))
|
||||
.andExpect(jsonPath("$.discount", CoreMatchers.is(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fetchAllTheCouponsShouldContainGetItForFree() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/"))
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/"))
|
||||
.andExpect(jsonPath("$.codes[3].code", is("get_it_for_free")));
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>8.0.0.M1</version>
|
||||
<version>v8.0.0.M15</version>
|
||||
</parent>
|
||||
<build>
|
||||
<plugins>
|
||||
|
@ -60,7 +60,7 @@ public class CrossSiteScripting extends NewLesson {
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Cross Site Scripting";
|
||||
return "xss.title";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,7 +64,7 @@ public class CrossSiteScriptingLesson5a extends AssignmentEndpoint {
|
||||
userSessionData.setValue("xss-reflected1-complete",(Object)"false");
|
||||
StringBuffer cart = new StringBuffer();
|
||||
cart.append("Thank you for shopping at WebGoat. <br />You're support is appreciated<hr />");
|
||||
cart.append("<p>We have chaged credit card:" + field1 + "<br />");
|
||||
cart.append("<p>We have charged credit card:" + field1 + "<br />");
|
||||
cart.append( " ------------------- <br />");
|
||||
cart.append( " $" + totalSale);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
# XSS success, failure messages and hints
|
||||
xss.title=Cross Site Scripting
|
||||
xss-reflected-5a-success=well done, but alerts aren't very impressive are they? Please continue.
|
||||
xss-reflected-5a-failure=Try again. We do want to see this specific javascript (in case you are trying to do something more fancy)
|
||||
xss-reflected-5b-success=Correct ... because <ul><li>The script was not triggered by the URL/QueryString</li><li>Even if you use the attack URL in a new tab, it won't execute (becuase of response type). Try it if you like.</li></ul>
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
|
||||
=== Why?
|
||||
Hopefully we've covered that by now. Bottom line, you don't want someone else's code running in the context of your users and their logged-in seession
|
||||
Hopefully we've covered that by now. Bottom line, you don't want someone else's code running in the context of your users and their logged-in session
|
||||
|
||||
=== What to encode?
|
||||
The basic premise of defending against XSS is *output endoding* any untrusted input that goes to the screen.
|
||||
The basic premise of defending against XSS is *output encoding* any untrusted input that goes to the screen.
|
||||
That may be changing with more sophisticated attacks, but is still the best defense we currently have. *AND* ... *context matters*
|
||||
|
||||
Another word on 'untrusted input'. If in doubt, treat everything (even data you populated in your DB as untrusted).
|
||||
|
@ -33,8 +33,10 @@ import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpointTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
@ -80,13 +82,13 @@ public class StoredXssCommentsTest extends AssignmentEndpointTest {
|
||||
*/
|
||||
|
||||
//Ensures it is vulnerable
|
||||
// @Test
|
||||
// public void isNotEncoded() throws Exception {
|
||||
// //do get to get comments after posting xss payload
|
||||
// ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScripting/stored-xss"));
|
||||
// taintedResults.andExpect(jsonPath("$[0].text",CoreMatchers.is(CoreMatchers.containsString("<script>console.warn('unit test me')</script>"))));
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void isNotEncoded() throws Exception {
|
||||
//do get to get comments after posting xss payload
|
||||
ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScripting/stored-xss"));
|
||||
MvcResult mvcResult = taintedResults.andReturn();
|
||||
assert(mvcResult.getResponse().getContentAsString().contains("<script>console.warn"));
|
||||
}
|
||||
|
||||
//Could be used to test an encoding solution ... commented out so build will pass. Uncommenting will fail build, but leaving in as positive Security Unit Test
|
||||
// @Test
|
||||
|
@ -6,6 +6,6 @@
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>8.0.0.M1</version>
|
||||
<version>v8.0.0.M15</version>
|
||||
</parent>
|
||||
</project>
|
@ -6,12 +6,9 @@ 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.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Created by jason on 9/29/17.
|
||||
*/
|
||||
@ -24,12 +21,16 @@ public class CSRFConfirmFlag1 extends AssignmentEndpoint {
|
||||
UserSessionData userSessionData;
|
||||
|
||||
@PostMapping(produces = {"application/json"})
|
||||
public @ResponseBody AttackResult completed(String confirmFlagVal) {
|
||||
public @ResponseBody
|
||||
AttackResult completed(String confirmFlagVal) {
|
||||
|
||||
if (confirmFlagVal.equals(userSessionData.getValue("csrf-get-success").toString())) {
|
||||
return success().feedback("csrf-get-null-referer.success").output("Correct, the flag was " + userSessionData.getValue("csrf-get-success")).build();
|
||||
Object userSessionDataStr = userSessionData.getValue("csrf-get-success");
|
||||
if (userSessionDataStr != null && confirmFlagVal.equals(userSessionDataStr.toString())) {
|
||||
return trackProgress(
|
||||
success().feedback("csrf-get-null-referer.success").output("Correct, the flag was " + userSessionData.getValue("csrf-get-success")).build()
|
||||
);
|
||||
}
|
||||
|
||||
return failed().feedback("").build();
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
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 origin = request.getHeader("origin");
|
||||
if (referer != null) {
|
||||
return !referer.contains(origin);
|
||||
} else {
|
||||
return true; //this case referer is null or origin does not matter we cannot compare so we return true which should of course be false
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
*/
|
||||
}
|
@ -40,12 +40,22 @@ public class CSRFGetFlag extends Endpoint {
|
||||
String referer = (req.getHeader("referer") == null) ? "NULL" : req.getHeader("referer");
|
||||
String[] refererArr = referer.split("/");
|
||||
|
||||
if (referer.equals("NULL") && req.getParameter("csrf").equals("true")) {
|
||||
|
||||
|
||||
if (referer.equals("NULL")) {
|
||||
if (req.getParameter("csrf").equals("true")) {
|
||||
Random random = new Random();
|
||||
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
|
||||
response.put("success", true);
|
||||
response.put("message", pluginMessages.getMessage("csrf-get-null-referer.success"));
|
||||
response.put("flag", userSessionData.getValue("csrf-get-success"));
|
||||
} else {
|
||||
Random random = new Random();
|
||||
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
|
||||
response.put("success", true);
|
||||
response.put("message", pluginMessages.getMessage("csrf-get-other-referer.success"));
|
||||
response.put("flag", userSessionData.getValue("csrf-get-success"));
|
||||
}
|
||||
} else if (refererArr[2].equals(host)) {
|
||||
response.put("success", false);
|
||||
response.put("message", "Appears the request came from the original host");
|
||||
|
@ -1,69 +0,0 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.owasp.webgoat.assignments.Endpoint;
|
||||
import org.owasp.webgoat.i18n.PluginMessages;
|
||||
import org.owasp.webgoat.session.UserSessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
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.Map;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by jason on 9/30/17.
|
||||
*/
|
||||
|
||||
public class CSRFGetXhrFlag extends Endpoint {
|
||||
|
||||
@Autowired
|
||||
UserSessionData userSessionData;
|
||||
@Autowired
|
||||
private PluginMessages pluginMessages;
|
||||
|
||||
@RequestMapping(produces = {"application/json"}, method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Map<String, Object> invoke(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
|
||||
Map<String,Object> response = new HashMap<>();
|
||||
|
||||
String host = (req.getHeader("host") == null) ? "NULL" : req.getHeader("host");
|
||||
// String origin = (req.getHeader("origin") == null) ? "NULL" : req.getHeader("origin");
|
||||
// Integer serverPort = (req.getServerPort() < 1) ? 0 : req.getServerPort();
|
||||
// String serverName = (req.getServerName() == null) ? "NULL" : req.getServerName();
|
||||
String referer = (req.getHeader("referer") == null) ? "NULL" : req.getHeader("referer");
|
||||
String[] refererArr = referer.split("/");
|
||||
|
||||
if (referer.equals("NULL") && req.getParameter("csrf").equals("true")) {
|
||||
Random random = new Random();
|
||||
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
|
||||
response.put("success",true);
|
||||
response.put("message",pluginMessages.getMessage("csrf-get-null-referer.success"));
|
||||
response.put("flag",userSessionData.getValue("csrf-get-success"));
|
||||
} else if (refererArr[2].equals(host)) {
|
||||
response.put("success", false);
|
||||
response.put("message", "Appears the request came from the original host");
|
||||
response.put("flag", null);
|
||||
} else {
|
||||
Random random = new Random();
|
||||
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
|
||||
response.put("success",true);
|
||||
response.put("message",pluginMessages.getMessage("csrf-get-other-referer.success"));
|
||||
response.put("flag",userSessionData.getValue("csrf-get-success"));
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return "/csrf/get-xhr-flag";
|
||||
}
|
||||
}
|
@ -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.findByUser(username);
|
||||
userTracker.assignmentSolved(getWebSession().getCurrentLesson(), this.getClass().getSimpleName());
|
||||
userTrackerRepository.save(userTracker);
|
||||
}
|
||||
}
|
@ -115,22 +115,13 @@ public class ForgedReviews extends AssignmentEndpoint {
|
||||
userReviews.put(webSession.getUserName(), reviews);
|
||||
//short-circuit
|
||||
if (validateReq == null || !validateReq.equals(weakAntiCSRF)) {
|
||||
return failed().feedback("csrf-you-forgot-something").build();
|
||||
return trackProgress(failed().feedback("csrf-you-forgot-something").build());
|
||||
}
|
||||
//we have the spoofed files
|
||||
if (referer != "NULL" && refererArr[2].equals(host) ) {
|
||||
return (failed().feedback("csrf-same-host").build());
|
||||
return trackProgress(failed().feedback("csrf-same-host").build());
|
||||
} else {
|
||||
return (success().feedback("csrf-review.success").build()); //feedback("xss-stored-comment-failure")
|
||||
}
|
||||
}
|
||||
|
||||
private Review parseJson(String comment) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try {
|
||||
return mapper.readValue(comment, Review.class);
|
||||
} catch (IOException e) {
|
||||
return new Review();
|
||||
return trackProgress(success().feedback("csrf-review.success").build()); //feedback("xss-stored-comment-failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
<form accept-charset="UNKNOWN" id="basic-csrf-get"
|
||||
method="GET" name="form1"
|
||||
target="_blank"
|
||||
successCallback=""
|
||||
action="/WebGoat/csrf/basic-get-flag"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
@ -26,10 +27,12 @@
|
||||
<div class="adoc-content" th:replace="doc:CSRF_Basic_Get-1.adoc"></div>
|
||||
|
||||
<div class="attack-container">
|
||||
<img th:src="@{/images/wolf-enabled.png}" class="webwolf-enabled"/>
|
||||
<div class="assignment-success">
|
||||
<i class="fa fa-2 fa-check hidden" aria-hidden="true">
|
||||
</i>
|
||||
</div>
|
||||
<br/>
|
||||
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-1"
|
||||
method="POST" name="form2"
|
||||
successCallback=""
|
||||
@ -40,7 +43,10 @@
|
||||
<input type="text" length="6" name="confirmFlagVal" value=""/>
|
||||
|
||||
<input name="submit" value="Submit" type="submit"/>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
</form>
|
||||
|
||||
<div class="attack-feedback"></div>
|
||||
@ -56,8 +62,9 @@
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/reviews.css}"/>
|
||||
<script th:src="@{/lesson_js/csrf-review.js}" language="JavaScript"></script>
|
||||
|
||||
<div class="attack-container">
|
||||
<img th:src="@{/images/wolf-enabled.png}" class="webwolf-enabled"/>
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="panel post">
|
||||
<div class="post-heading">
|
||||
@ -89,7 +96,8 @@
|
||||
method="POST" name="review-form"
|
||||
successCallback=""
|
||||
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"
|
||||
type="text"/>
|
||||
<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"/>
|
||||
@ -108,14 +116,149 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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="attack-container">
|
||||
<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 class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</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-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 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>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user