Merge branch 'develop' of github.com:misfir2/WebGoat into develop
This commit is contained in:
commit
e96ab488ff
6
.gitignore
vendored
6
.gitignore
vendored
@ -14,7 +14,8 @@
|
|||||||
/.settings/org.eclipse.wst.validation.prefs
|
/.settings/org.eclipse.wst.validation.prefs
|
||||||
/.externalToolBuilders/
|
/.externalToolBuilders/
|
||||||
.project
|
.project
|
||||||
/target
|
*/target/*
|
||||||
|
mongo-data/*
|
||||||
.classpath
|
.classpath
|
||||||
.idea/
|
.idea/
|
||||||
.settings/
|
.settings/
|
||||||
@ -29,6 +30,7 @@ src/main/webapp/plugin_lessons/*.jar
|
|||||||
src/main/webapp/users/*.props
|
src/main/webapp/users/*.props
|
||||||
classes/*
|
classes/*
|
||||||
*.iml
|
*.iml
|
||||||
|
pom.xml.versionsBackup
|
||||||
|
|
||||||
/*.iml
|
/*.iml
|
||||||
.extract/*
|
.extract/*
|
||||||
@ -39,3 +41,5 @@ webgoat-lessons/**/target
|
|||||||
**/*.jar
|
**/*.jar
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
webgoat-server/mongo-data/*
|
webgoat-server/mongo-data/*
|
||||||
|
webgoat-lessons/vulnerable-components/dependency-reduced-pom.xml
|
||||||
|
/.sonatype
|
15
.travis.yml
15
.travis.yml
@ -7,10 +7,20 @@ install: "/bin/true"
|
|||||||
script:
|
script:
|
||||||
- export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)
|
- export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)
|
||||||
- echo "TRAVIS_BRANCH=$TRAVIS_BRANCH, PR=$PR, BRANCH=$BRANCH"
|
- echo "TRAVIS_BRANCH=$TRAVIS_BRANCH, PR=$PR, BRANCH=$BRANCH"
|
||||||
|
- if [ ! -z "${TRAVIS_TAG}" ]; then mvn versions:set -DnewVersion=${TRAVIS_TAG:1}; fi
|
||||||
- mvn clean install -q
|
- mvn clean install -q
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- "$HOME/.m2"
|
- "$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:
|
deploy:
|
||||||
- provider: script
|
- provider: script
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
@ -25,10 +35,13 @@ deploy:
|
|||||||
repo: WebGoat/WebGoat
|
repo: WebGoat/WebGoat
|
||||||
branch: develop
|
branch: develop
|
||||||
- provider: releases
|
- provider: releases
|
||||||
|
skip_cleanup: true
|
||||||
|
overwrite: true
|
||||||
api_key:
|
api_key:
|
||||||
#api-key from webgoat-github user
|
#api-key from webgoat-github user
|
||||||
secure: pJOLBnl6427PcVg/tVy/qB18JC7b8cKpffau+IP0pjdSt7KUfBdBY3QuJ7mrM65zRoVILzggLckaew2PlRmYQRdumyWlyRn44XiJ9KO4n6Bsufbz+ictB4ggtozpp9+I9IIUh1TmqypL9lhkX2ONM9dSHmyblYpAAgMuYSK8FYc=
|
secure: pJOLBnl6427PcVg/tVy/qB18JC7b8cKpffau+IP0pjdSt7KUfBdBY3QuJ7mrM65zRoVILzggLckaew2PlRmYQRdumyWlyRn44XiJ9KO4n6Bsufbz+ictB4ggtozpp9+I9IIUh1TmqypL9lhkX2ONM9dSHmyblYpAAgMuYSK8FYc=
|
||||||
file: "webgoat-server/target/webgoat-server*.jar"
|
file_glob: true
|
||||||
|
file: $WEBGOAT_ARTIFACTS_FOLDER/*
|
||||||
on:
|
on:
|
||||||
repo: WebGoat/WebGoat
|
repo: WebGoat/WebGoat
|
||||||
tags: true
|
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.M3
|
||||||
|
git push origin v8.0.0.M3
|
||||||
|
```
|
||||||
|
|
||||||
|
Now Travis takes over and will create the release in Github and on Docker Hub.
|
||||||
|
|
||||||
|
|
46
README.MD
46
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://travis-ci.org/WebGoat/WebGoat)
|
||||||
[](https://coveralls.io/github/WebGoat/WebGoat?branch=master)
|
[](https://coveralls.io/github/WebGoat/WebGoat?branch=master)
|
||||||
[](https://www.codacy.com/app/dm/WebGoat)
|
[](https://www.codacy.com/app/dm/WebGoat)
|
||||||
[](https://www.versioneye.com/user/projects/562da95ae346d7000e0369aa)
|
[](https://www.versioneye.com/user/projects/562da95ae346d7000e0369aa)
|
||||||
[](https://www.owasp.org/index.php/OWASP_Project_Inventory#tab=Labs_Projects)
|
[](https://www.owasp.org/index.php/OWASP_Project_Inventory#tab=Labs_Projects)
|
||||||
|
[](https://github.com/WebGoat/WebGoat/releases/latest)
|
||||||
# Important
|
|
||||||
|
|
||||||
This is the development version of WebGoat 8, if you are looking for a released stable version please go to: https://github.com/WebGoat/WebGoat/wiki/Running-WebGoat
|
|
||||||
|
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
@ -44,6 +40,15 @@ docker pull webgoat/webgoat-8.0
|
|||||||
docker run -p 8080:8080 -it webgoat/webgoat-8.0 /home/webgoat/start.sh
|
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.
|
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`
|
- If you are using `docker-machine`, verify the machine IP using `docker-machine env`
|
||||||
@ -65,9 +70,23 @@ _Please note: this version may not be completely in sync with the develop branch
|
|||||||
Download the latest WebWolf release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases)
|
Download the latest WebWolf release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases)
|
||||||
|
|
||||||
```Shell
|
```Shell
|
||||||
java -jar webwolf-<<version>>.jar
|
java -jar webgoat-server-<<version>>.jar
|
||||||
```
|
```
|
||||||
|
|
||||||
|
By default WebGoat starts at port 8080 in order to change this use the following property:
|
||||||
|
|
||||||
|
```Shell
|
||||||
|
java -jar webgoat-server-<<version>>.jar --server.port=9090
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
## 3. Run from the sources
|
||||||
|
|
||||||
@ -88,18 +107,19 @@ Now let's start by compiling the project.
|
|||||||
|
|
||||||
```Shell
|
```Shell
|
||||||
cd WebGoat
|
cd WebGoat
|
||||||
git checkout develop
|
git checkout <<branch_name>>
|
||||||
mvn clean install
|
mvn clean install
|
||||||
```
|
```
|
||||||
|
|
||||||
Now we are ready to run the project. WebGoat 8.x is using Spring-Boot.
|
Now we are ready to run the project. WebGoat 8.x is using Spring-Boot.
|
||||||
|
|
||||||
```Shell
|
```Shell
|
||||||
mvn -pl webwolf spring-boot:run
|
mvn -pl webgoat-server spring-boot:run
|
||||||
```
|
```
|
||||||
... you should be running webgoat on localhost:8080/WebGoat momentarily
|
... you should be running webgoat on localhost:8080/WebGoat momentarily
|
||||||
|
|
||||||
To change IP addresss add the following variable to WebGoat/webgoat-container/src/main/resources/application.properties file
|
|
||||||
|
To change IP address add the following variable to WebGoat/webgoat-container/src/main/resources/application.properties file
|
||||||
|
|
||||||
```
|
```
|
||||||
server.address=x.x.x.x
|
server.address=x.x.x.x
|
||||||
@ -110,7 +130,7 @@ server.address=x.x.x.x
|
|||||||
We supply a complete development environment using Vagrant, to run WebGoat with Vagrant you must first have Vagrant and Virtualbox installed.
|
We supply a complete development environment using Vagrant, to run WebGoat with Vagrant you must first have Vagrant and Virtualbox installed.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ cd WebGoat/webgoat-images/vagrant-users
|
$ cd WebGoat/webgoat-images/vagrant-training
|
||||||
$ vagrant up
|
$ vagrant up
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -120,6 +140,8 @@ The source code will be available in the home directory.
|
|||||||
|
|
||||||
# Building a new Docker image
|
# 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).
|
WebGoat now has Docker support for x86 and ARM (raspberry pi).
|
||||||
### Docker on x86
|
### Docker on x86
|
||||||
On x86 you can build a container with the following commands:
|
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:
|
services:
|
||||||
activemq:
|
|
||||||
image: webcenter/activemq:latest
|
|
||||||
ports:
|
|
||||||
- 8161:8161
|
|
||||||
- 61616:61616
|
|
||||||
- 61613:61613
|
|
||||||
mongo:
|
|
||||||
image: mongo:latest
|
|
||||||
expose:
|
|
||||||
- "27017"
|
|
||||||
volumes:
|
|
||||||
- './mongo-data:/data/db'
|
|
||||||
webgoat:
|
webgoat:
|
||||||
build: webgoat-server/
|
image: webgoat/webgoat-8.0
|
||||||
command: "sh /home/webgoat/start.sh"
|
environment:
|
||||||
|
- WEBWOLF_HOST=webwolf
|
||||||
|
- spring.datasource.url=jdbc:hsqldb:hsql://webgoat_db:9001/webgoat
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
depends_on:
|
depends_on:
|
||||||
[mongo, activemq]
|
- db
|
||||||
environment:
|
|
||||||
WG_MONGO_PORT: 27017
|
|
||||||
WG_MONGO_HOST: mongo
|
|
||||||
WG_MQ_HOST: activemq
|
|
||||||
WG_MQ_PORT: 61616
|
|
||||||
WG_INTERNAL_MONGO: "false"
|
|
||||||
webwolf:
|
webwolf:
|
||||||
build: webwolf/
|
image: webgoat/webwolf
|
||||||
command: "sh /home/webwolf/start.sh"
|
environment:
|
||||||
depends_on:
|
- spring.datasource.url=jdbc:hsqldb:hsql://webgoat_db:9001/webgoat
|
||||||
- webgoat
|
|
||||||
ports:
|
ports:
|
||||||
- "8081:8081"
|
- "8081:8081"
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
db:
|
||||||
|
image: blacklabelops/hsqldb
|
||||||
|
container_name: webgoat_db
|
||||||
environment:
|
environment:
|
||||||
WG_MONGO_PORT: 27017
|
- HSQLDB_TRACE=false
|
||||||
WG_MONGO_HOST: mongo
|
- HSQLDB_SILENT=true
|
||||||
WG_MQ_HOST: activemq
|
- HSQLDB_DATABASE_NAME=webgoat
|
||||||
WG_MQ_PORT: 61616
|
- HSQLDB_DATABASE_ALIAS=webgoat
|
||||||
|
9
pom.xml
9
pom.xml
@ -5,7 +5,7 @@
|
|||||||
<groupId>org.owasp.webgoat</groupId>
|
<groupId>org.owasp.webgoat</groupId>
|
||||||
<artifactId>webgoat-parent</artifactId>
|
<artifactId>webgoat-parent</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
|
|
||||||
<name>WebGoat Parent Pom</name>
|
<name>WebGoat Parent Pom</name>
|
||||||
<description>Parent Pom for the WebGoat Project. A deliberately insecure Web Application</description>
|
<description>Parent Pom for the WebGoat Project. A deliberately insecure Web Application</description>
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>1.5.5.RELEASE</version>
|
<version>1.5.12.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<licenses>
|
<licenses>
|
||||||
@ -135,14 +135,13 @@
|
|||||||
<gatling-plugin.version>2.2.4</gatling-plugin.version>
|
<gatling-plugin.version>2.2.4</gatling-plugin.version>
|
||||||
<guava.version>18.0</guava.version>
|
<guava.version>18.0</guava.version>
|
||||||
<h2.version>1.4.190</h2.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>
|
<j2h.version>1.3.1</j2h.version>
|
||||||
<jackson-core.version>2.6.3</jackson-core.version>
|
<jackson-core.version>2.6.3</jackson-core.version>
|
||||||
<jackson-databind.version>2.6.3</jackson-databind.version>
|
<jackson-databind.version>2.6.3</jackson-databind.version>
|
||||||
<javaee-api.version>6.0</javaee-api.version>
|
<javaee-api.version>6.0</javaee-api.version>
|
||||||
<javax.transaction-api.version>1.2</javax.transaction-api.version>
|
<javax.transaction-api.version>1.2</javax.transaction-api.version>
|
||||||
<jcl-over-slf4j.version>1.7.12</jcl-over-slf4j.version>
|
<jcl-over-slf4j.version>1.7.12</jcl-over-slf4j.version>
|
||||||
<jstl.version>1.2</jstl.version>
|
|
||||||
<jtds.version>1.3.1</jtds.version>
|
<jtds.version>1.3.1</jtds.version>
|
||||||
<junit.version>4.12</junit.version>
|
<junit.version>4.12</junit.version>
|
||||||
<mail-api.version>1.5.4</mail-api.version>
|
<mail-api.version>1.5.4</mail-api.version>
|
||||||
@ -296,8 +295,8 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<version>1.16.10</version>
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
|
@ -4,19 +4,36 @@ docker login -u $DOCKER_USER -p $DOCKER_PASS
|
|||||||
export REPO=webgoat/webgoat-8.0
|
export REPO=webgoat/webgoat-8.0
|
||||||
|
|
||||||
cd webgoat-server
|
cd webgoat-server
|
||||||
|
ls target/
|
||||||
|
|
||||||
if [ "${BRANCH}" == "master" ] && [ ! -z "${TRAVIS_TAG}" ]; then
|
if [ "${BRANCH}" == "master" ] && [ ! -z "${TRAVIS_TAG}" ]; then
|
||||||
# If we push a tag to master this will update the LATEST Docker image and tag with the version number
|
# If we push a tag to master this will update the LATEST Docker image and tag with the version number
|
||||||
docker build -f Dockerfile -t $REPO:latest .
|
docker build --build-arg webgoat_version=${TRAVIS_TAG:1} -f Dockerfile -t $REPO:latest -t $REPO:${TRAVIS_TAG} .
|
||||||
docker tag $REPO:${TRAVIS_TAG}
|
|
||||||
docker push $REPO
|
docker push $REPO
|
||||||
elif [ ! -z "${TRAVIS_TAG}" ]; then
|
elif [ ! -z "${TRAVIS_TAG}" ]; then
|
||||||
# Creating a tag build we push it to Docker with that tag
|
# Creating a tag build we push it to Docker with that tag
|
||||||
docker build -f Dockerfile -t $REPO:${TRAVIS_TAG} .
|
docker build --build-arg webgoat_version=${TRAVIS_TAG:1} -f Dockerfile -t $REPO:${TRAVIS_TAG} -t $REPO:latest .
|
||||||
docker tag $REPO:${TRAVIS_TAG}
|
|
||||||
docker push $REPO
|
docker push $REPO
|
||||||
elif [ "${BRANCH}" == "develop" ]; then
|
#elif [ "${BRANCH}" == "develop" ]; then
|
||||||
docker build -f Dockerfile -t $REPO:snapshot .
|
# docker build -f Dockerfile -t $REPO:snapshot .
|
||||||
|
# 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
|
docker push $REPO
|
||||||
else
|
else
|
||||||
echo "Skipping releasing to DockerHub because it is a build of branch ${BRANCH}"
|
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>
|
<parent>
|
||||||
<groupId>org.owasp.webgoat</groupId>
|
<groupId>org.owasp.webgoat</groupId>
|
||||||
<artifactId>webgoat-parent</artifactId>
|
<artifactId>webgoat-parent</artifactId>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
@ -36,16 +36,6 @@
|
|||||||
|
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>de.flapdoodle.embed</groupId>
|
|
||||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
|
||||||
<version>2.0.0</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<resources>
|
<resources>
|
||||||
<resource>
|
<resource>
|
||||||
@ -92,29 +82,6 @@
|
|||||||
<forkMode>never</forkMode>
|
<forkMode>never</forkMode>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-clean-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<filesets>
|
|
||||||
<fileset>
|
|
||||||
<directory>${project.basedir}/src/main/resources/plugin_lessons</directory>
|
|
||||||
<includes>
|
|
||||||
<include>**/*.jar</include>
|
|
||||||
<include>**/*.pom</include>
|
|
||||||
</includes>
|
|
||||||
</fileset>
|
|
||||||
<fileset>
|
|
||||||
<directory>${user.home}/.webgoat/</directory>
|
|
||||||
<includes>
|
|
||||||
<include>**/*.jar</include>
|
|
||||||
<include>**/org/**</include>
|
|
||||||
<include>**/plugin/**</include>
|
|
||||||
</includes>
|
|
||||||
</fileset>
|
|
||||||
|
|
||||||
</filesets>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
@ -135,14 +102,6 @@
|
|||||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
@ -150,10 +109,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-cache</artifactId>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.asciidoctor</groupId>
|
<groupId>org.asciidoctor</groupId>
|
||||||
@ -162,31 +117,26 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-lang3</artifactId>
|
<artifactId>commons-lang3</artifactId>
|
||||||
<version>${commons-lang3.version}</version>
|
<version>${commons-lang3.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>${guava.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.gatling.highcharts</groupId>
|
<groupId>io.gatling.highcharts</groupId>
|
||||||
<artifactId>gatling-charts-highcharts</artifactId>
|
<artifactId>gatling-charts-highcharts</artifactId>
|
||||||
<version>${gatling.version}</version>
|
<version>${gatling.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>javax.servlet</groupId>
|
|
||||||
<artifactId>jstl</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-security</artifactId>
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
@ -205,11 +155,6 @@
|
|||||||
<artifactId>activation</artifactId>
|
<artifactId>activation</artifactId>
|
||||||
<version>${activation.version}</version>
|
<version>${activation.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
<version>${h2.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hsqldb</groupId>
|
<groupId>org.hsqldb</groupId>
|
||||||
<artifactId>hsqldb</artifactId>
|
<artifactId>hsqldb</artifactId>
|
||||||
@ -224,19 +169,7 @@
|
|||||||
<groupId>org.scala-lang</groupId>
|
<groupId>org.scala-lang</groupId>
|
||||||
<artifactId>scala-compiler</artifactId>
|
<artifactId>scala-compiler</artifactId>
|
||||||
<version>${scala.version}</version>
|
<version>${scala.version}</version>
|
||||||
</dependency>
|
<scope>test</scope>
|
||||||
|
|
||||||
<!-- Apache Commons Upload -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-fileupload</groupId>
|
|
||||||
<artifactId>commons-fileupload</artifactId>
|
|
||||||
<version>${commons-fileupload.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.guava</groupId>
|
|
||||||
<artifactId>guava</artifactId>
|
|
||||||
<version>${guava.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
@ -259,12 +192,6 @@
|
|||||||
<version>${junit.version}</version>
|
<version>${junit.version}</version>
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.fakemongo</groupId>
|
|
||||||
<artifactId>fongo</artifactId>
|
|
||||||
<version>2.1.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<!-- ************* END: Dependencies for Unit and Integration Testing ************** -->
|
<!-- ************* END: Dependencies for Unit and Integration Testing ************** -->
|
||||||
<!-- ************* END: <dependencies> ************** -->
|
<!-- ************* END: <dependencies> ************** -->
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -32,7 +32,11 @@ package org.owasp.webgoat;
|
|||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.asciidoctor.Asciidoctor;
|
import org.asciidoctor.Asciidoctor;
|
||||||
|
import org.asciidoctor.extension.JavaExtensionRegistry;
|
||||||
|
import org.owasp.webgoat.asciidoc.WebGoatVersionMacro;
|
||||||
|
import org.owasp.webgoat.asciidoc.WebWolfMacro;
|
||||||
import org.owasp.webgoat.i18n.Language;
|
import org.owasp.webgoat.i18n.Language;
|
||||||
import org.thymeleaf.TemplateProcessingParameters;
|
import org.thymeleaf.TemplateProcessingParameters;
|
||||||
import org.thymeleaf.resourceresolver.IResourceResolver;
|
import org.thymeleaf.resourceresolver.IResourceResolver;
|
||||||
@ -41,6 +45,7 @@ import org.thymeleaf.templateresolver.TemplateResolver;
|
|||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.CharEncoding.UTF_8;
|
||||||
import static org.asciidoctor.Asciidoctor.Factory.create;
|
import static org.asciidoctor.Asciidoctor.Factory.create;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,6 +55,7 @@ import static org.asciidoctor.Asciidoctor.Factory.create;
|
|||||||
* <div th:replace="doc:AccessControlMatrix_plan.adoc"></div>
|
* <div th:replace="doc:AccessControlMatrix_plan.adoc"></div>
|
||||||
* </code>
|
* </code>
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class AsciiDoctorTemplateResolver extends TemplateResolver {
|
public class AsciiDoctorTemplateResolver extends TemplateResolver {
|
||||||
|
|
||||||
private static final Asciidoctor asciidoctor = create();
|
private static final Asciidoctor asciidoctor = create();
|
||||||
@ -73,11 +79,19 @@ public class AsciiDoctorTemplateResolver extends TemplateResolver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) {
|
public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) {
|
||||||
InputStream is = readInputStreamOrFallbackToEnglish(resourceName, language);
|
try (InputStream is = readInputStreamOrFallbackToEnglish(resourceName, language)) {
|
||||||
try {
|
if (is == null) {
|
||||||
|
log.warn("Resource name: {} not found, did you add the adoc file?", resourceName);
|
||||||
|
return new ByteArrayInputStream(new byte[0]);
|
||||||
|
} else {
|
||||||
StringWriter writer = new StringWriter();
|
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());
|
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) {
|
} catch (IOException e) {
|
||||||
//no html yet
|
//no html yet
|
||||||
return new ByteArrayInputStream(new byte[0]);
|
return new ByteArrayInputStream(new byte[0]);
|
||||||
|
@ -23,11 +23,5 @@ public class CleanupLocalProgressFiles {
|
|||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void clean() {
|
public void clean() {
|
||||||
File dir = new File(webgoatHome);
|
|
||||||
//do it safe, check whether the subdir mongodb is available as subdirectory
|
|
||||||
File[] mongoDir = dir.listFiles(f -> f.isDirectory() && f.getName().contains("mongodb"));
|
|
||||||
if (mongoDir != null && mongoDir.length == 1) {
|
|
||||||
FileSystemUtils.deleteRecursively(dir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,7 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
|||||||
@Bean
|
@Bean
|
||||||
public PluginMessages pluginMessages(Messages messages, Language language) {
|
public PluginMessages pluginMessages(Messages messages, Language language) {
|
||||||
PluginMessages pluginMessages = new PluginMessages(messages, language);
|
PluginMessages pluginMessages = new PluginMessages(messages, language);
|
||||||
|
pluginMessages.setDefaultEncoding("UTF-8");
|
||||||
pluginMessages.setBasenames("i18n/WebGoatLabels");
|
pluginMessages.setBasenames("i18n/WebGoatLabels");
|
||||||
return pluginMessages;
|
return pluginMessages;
|
||||||
}
|
}
|
||||||
@ -142,6 +143,7 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
|||||||
@Bean
|
@Bean
|
||||||
public Messages messageSource(Language language) {
|
public Messages messageSource(Language language) {
|
||||||
Messages messages = new Messages(language);
|
Messages messages = new Messages(language);
|
||||||
|
messages.setDefaultEncoding("UTF-8");
|
||||||
messages.setBasename("classpath:i18n/messages");
|
messages.setBasename("classpath:i18n/messages");
|
||||||
return 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?
|
//// TODO: 11/13/2016 events better fit?
|
||||||
protected AttackResult trackProgress(AttackResult attackResult) {
|
protected AttackResult trackProgress(AttackResult attackResult) {
|
||||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||||
if (userTracker == null) {
|
if (userTracker == null) {
|
||||||
userTracker = new UserTracker(webSession.getUserName());
|
userTracker = new UserTracker(webSession.getUserName());
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package org.owasp.webgoat.lessons;
|
package org.owasp.webgoat.lessons;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,16 +35,30 @@ import java.util.List;
|
|||||||
* @version $Id: $Id
|
* @version $Id: $Id
|
||||||
* @since November 25, 2016
|
* @since November 25, 2016
|
||||||
*/
|
*/
|
||||||
@AllArgsConstructor
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
@Getter
|
@Getter
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
|
@Entity
|
||||||
public class Assignment {
|
public class Assignment {
|
||||||
@NonNull
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
private String name;
|
private String name;
|
||||||
@NonNull
|
|
||||||
private String path;
|
private String path;
|
||||||
|
@Transient
|
||||||
private List<String> hints;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ public class LessonMenuService {
|
|||||||
List<LessonMenuItem> showLeftNav() {
|
List<LessonMenuItem> showLeftNav() {
|
||||||
List<LessonMenuItem> menu = new ArrayList<>();
|
List<LessonMenuItem> menu = new ArrayList<>();
|
||||||
List<Category> categories = course.getCategories();
|
List<Category> categories = course.getCategories();
|
||||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||||
|
|
||||||
for (Category category : categories) {
|
for (Category category : categories) {
|
||||||
LessonMenuItem categoryItem = new LessonMenuItem();
|
LessonMenuItem categoryItem = new LessonMenuItem();
|
||||||
|
@ -40,9 +40,10 @@ public class LessonProgressService {
|
|||||||
@RequestMapping(value = "/service/lessonprogress.mvc", produces = "application/json")
|
@RequestMapping(value = "/service/lessonprogress.mvc", produces = "application/json")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Map getLessonInfo() {
|
public Map getLessonInfo() {
|
||||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
|
||||||
LessonTracker lessonTracker = userTracker.getLessonTracker(webSession.getCurrentLesson());
|
|
||||||
Map json = Maps.newHashMap();
|
Map json = Maps.newHashMap();
|
||||||
|
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||||
|
if (webSession.getCurrentLesson() != null) {
|
||||||
|
LessonTracker lessonTracker = userTracker.getLessonTracker(webSession.getCurrentLesson());
|
||||||
String successMessage = "";
|
String successMessage = "";
|
||||||
boolean lessonCompleted = false;
|
boolean lessonCompleted = false;
|
||||||
if (lessonTracker != null) {
|
if (lessonTracker != null) {
|
||||||
@ -51,6 +52,7 @@ public class LessonProgressService {
|
|||||||
}
|
}
|
||||||
json.put("lessonCompleted", lessonCompleted);
|
json.put("lessonCompleted", lessonCompleted);
|
||||||
json.put("successMessage", successMessage);
|
json.put("successMessage", successMessage);
|
||||||
|
}
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +65,7 @@ public class LessonProgressService {
|
|||||||
@RequestMapping(value = "/service/lessonoverview.mvc", produces = "application/json")
|
@RequestMapping(value = "/service/lessonoverview.mvc", produces = "application/json")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public List<LessonOverview> lessonOverview() {
|
public List<LessonOverview> lessonOverview() {
|
||||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||||
AbstractLesson currentLesson = webSession.getCurrentLesson();
|
AbstractLesson currentLesson = webSession.getCurrentLesson();
|
||||||
List<LessonOverview> result = Lists.newArrayList();
|
List<LessonOverview> result = Lists.newArrayList();
|
||||||
if ( currentLesson != null ) {
|
if ( currentLesson != null ) {
|
||||||
|
@ -32,6 +32,7 @@ import com.google.common.collect.Lists;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.owasp.webgoat.i18n.PluginMessages;
|
||||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||||
import org.owasp.webgoat.session.Course;
|
import org.owasp.webgoat.session.Course;
|
||||||
import org.owasp.webgoat.session.WebSession;
|
import org.owasp.webgoat.session.WebSession;
|
||||||
@ -57,6 +58,7 @@ public class ReportCardService {
|
|||||||
private final WebSession webSession;
|
private final WebSession webSession;
|
||||||
private final UserTrackerRepository userTrackerRepository;
|
private final UserTrackerRepository userTrackerRepository;
|
||||||
private final Course course;
|
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
|
* 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")
|
@GetMapping(path = "/service/reportcard.mvc", produces = "application/json")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public ReportCard reportCard() {
|
public ReportCard reportCard() {
|
||||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||||
List<AbstractLesson> lessons = course.getLessons();
|
List<AbstractLesson> lessons = course.getLessons();
|
||||||
ReportCard reportCard = new ReportCard();
|
ReportCard reportCard = new ReportCard();
|
||||||
reportCard.setTotalNumberOfLessons(course.getTotalOfLessons());
|
reportCard.setTotalNumberOfLessons(course.getTotalOfLessons());
|
||||||
@ -74,7 +76,7 @@ public class ReportCardService {
|
|||||||
for (AbstractLesson lesson : lessons) {
|
for (AbstractLesson lesson : lessons) {
|
||||||
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
|
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
|
||||||
LessonStatistics lessonStatistics = new LessonStatistics();
|
LessonStatistics lessonStatistics = new LessonStatistics();
|
||||||
lessonStatistics.setName(lesson.getTitle());
|
lessonStatistics.setName(pluginMessages.getMessage(lesson.getTitle()));
|
||||||
lessonStatistics.setNumberOfAttempts(lessonTracker.getNumberOfAttempts());
|
lessonStatistics.setNumberOfAttempts(lessonTracker.getNumberOfAttempts());
|
||||||
lessonStatistics.setSolved(lessonTracker.isLessonSolved());
|
lessonStatistics.setSolved(lessonTracker.isLessonSolved());
|
||||||
reportCard.lessonStatistics.add(lessonStatistics);
|
reportCard.lessonStatistics.add(lessonStatistics);
|
||||||
|
@ -59,7 +59,7 @@ public class RestartLessonService {
|
|||||||
AbstractLesson al = webSession.getCurrentLesson();
|
AbstractLesson al = webSession.getCurrentLesson();
|
||||||
log.debug("Restarting lesson: " + al);
|
log.debug("Restarting lesson: " + al);
|
||||||
|
|
||||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||||
userTracker.reset(al);
|
userTracker.reset(al);
|
||||||
userTrackerRepository.save(userTracker);
|
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.";
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,6 +7,7 @@ import lombok.Getter;
|
|||||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||||
import org.owasp.webgoat.lessons.Assignment;
|
import org.owasp.webgoat.lessons.Assignment;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -44,16 +45,23 @@ import java.util.stream.Collectors;
|
|||||||
* @version $Id: $Id
|
* @version $Id: $Id
|
||||||
* @since October 29, 2003
|
* @since October 29, 2003
|
||||||
*/
|
*/
|
||||||
|
@Entity
|
||||||
public class LessonTracker {
|
public class LessonTracker {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
@Getter
|
@Getter
|
||||||
private String lessonName;
|
private String lessonName;
|
||||||
|
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||||
private final Set<Assignment> solvedAssignments = Sets.newHashSet();
|
private final Set<Assignment> solvedAssignments = Sets.newHashSet();
|
||||||
private final List<Assignment> allAssignments = Lists.newArrayList();
|
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||||
|
private final Set<Assignment> allAssignments = Sets.newHashSet();
|
||||||
@Getter
|
@Getter
|
||||||
private int numberOfAttempts = 0;
|
private int numberOfAttempts = 0;
|
||||||
|
|
||||||
protected LessonTracker() {
|
private LessonTracker() {
|
||||||
//Mongo
|
//JPA
|
||||||
}
|
}
|
||||||
|
|
||||||
public LessonTracker(AbstractLesson lesson) {
|
public LessonTracker(AbstractLesson lesson) {
|
||||||
|
@ -38,7 +38,7 @@ public class Scoreboard {
|
|||||||
List<WebGoatUser> allUsers = userRepository.findAll();
|
List<WebGoatUser> allUsers = userRepository.findAll();
|
||||||
List<Ranking> rankings = Lists.newArrayList();
|
List<Ranking> rankings = Lists.newArrayList();
|
||||||
for (WebGoatUser user : allUsers) {
|
for (WebGoatUser user : allUsers) {
|
||||||
UserTracker userTracker = userTrackerRepository.findOne(user.getUsername());
|
UserTracker userTracker = userTrackerRepository.findByUser(user.getUsername());
|
||||||
rankings.add(new Ranking(user.getUsername(), challengesSolved(userTracker)));
|
rankings.add(new Ranking(user.getUsername(), challengesSolved(userTracker)));
|
||||||
}
|
}
|
||||||
return rankings;
|
return rankings;
|
||||||
|
@ -15,7 +15,7 @@ import javax.validation.constraints.Size;
|
|||||||
public class UserForm {
|
public class UserForm {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Size(min=6, max=10)
|
@Size(min=6, max=20)
|
||||||
private String username;
|
private String username;
|
||||||
@NotNull
|
@NotNull
|
||||||
@Size(min=6, max=10)
|
@Size(min=6, max=10)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package org.owasp.webgoat.users;
|
package org.owasp.webgoat.users;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ import java.util.List;
|
|||||||
* @author nbaars
|
* @author nbaars
|
||||||
* @since 3/19/17.
|
* @since 3/19/17.
|
||||||
*/
|
*/
|
||||||
public interface UserRepository extends MongoRepository<WebGoatUser, String> {
|
public interface UserRepository extends JpaRepository<WebGoatUser, String> {
|
||||||
|
|
||||||
WebGoatUser findByUsername(String username);
|
WebGoatUser findByUsername(String username);
|
||||||
|
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
package org.owasp.webgoat.users;
|
package org.owasp.webgoat.users;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||||
import org.owasp.webgoat.lessons.Assignment;
|
import org.owasp.webgoat.lessons.Assignment;
|
||||||
import org.springframework.data.annotation.Id;
|
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
@ -44,11 +46,18 @@ import java.util.stream.Collectors;
|
|||||||
* @since October 29, 2003
|
* @since October 29, 2003
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@Entity
|
||||||
public class UserTracker {
|
public class UserTracker {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
private final String user;
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
private List<LessonTracker> lessonTrackers = Lists.newArrayList();
|
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) {
|
public UserTracker(final String user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package org.owasp.webgoat.users;
|
package org.owasp.webgoat.users;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author nbaars
|
* @author nbaars
|
||||||
* @since 4/30/17.
|
* @since 4/30/17.
|
||||||
*/
|
*/
|
||||||
public interface UserTrackerRepository extends MongoRepository<UserTracker, String> {
|
public interface UserTrackerRepository extends JpaRepository<UserTracker, String> {
|
||||||
|
|
||||||
|
UserTracker findByUser(String user);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package org.owasp.webgoat.users;
|
package org.owasp.webgoat.users;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.springframework.data.annotation.Id;
|
|
||||||
import org.springframework.data.annotation.Transient;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.userdetails.User;
|
import org.springframework.security.core.userdetails.User;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Transient;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ import java.util.Collections;
|
|||||||
* @since 3/19/17.
|
* @since 3/19/17.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
|
@Entity
|
||||||
public class WebGoatUser implements UserDetails {
|
public class WebGoatUser implements UserDetails {
|
||||||
|
|
||||||
public static final String ROLE_USER = "WEBGOAT_USER";
|
public static final String ROLE_USER = "WEBGOAT_USER";
|
||||||
|
@ -3,6 +3,12 @@ server.error.path=/error.html
|
|||||||
server.session.timeout=600
|
server.session.timeout=600
|
||||||
server.contextPath=/WebGoat
|
server.contextPath=/WebGoat
|
||||||
server.port=8080
|
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=WARN
|
||||||
@ -16,9 +22,10 @@ security.enable-csrf=false
|
|||||||
spring.resources.cache-period=0
|
spring.resources.cache-period=0
|
||||||
spring.thymeleaf.cache=false
|
spring.thymeleaf.cache=false
|
||||||
|
|
||||||
|
webgoat.start.hsqldb=true
|
||||||
webgoat.clean=false
|
webgoat.clean=false
|
||||||
webgoat.server.directory=${user.home}/.webgoat/
|
webgoat.server.directory=${user.home}/.webgoat-${webgoat.build.version}/
|
||||||
webgoat.user.directory=${user.home}/.webgoat/
|
webgoat.user.directory=${user.home}/.webgoat-${webgoat.build.version}/
|
||||||
webgoat.build.version=@project.version@
|
webgoat.build.version=@project.version@
|
||||||
webgoat.build.number=@build.number@
|
webgoat.build.number=@build.number@
|
||||||
webgoat.email=webgoat@owasp.org
|
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.driver=org.hsqldb.jdbcDriver
|
||||||
webgoat.database.connection.string=jdbc:hsqldb:mem:{USER}
|
webgoat.database.connection.string=jdbc:hsqldb:mem:{USER}
|
||||||
webgoat.default.language=en
|
webgoat.default.language=en
|
||||||
webgoat.embedded.mongo=${WG_INTERNAL_MONGO:true}
|
|
||||||
|
|
||||||
webwolf.port=8081
|
webwolf.host=${WEBWOLF_HOST:localhost}
|
||||||
webwolf.url=http://localhost:${webwolf.port}/WebWolf
|
webwolf.port=${WEBWOLF_PORT:8081}
|
||||||
webworf.url.landingpage=http://localhost:${webwolf.port}/landing
|
webwolf.url=http://${webwolf.host}:${webwolf.port}/WebWolf
|
||||||
webworf.url.mail=http://localhost:${webwolf.port}/mail
|
webworf.url.landingpage=http://${webwolf.host}:${webwolf.port}/landing
|
||||||
|
webwolf.url.mail=http://${webwolf.host}:${webwolf.port}/mail
|
||||||
|
|
||||||
spring.jackson.serialization.indent_output=true
|
spring.jackson.serialization.indent_output=true
|
||||||
spring.jackson.serialization.write-dates-as-timestamps=false
|
spring.jackson.serialization.write-dates-as-timestamps=false
|
||||||
|
|
||||||
spring.activemq.brokerUrl=tcp://${WG_MQ_HOST:localhost}:${WG_MQ_PORT:61616}
|
|
||||||
|
|
||||||
spring.data.mongodb.host=${WG_MONGO_HOST:localhost}
|
|
||||||
spring.data.mongodb.port=${WG_MONGO_PORT:27017}
|
|
||||||
spring.data.mongodb.database=webgoat
|
|
||||||
spring.mongodb.embedded.storage.databaseDir=${webgoat.user.directory}/mongodb/
|
|
||||||
|
|
||||||
#For static file refresh ... and faster dev :D
|
#For static file refresh ... and faster dev :D
|
||||||
spring.devtools.restart.additional-paths=webgoat-container/src/main/resources/static/js,webgoat-container/src/main/resources/static/css
|
spring.devtools.restart.additional-paths=webgoat-container/src/main/resources/static/js,webgoat-container/src/main/resources/static/css
|
||||||
|
@ -1066,6 +1066,7 @@ span.show-next-page, span.show-prev-page {
|
|||||||
|
|
||||||
/* ATTACK DISPLAY */
|
/* ATTACK DISPLAY */
|
||||||
.attack-container {
|
.attack-container {
|
||||||
|
position: relative;
|
||||||
background-color: #f1f1f1;
|
background-color: #f1f1f1;
|
||||||
border: 2px solid #a66;
|
border: 2px solid #a66;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
@ -1151,3 +1152,15 @@ div.captured-flag {
|
|||||||
width: 1268px;
|
width: 1268px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webwolf-enabled {
|
||||||
|
position:absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 25px;
|
||||||
|
width: 42px;
|
||||||
|
height: 47px;
|
||||||
|
}
|
@ -73,6 +73,7 @@ define(['jquery',
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.loadLesson = function(name,pageNum) {
|
this.loadLesson = function(name,pageNum) {
|
||||||
|
|
||||||
if (this.name === name) {
|
if (this.name === name) {
|
||||||
this.listenToOnce(this.lessonHintView, 'hints:showButton', this.onShowHintsButton);
|
this.listenToOnce(this.lessonHintView, 'hints:showButton', this.onShowHintsButton);
|
||||||
this.listenTo(this.lessonHintView, 'hints:hideButton', this.onHideHintsButton);
|
this.listenTo(this.lessonHintView, 'hints:hideButton', this.onHideHintsButton);
|
||||||
@ -83,15 +84,15 @@ define(['jquery',
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pageNum && !this.name) {
|
||||||
|
//placeholder
|
||||||
|
}
|
||||||
|
|
||||||
this.helpsLoaded = {};
|
this.helpsLoaded = {};
|
||||||
if (typeof(name) === 'undefined' || name === null) {
|
if (typeof(name) === 'undefined' || name === null) {
|
||||||
//TODO: implement lesson not found or return to welcome page?
|
//TODO: implement lesson not found or return to welcome page?
|
||||||
}
|
}
|
||||||
this.lessonContent.loadData({'name':name});
|
this.lessonContent.loadData({'name':name});
|
||||||
// this.planView = {};
|
|
||||||
// this.solutionView = {};
|
|
||||||
// this.sourceView = {};
|
|
||||||
// this.lessonHintView = {};
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -124,15 +125,8 @@ define(['jquery',
|
|||||||
this.helpControlsView = null;
|
this.helpControlsView = null;
|
||||||
this.lessonContentView.model = this.lessonContent;
|
this.lessonContentView.model = this.lessonContent;
|
||||||
this.lessonContentView.render();
|
this.lessonContentView.render();
|
||||||
|
//TODO: consider moving hintView as child of lessonContentView ...
|
||||||
//this.planView = new PlanView();
|
this.createLessonHintView();
|
||||||
//this.solutionView = new SolutionView();
|
|
||||||
//this.sourceView = new SourceView();
|
|
||||||
if (this.lessonHintView) {
|
|
||||||
this.lessonHintView.stopListening();
|
|
||||||
this.lessonHintView = null;
|
|
||||||
}
|
|
||||||
this.lessonHintView = new HintView();
|
|
||||||
|
|
||||||
//TODO: instantiate model with values (not sure why was not working before)
|
//TODO: instantiate model with values (not sure why was not working before)
|
||||||
var paramModel = new ParamModel({});
|
var paramModel = new ParamModel({});
|
||||||
@ -148,40 +142,23 @@ define(['jquery',
|
|||||||
this.lessonProgressModel.completed();
|
this.lessonProgressModel.completed();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.createLessonHintView = function () {
|
||||||
|
if (this.lessonHintView) {
|
||||||
|
this.lessonHintView.stopListening();
|
||||||
|
this.lessonHintView = null;
|
||||||
|
}
|
||||||
|
this.lessonHintView = new HintView();
|
||||||
|
}
|
||||||
|
|
||||||
this.addCurHelpState = function (curHelp) {
|
this.addCurHelpState = function (curHelp) {
|
||||||
this.helpsLoaded[curHelp.helpElement] = curHelp.value;
|
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;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// 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.showHintsView = function() {
|
this.showHintsView = function() {
|
||||||
|
if (!this.lessonHintView) {
|
||||||
|
this.createLessonHintView();
|
||||||
|
}
|
||||||
|
//
|
||||||
this.lessonHintView.render();
|
this.lessonHintView.render();
|
||||||
if (this.lessonHintView.getHintsCount > 0) {
|
if (this.lessonHintView.getHintsCount > 0) {
|
||||||
this.helpControlsView.showHintsButton();
|
this.helpControlsView.showHintsButton();
|
||||||
|
@ -7,9 +7,13 @@ define(['jquery',
|
|||||||
return Backbone.Collection.extend({
|
return Backbone.Collection.extend({
|
||||||
model: MenuModel,
|
model: MenuModel,
|
||||||
url: 'service/lessonmenu.mvc',
|
url: 'service/lessonmenu.mvc',
|
||||||
|
|
||||||
initialize: function () {
|
initialize: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.fetch();
|
this.fetch();
|
||||||
|
setInterval(function () {
|
||||||
|
this.fetch()
|
||||||
|
}.bind(this), 5000);
|
||||||
},
|
},
|
||||||
|
|
||||||
onDataLoaded: function () {
|
onDataLoaded: function () {
|
||||||
|
@ -67,7 +67,7 @@ define(['jquery',
|
|||||||
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
|
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
//devs leave stuff like this in all the time
|
//devs leave stuff like this in all the time
|
||||||
console.log('phone home said ' + data);
|
console.log('phone home said ' + JSON.stringify(data));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,9 @@ define(['jquery',
|
|||||||
self.navToPage(page);
|
self.navToPage(page);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
setInterval(function () {
|
||||||
|
this.updatePagination();
|
||||||
|
}.bind(this), 5000);
|
||||||
},
|
},
|
||||||
|
|
||||||
findPage: function(assignment) {
|
findPage: function(assignment) {
|
||||||
@ -45,7 +48,6 @@ define(['jquery',
|
|||||||
this.$el.find('.attack-feedback').hide();
|
this.$el.find('.attack-feedback').hide();
|
||||||
this.$el.find('.attack-output').hide();
|
this.$el.find('.attack-output').hide();
|
||||||
this.makeFormsAjax();
|
this.makeFormsAjax();
|
||||||
//this.ajaxifyAttackHref();
|
|
||||||
$(window).scrollTop(0); //work-around til we get the scroll down sorted out
|
$(window).scrollTop(0); //work-around til we get the scroll down sorted out
|
||||||
var startPageNum = this.model.get('pageNum');
|
var startPageNum = this.model.get('pageNum');
|
||||||
this.initPagination(startPageNum);
|
this.initPagination(startPageNum);
|
||||||
@ -57,11 +59,13 @@ define(['jquery',
|
|||||||
var currentPage = (!isNaN(startPageNum) && startPageNum && startPageNum < this.$contentPages) ? startPageNum : 0;
|
var currentPage = (!isNaN(startPageNum) && startPageNum && startPageNum < this.$contentPages) ? startPageNum : 0;
|
||||||
//init views & pagination
|
//init views & pagination
|
||||||
this.showCurContentPage(currentPage);
|
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() {
|
updatePagination: function() {
|
||||||
|
if ( this.paginationControlView != undefined ) {
|
||||||
this.paginationControlView.updateCollection();
|
this.paginationControlView.updateCollection();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getCurrentPage: function () {
|
getCurrentPage: function () {
|
||||||
@ -86,6 +90,8 @@ define(['jquery',
|
|||||||
var prepareDataFunctionName = $(curForm).attr('prepareData');
|
var prepareDataFunctionName = $(curForm).attr('prepareData');
|
||||||
var callbackFunctionName = $(curForm).attr('callback');
|
var callbackFunctionName = $(curForm).attr('callback');
|
||||||
var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize();
|
var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize();
|
||||||
|
var successCallBackFunctionName = $(curForm).attr('successCallback');
|
||||||
|
var failureCallbackFunctionName = $(curForm).attr('failureCallback');
|
||||||
var callbackFunction = (typeof webgoat.customjs[callbackFunctionName] === 'function') ? webgoat.customjs[callbackFunctionName] : function() {};
|
var callbackFunction = (typeof webgoat.customjs[callbackFunctionName] === 'function') ? webgoat.customjs[callbackFunctionName] : function() {};
|
||||||
// var submitData = this.$form.serialize();
|
// var submitData = this.$form.serialize();
|
||||||
this.curForm = curForm;
|
this.curForm = curForm;
|
||||||
@ -104,19 +110,18 @@ define(['jquery',
|
|||||||
//complete: function (data) {
|
//complete: function (data) {
|
||||||
//callbackFunction(data);
|
//callbackFunction(data);
|
||||||
//}
|
//}
|
||||||
}).then(self.onSuccessResponse.bind(self), self.onErrorResponse.bind(self));
|
}).then(function(data){
|
||||||
|
self.onSuccessResponse(data, failureCallbackFunctionName, successCallBackFunctionName)}, self.onErrorResponse.bind(self));
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
onSuccessResponse: function(data) {
|
onSuccessResponse: function(data, failureCallbackFunctionName, successCallBackFunctionName) {
|
||||||
this.renderFeedback(data.feedback);
|
this.renderFeedback(data.feedback);
|
||||||
this.renderOutput(data.output || "");
|
this.renderOutput(data.output || "");
|
||||||
|
|
||||||
var successCallBackFunctionName = this.$form.attr('successCallback');
|
|
||||||
var failureCallbackFunctionName = this.$form.attr('failureCallback');
|
|
||||||
//var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize();
|
//var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize();
|
||||||
successCallbackFunction = (typeof webgoat.customjs[successCallBackFunctionName] === 'function') ? webgoat.customjs[successCallBackFunctionName] : function() {};
|
var successCallbackFunction = (typeof webgoat.customjs[successCallBackFunctionName] === 'function') ? webgoat.customjs[successCallBackFunctionName] : function() {};
|
||||||
failureCallbackFunction = (typeof webgoat.customjs[failureCallbackFunctionName] === 'function') ? webgoat.customjs[failureCallbackFunctionName] : function() {};
|
var failureCallbackFunction = (typeof webgoat.customjs[failureCallbackFunctionName] === 'function') ? webgoat.customjs[failureCallbackFunctionName] : function() {};
|
||||||
//TODO: refactor back assignmentCompleted in Java
|
//TODO: refactor back assignmentCompleted in Java
|
||||||
if (data.lessonCompleted || data.assignmentCompleted) {
|
if (data.lessonCompleted || data.assignmentCompleted) {
|
||||||
this.markAssignmentComplete();
|
this.markAssignmentComplete();
|
||||||
@ -146,22 +151,23 @@ define(['jquery',
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
ajaxifyAttackHref: function() { // rewrite any links with hrefs point to relative attack URLs
|
removeSlashesFromJSON: function(str) {
|
||||||
var self = this;
|
// slashes are leftover escapes from JSON serialization by server
|
||||||
// instruct in template to have links returned with the attack-link class
|
// for every two char sequence starting with backslash,
|
||||||
$('a.attack-link').submit(function(event){
|
// replace them in the text with second char only
|
||||||
$.get(this.action, "json").then(self.onSuccessResponse, self.onErrorResponse);
|
return str.replace(/\\(.)/g, "$1");
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
renderFeedback: function(feedback) {
|
renderFeedback: function(feedback) {
|
||||||
this.$curFeedback.html(polyglot.t(feedback) || "");
|
var s = this.removeSlashesFromJSON(feedback);
|
||||||
|
this.$curFeedback.html(polyglot.t(s) || "");
|
||||||
this.$curFeedback.show(400)
|
this.$curFeedback.show(400)
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
renderOutput: function(output) {
|
renderOutput: function(output) {
|
||||||
this.$curOutput.html(polyglot.t(output) || "");
|
var s = this.removeSlashesFromJSON(output);
|
||||||
|
this.$curOutput.html(polyglot.t(s) || "");
|
||||||
this.$curOutput.show(400)
|
this.$curOutput.show(400)
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -181,13 +187,19 @@ define(['jquery',
|
|||||||
return endpoints;
|
return endpoints;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onNavToPage: function(pageNum) {
|
||||||
|
var assignmentPaths = this.findAssigmentEndpointsOnPage(pageNum);
|
||||||
|
this.trigger('endpoints:filtered',assignmentPaths);
|
||||||
|
},
|
||||||
|
|
||||||
navToPage: function (pageNum) {
|
navToPage: function (pageNum) {
|
||||||
this.paginationControlView.setCurrentPage(pageNum);//provides validation
|
this.paginationControlView.setCurrentPage(pageNum);//provides validation
|
||||||
this.showCurContentPage(this.paginationControlView.currentPage);
|
this.showCurContentPage(this.paginationControlView.currentPage);
|
||||||
this.paginationControlView.render();
|
this.paginationControlView.render();
|
||||||
this.paginationControlView.hideShowNavButtons();
|
this.paginationControlView.hideShowNavButtons();
|
||||||
var assignmentPaths = this.findAssigmentEndpointsOnPage(pageNum);
|
this.onNavToPage(pageNum);
|
||||||
this.trigger('endpoints:filtered',assignmentPaths);
|
//var assignmentPaths = this.findAssigmentEndpointsOnPage(pageNum);
|
||||||
|
//this.trigger('endpoints:filtered',assignmentPaths);
|
||||||
},
|
},
|
||||||
|
|
||||||
/* for testing */
|
/* for testing */
|
||||||
|
@ -12,14 +12,14 @@ define(['jquery',
|
|||||||
template: PaginationTemplate,
|
template: PaginationTemplate,
|
||||||
el: '#lesson-page-controls',
|
el: '#lesson-page-controls',
|
||||||
|
|
||||||
initialize: function ($contentPages,baseLessonUrl) {
|
initialize: function ($contentPages,baseLessonUrl,initPageNum) {
|
||||||
this.$contentPages = $contentPages;
|
this.$contentPages = $contentPages;
|
||||||
this.collection = new LessonOverviewCollection();
|
this.collection = new LessonOverviewCollection();
|
||||||
this.listenTo(this.collection, 'reset', this.render);
|
this.listenTo(this.collection, 'reset', this.render);
|
||||||
this.numPages = this.$contentPages.length;
|
this.numPages = this.$contentPages.length;
|
||||||
this.baseUrl = baseLessonUrl;
|
this.baseUrl = baseLessonUrl;
|
||||||
this.collection.fetch({reset:true});
|
this.collection.fetch({reset:true});
|
||||||
this.initPagination();
|
this.initPagination(initPageNum);
|
||||||
//this.render();
|
//this.render();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -117,9 +117,9 @@ define(['jquery',
|
|||||||
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').hide();
|
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').hide();
|
||||||
},
|
},
|
||||||
|
|
||||||
initPagination: function() {
|
initPagination: function(initPageNum) {
|
||||||
//track pagination state in this view ... start at 0
|
//track pagination state in this view ... start at 0 .. unless a pageNum was provided
|
||||||
this.currentPage = 0;
|
this.currentPage = !initPageNum ? 0 : initPageNum;
|
||||||
},
|
},
|
||||||
|
|
||||||
setCurrentPage: function (pageNum) {
|
setCurrentPage: function (pageNum) {
|
||||||
|
@ -30,7 +30,7 @@ require.config({
|
|||||||
shim: {
|
shim: {
|
||||||
"jqueryui": {
|
"jqueryui": {
|
||||||
exports:"$",
|
exports:"$",
|
||||||
deps: ['jquery']
|
deps: ['libs/jquery-2.1.4.min']
|
||||||
},
|
},
|
||||||
underscore: {
|
underscore: {
|
||||||
exports: "_"
|
exports: "_"
|
||||||
|
@ -76,24 +76,25 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation" class="divider"></li>
|
<li role="presentation" class="divider"></li>
|
||||||
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#"
|
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">
|
||||||
th:text="#{version}">Version: <span
|
<span th:text="#{version}">Version:</span><span>: </span>
|
||||||
th:text="${@environment.getProperty('webgoat.build.version')}"></span></a>
|
<span th:text="${@environment.getProperty('webgoat.build.version')}"></span></a>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#"
|
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">
|
||||||
th:text="#{build}">Build:
|
<span th:text="#{build}">Build:</span><span>: </span>
|
||||||
<span th:text="${@environment.getProperty('webgoat.build.number')}"></span></a></li>
|
<span th:text="${@environment.getProperty('webgoat.build.number')}"></span></a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:inline" id="settings">
|
<div style="display:inline" id="settings">
|
||||||
<!--<button type="button" id="admin-button" class="btn btn-default right_nav_button" title="Administrator">-->
|
<!--<button type="button" id="admin-button" class="btn btn-default right_nav_button" title="Administrator">-->
|
||||||
<!--<i class="fa fa-cog"></i>-->
|
<!--<i class="fa fa-cog"></i>-->
|
||||||
<!--</button>-->
|
<!--</button>-->
|
||||||
|
<a href="#reportCard">
|
||||||
<button type="button" id="report-card-button" class="btn btn-default right_nav_button button-up"
|
<button type="button" id="report-card-button" class="btn btn-default right_nav_button button-up"
|
||||||
th:title="#{report.card}">
|
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>
|
</button>
|
||||||
|
</a>
|
||||||
<!--<button type="button" id="user-management" class="btn btn-default right_nav_button"-->
|
<!--<button type="button" id="user-management" class="btn btn-default right_nav_button"-->
|
||||||
<!--title="User management">-->
|
<!--title="User management">-->
|
||||||
<!--<i class="fa fa-users"></i>-->
|
<!--<i class="fa fa-users"></i>-->
|
||||||
|
@ -62,7 +62,7 @@ public class AssignmentEndpointTest {
|
|||||||
|
|
||||||
public void init(AssignmentEndpoint a) {
|
public void init(AssignmentEndpoint a) {
|
||||||
messages.setBasenames("classpath:/i18n/messages", "classpath:/i18n/WebGoatLabels");
|
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, "userTrackerRepository", userTrackerRepository);
|
||||||
ReflectionTestUtils.setField(a, "userSessionData", userSessionData);
|
ReflectionTestUtils.setField(a, "userSessionData", userSessionData);
|
||||||
ReflectionTestUtils.setField(a, "webSession", webSession);
|
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.getLessons(any())).thenReturn(Lists.newArrayList(l1, l2));
|
||||||
when(course.getCategories()).thenReturn(Lists.newArrayList(Category.ACCESS_CONTROL));
|
when(course.getCategories()).thenReturn(Lists.newArrayList(Category.ACCESS_CONTROL));
|
||||||
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
|
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))
|
mockMvc.perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
@ -81,7 +81,7 @@ public class LessonMenuServiceTest {
|
|||||||
when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1));
|
when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1));
|
||||||
when(course.getCategories()).thenReturn(Lists.newArrayList(Category.ACCESS_CONTROL));
|
when(course.getCategories()).thenReturn(Lists.newArrayList(Category.ACCESS_CONTROL));
|
||||||
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
|
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))
|
mockMvc.perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC))
|
||||||
|
@ -72,7 +72,7 @@ public class LessonProgressServiceTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
Assignment assignment = new Assignment("test", "test");
|
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(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
|
||||||
when(websession.getCurrentLesson()).thenReturn(lesson);
|
when(websession.getCurrentLesson()).thenReturn(lesson);
|
||||||
when(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true));
|
when(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true));
|
||||||
|
@ -6,6 +6,7 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
import org.owasp.webgoat.i18n.PluginMessages;
|
||||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||||
import org.owasp.webgoat.session.Course;
|
import org.owasp.webgoat.session.Course;
|
||||||
import org.owasp.webgoat.session.WebSession;
|
import org.owasp.webgoat.session.WebSession;
|
||||||
@ -40,10 +41,13 @@ public class ReportCardServiceTest {
|
|||||||
private UserTrackerRepository userTrackerRepository;
|
private UserTrackerRepository userTrackerRepository;
|
||||||
@Mock
|
@Mock
|
||||||
private WebSession websession;
|
private WebSession websession;
|
||||||
|
@Mock
|
||||||
|
private PluginMessages pluginMessages;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
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
|
@Test
|
||||||
@ -53,7 +57,7 @@ public class ReportCardServiceTest {
|
|||||||
when(course.getTotalOfLessons()).thenReturn(1);
|
when(course.getTotalOfLessons()).thenReturn(1);
|
||||||
when(course.getTotalOfAssignments()).thenReturn(10);
|
when(course.getTotalOfAssignments()).thenReturn(10);
|
||||||
when(course.getLessons()).thenReturn(Lists.newArrayList(lesson));
|
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);
|
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
|
||||||
mockMvc.perform(MockMvcRequestBuilders.get("/service/reportcard.mvc"))
|
mockMvc.perform(MockMvcRequestBuilders.get("/service/reportcard.mvc"))
|
||||||
.andExpect(status().isOk())
|
.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}
|
webgoat.user.directory=${java.io.tmpdir}
|
||||||
|
|
||||||
|
spring.datasource.url=jdbc:hsqldb:mem:test
|
||||||
|
spring.jpa.hibernate.ddl-auto=create-drop
|
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 [arch=amd64] 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/8u144-b01/090f390dda5b47b9b721c7dfaa008135/jdk-8u144-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_144/bin/java" 1
|
|
||||||
sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk1.8.0_144/bin/javac" 1
|
|
||||||
sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/lib/jvm/jdk1.8.0_144/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_144
|
|
||||||
|
|
||||||
echo "export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_144" >> /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>
|
<parent>
|
||||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||||
<artifactId>webgoat-lessons-parent</artifactId>
|
<artifactId>webgoat-lessons-parent</artifactId>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
</project>
|
</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.
|
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
|
=== 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>
|
<parent>
|
||||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||||
<artifactId>webgoat-lessons-parent</artifactId>
|
<artifactId>webgoat-lessons-parent</artifactId>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
</parent>
|
</parent>
|
||||||
</project>
|
</project>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||||
<artifactId>webgoat-lessons-parent</artifactId>
|
<artifactId>webgoat-lessons-parent</artifactId>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,7 +46,6 @@ public class Flag extends Endpoint {
|
|||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void initFlags() {
|
public void initFlags() {
|
||||||
IntStream.range(1, 10).forEach(i -> FLAGS.put(i, UUID.randomUUID().toString()));
|
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
|
@Override
|
||||||
|
@ -45,7 +45,7 @@ public class Assignment7 extends AssignmentEndpoint {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RestTemplate restTemplate;
|
private RestTemplate restTemplate;
|
||||||
@Value("${webworf.url.mail}")
|
@Value("${webwolf.url.mail}")
|
||||||
private String webWolfMailURL;
|
private String webWolfMailURL;
|
||||||
|
|
||||||
@GetMapping("/reset-password/{link}")
|
@GetMapping("/reset-password/{link}")
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||||
<artifactId>webgoat-lessons-parent</artifactId>
|
<artifactId>webgoat-lessons-parent</artifactId>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -56,7 +56,7 @@ public class ClientSideFiltering extends NewLesson {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return "Client side filtering";
|
return "client.side.filtering.title";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
client.side.filtering.title=Client side filtering
|
||||||
ClientSideFilteringSelectUser=Select user:
|
ClientSideFilteringSelectUser=Select user:
|
||||||
ClientSideFilteringUserID=User ID
|
ClientSideFilteringUserID=User ID
|
||||||
ClientSideFilteringFirstName=First Name
|
ClientSideFilteringFirstName=First Name
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||||
<artifactId>webgoat-lessons-parent</artifactId>
|
<artifactId>webgoat-lessons-parent</artifactId>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
</parent>
|
</parent>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
@ -60,7 +60,7 @@ public class CrossSiteScripting extends NewLesson {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return "Cross Site Scripting";
|
return "xss.title";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -64,7 +64,7 @@ public class CrossSiteScriptingLesson5a extends AssignmentEndpoint {
|
|||||||
userSessionData.setValue("xss-reflected1-complete",(Object)"false");
|
userSessionData.setValue("xss-reflected1-complete",(Object)"false");
|
||||||
StringBuffer cart = new StringBuffer();
|
StringBuffer cart = new StringBuffer();
|
||||||
cart.append("Thank you for shopping at WebGoat. <br />You're support is appreciated<hr />");
|
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( " ------------------- <br />");
|
||||||
cart.append( " $" + totalSale);
|
cart.append( " $" + totalSale);
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# XSS success, failure messages and hints
|
# 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-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-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>
|
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?
|
=== 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?
|
=== 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*
|
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).
|
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.owasp.webgoat.assignments.AssignmentEndpointTest;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
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.ResultActions;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
@ -80,13 +82,13 @@ public class StoredXssCommentsTest extends AssignmentEndpointTest {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//Ensures it is vulnerable
|
//Ensures it is vulnerable
|
||||||
// @Test
|
@Test
|
||||||
// public void isNotEncoded() throws Exception {
|
public void isNotEncoded() throws Exception {
|
||||||
// //do get to get comments after posting xss payload
|
//do get to get comments after posting xss payload
|
||||||
// ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScripting/stored-xss"));
|
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>"))));
|
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
|
//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
|
// @Test
|
||||||
|
@ -6,6 +6,6 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||||
<artifactId>webgoat-lessons-parent</artifactId>
|
<artifactId>webgoat-lessons-parent</artifactId>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
</parent>
|
</parent>
|
||||||
</project>
|
</project>
|
@ -0,0 +1,88 @@
|
|||||||
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||||
|
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||||
|
import org.owasp.webgoat.assignments.AttackResult;
|
||||||
|
import org.owasp.webgoat.session.UserSessionData;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
import javax.servlet.http.Cookie;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author nbaars
|
||||||
|
* @since 11/17/17.
|
||||||
|
*/
|
||||||
|
@AssignmentPath("/csrf/feedback")
|
||||||
|
@AssignmentHints({"csrf-feedback-hint1", "csrf-feedback-hint2", "csrf-feedback-hint3"})
|
||||||
|
public class CSRFFeedback extends AssignmentEndpoint {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserSessionData userSessionData;
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@PostMapping(value = "/message", produces = {"application/json"})
|
||||||
|
@ResponseBody
|
||||||
|
public AttackResult completed(HttpServletRequest request, @RequestBody String feedback) {
|
||||||
|
try {
|
||||||
|
objectMapper.readValue(feedback.getBytes(), Map.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return failed().feedback(ExceptionUtils.getStackTrace(e)).build();
|
||||||
|
}
|
||||||
|
boolean correctCSRF = requestContainsWebGoatCookie(request.getCookies()) && request.getContentType().equals(MediaType.TEXT_PLAIN_VALUE);
|
||||||
|
correctCSRF &= hostOrRefererDifferentHost(request);
|
||||||
|
if (correctCSRF) {
|
||||||
|
String flag = UUID.randomUUID().toString();
|
||||||
|
userSessionData.setValue("csrf-feedback", flag);
|
||||||
|
return success().feedback("csrf-feedback-success").feedbackArgs(flag).build();
|
||||||
|
}
|
||||||
|
return failed().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(produces = "application/json")
|
||||||
|
@ResponseBody
|
||||||
|
public AttackResult flag(@RequestParam("confirmFlagVal") String flag) {
|
||||||
|
if (flag.equals(userSessionData.getValue("csrf-feedback"))) {
|
||||||
|
return trackProgress(success().build());
|
||||||
|
} else {
|
||||||
|
return trackProgress(failed().build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hostOrRefererDifferentHost(HttpServletRequest request) {
|
||||||
|
String referer = request.getHeader("referer");
|
||||||
|
String host = request.getHeader("host");
|
||||||
|
return !StringUtils.contains(referer, host);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean requestContainsWebGoatCookie(Cookie[] cookies) {
|
||||||
|
if (cookies != null) {
|
||||||
|
for (Cookie c : cookies) {
|
||||||
|
if (c.getName().equals("JSESSIONID")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Solution
|
||||||
|
<form name="attack" enctype="text/plain" action="http://localhost:8080/WebGoat/csrf/feedback/message" METHOD="POST">
|
||||||
|
<input type="hidden" name='{"name": "Test", "email": "test1233@dfssdf.de", "subject": "service", "message":"dsaffd"}'>
|
||||||
|
</form>
|
||||||
|
<script>document.attack.submit();</script>
|
||||||
|
*/
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -58,6 +58,7 @@
|
|||||||
|
|
||||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
|
|
||||||
|
<div class="attack-container">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="panel post">
|
<div class="panel post">
|
||||||
<div class="post-heading">
|
<div class="post-heading">
|
||||||
@ -89,7 +90,8 @@
|
|||||||
method="POST" name="review-form"
|
method="POST" name="review-form"
|
||||||
successCallback=""
|
successCallback=""
|
||||||
action="/WebGoat/csrf/review">
|
action="/WebGoat/csrf/review">
|
||||||
<input class="form-control" id="reviewText" name="reviewText" placeholder="Add a Review" type="text"/>
|
<input class="form-control" id="reviewText" name="reviewText" placeholder="Add a Review"
|
||||||
|
type="text"/>
|
||||||
<input class="form-control" id="reviewStars" name="stars" type="text"/>
|
<input class="form-control" id="reviewStars" name="stars" type="text"/>
|
||||||
<input type="hidden" name="validateReq" value="2aa14227b9a13d0bede0388a7fba9aa9"/>
|
<input type="hidden" name="validateReq" value="2aa14227b9a13d0bede0388a7fba9aa9"/>
|
||||||
<input type="submit" name="submit" value="Submit review"/>
|
<input type="submit" name="submit" value="Submit review"/>
|
||||||
@ -108,14 +110,144 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- end comments -->
|
<!-- end comments -->
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="doc:CSRF_Frameworks.adoc"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="doc:CSRF_JSON.adoc"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="doc:CSRF_ContentType.adoc"></div>
|
||||||
|
|
||||||
|
<script th:src="@{/lesson_js/feedback.js}" language="JavaScript"></script>
|
||||||
|
<div style="container-fluid; background-color: #f1f1f1; border: 2px solid #a66;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 7px;
|
||||||
|
margin-top:7px;
|
||||||
|
padding:5px;">
|
||||||
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="well well-sm">
|
||||||
|
<form class="attack-form" accept-charset="UNKNOWN" id="csrf-feedback"
|
||||||
|
method="POST"
|
||||||
|
prepareData="feedback"
|
||||||
|
action="/WebGoat/csrf/feedback/message"
|
||||||
|
contentType="application/json">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">
|
||||||
|
Name</label>
|
||||||
|
<input type="text" class="form-control" name="name" id="name"
|
||||||
|
placeholder="Enter name"
|
||||||
|
required="required"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="email">
|
||||||
|
Email Address</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><span class="glyphicon glyphicon-envelope"></span>
|
||||||
|
</span>
|
||||||
|
<input type="email" name="email" class="form-control" id="email"
|
||||||
|
placeholder="Enter email"
|
||||||
|
required="required"/></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="subject">
|
||||||
|
Subject</label>
|
||||||
|
<select id="subject" name="subject" class="form-control" required="required">
|
||||||
|
<option value="na" selected="">Choose One:</option>
|
||||||
|
<option value="service">General Customer Service</option>
|
||||||
|
<option value="suggestions">Suggestions</option>
|
||||||
|
<option value="product">Product Support</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">
|
||||||
|
Message</label>
|
||||||
|
<textarea name="message" id="message" class="form-control" rows="9" cols="25"
|
||||||
|
required="required"
|
||||||
|
placeholder="Message"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<button class="btn btn-primary pull-right" id="btnContactUs">
|
||||||
|
Send Message
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div 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="lesson-page-wrapper">
|
||||||
<div class="adoc-content" th:replace="doc:CSRF_Impact_Defense.adoc"></div>
|
<div class="adoc-content" th:replace="doc:CSRF_Impact_Defense.adoc"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!--</div>-->
|
<!--</div>-->
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -17,3 +17,16 @@ csrf-review.success=It appears you have submitted correctly from another site. G
|
|||||||
csrf-review-hint1=Again, you will need to submit from an external domain/host to trigger this action. While CSRF can often be triggered from the same host (e.g. via persisted payload), this doesn't work that way.
|
csrf-review-hint1=Again, you will need to submit from an external domain/host to trigger this action. While CSRF can often be triggered from the same host (e.g. via persisted payload), this doesn't work that way.
|
||||||
csrf-review-hint2=Remember, you need to mimic the existing workflow/form.
|
csrf-review-hint2=Remember, you need to mimic the existing workflow/form.
|
||||||
csrf-review-hint3=This one has a weak anti-CSRF protection, but you do need to overcome (mimic) it
|
csrf-review-hint3=This one has a weak anti-CSRF protection, but you do need to overcome (mimic) it
|
||||||
|
|
||||||
|
csrf-feedback-hint1=Look at the content-type.
|
||||||
|
csrf-feedback-hint2=Try to post the same message with content-type text/plain
|
||||||
|
csrf-feedback-hint3=The json can be put into a hidden field inside
|
||||||
|
|
||||||
|
csrf-feedback-invalid-json=Invalid JSON received.
|
||||||
|
csrf-feedback-success=Congratulations you have found the correct solution, the flag is: {0}
|
||||||
|
|
||||||
|
csrf-login-hint1=First create a new account with csrf-username
|
||||||
|
csrf-login-hint2=Create a form which will log you in as this user (hint 1) and upload it to WebWolf
|
||||||
|
csrf-login-hint3=Visit this assignment again
|
||||||
|
csrf-login-success=Congratulations, now log out and login with your normal user account within WebGoat, remember the attacker knows you solved this assignment
|
||||||
|
csrf-login-failed=The solution is not correct, you are clicking the button while logged in as {0}
|
BIN
webgoat-lessons/csrf/src/main/resources/images/login-csrf.png
Normal file
BIN
webgoat-lessons/csrf/src/main/resources/images/login-csrf.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 212 KiB |
7
webgoat-lessons/csrf/src/main/resources/js/feedback.js
Normal file
7
webgoat-lessons/csrf/src/main/resources/js/feedback.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
webgoat.customjs.feedback = function() {
|
||||||
|
var data = {};
|
||||||
|
$('#csrf-feedback').find('input, textarea, select').each(function(i, field) {
|
||||||
|
data[field.name] = field.value;
|
||||||
|
});
|
||||||
|
return JSON.stringify(data);
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
== CSRF and content-type
|
||||||
|
|
||||||
|
In the previous section we saw how relying on the content-type is not a protection against
|
||||||
|
CSRF. In this section we will look into another way we can perform a CSRF attack against
|
||||||
|
a APIs which are not protected against CSRF.
|
||||||
|
|
||||||
|
In this assignment you need to achieve to POST the following JSON message to our endpoints:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
POST /csrf/feedback/message HTTP/1.1
|
||||||
|
|
||||||
|
{
|
||||||
|
"name" : "WebGoat",
|
||||||
|
"email" : "webgoat@webgoat.org",
|
||||||
|
"content" : "WebGoat is the best!!"
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
More information can be found http://pentestmonkey.net/blog/csrf-xml-post-request[here]
|
||||||
|
|
||||||
|
Remember you need to make the call from another origin (WebWolf can help here) and you need to be logged in into
|
||||||
|
WebGoat.
|
@ -0,0 +1,22 @@
|
|||||||
|
=== Automatic support from frameworks
|
||||||
|
|
||||||
|
Most frameworks now have default support for preventing CSRF. For example with Angular an interceptor reads a token
|
||||||
|
from a cookie by default XSRF-TOKEN and sets it as an HTTP header, X-XSRF-TOKEN. Since only code that runs on your domain
|
||||||
|
could read the cookie, the backend can be certain that the HTTP request came from your client application and not an attacker.
|
||||||
|
|
||||||
|
In order for this to work the backend server sets the token in a cookie. As the value of the cookie should be read
|
||||||
|
by Angular (JavaScript) this cookie should not be marked with the http-only flag. On every request towards the server
|
||||||
|
Angular will put the token in the X-XSRF-TOKEN as a HTTP header. The server can validate whether those two tokens
|
||||||
|
match and this will ensure the server the request is running on the same domain.
|
||||||
|
|
||||||
|
*Important: DEFINE A SEPARATE COOKIE, DO NOT REUSE THE SESSION COOKIE*
|
||||||
|
|
||||||
|
Remember the session cookie should always be defined with http-only flag.
|
||||||
|
|
||||||
|
Another effective defense can be to add a custom request header to each call. This will work if all the interactions
|
||||||
|
with the server are performed with JavaScript. On the server side you only need to check the presence of this header
|
||||||
|
if this header is not present deny the request.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
|||||||
|
**But I only have JSON APIs and no CORS enabled, how can those be susceptible to CSRF?**
|
||||||
|
|
||||||
|
A lot of web applications implement no protection against CSRF they are somehow protected by the fact that
|
||||||
|
they only work with `application/json` as content type. The only way to make a request with this content-type from the
|
||||||
|
browser is with a XHR request. Before the browser can make such a request a preflight request will be made towards
|
||||||
|
the server (remember the CSRF request will be cross origin). If the preflight response does not allow the cross origin
|
||||||
|
request the browser will not make the call.
|
||||||
|
|
||||||
|
To make a long answer short: this is *not* a valid protection against CSRF.
|
||||||
|
|
||||||
|
One example why this protection is not enough can be found https://bugs.chromium.org/p/chromium/issues/detail?id=490015[here].
|
||||||
|
Turns out `Navigator.sendBeacon()` was allowed to send POST request with an arbitrary content-type.
|
||||||
|
|
||||||
|
[qoute, developer.mozilla.org]
|
||||||
|
____
|
||||||
|
The navigator.sendBeacon() method can be used to asynchronously transfer a small amount of
|
||||||
|
data over HTTP to a web server. This method addresses the needs of analytics and diagnostics
|
||||||
|
code that typically attempts to send data to a web server prior to the unloading of the
|
||||||
|
document. Sending the data any sooner may result in a missed opportunity to gather data..."
|
||||||
|
____
|
||||||
|
|
||||||
|
{nbsp} +
|
||||||
|
For example:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
function postBeacon() {
|
||||||
|
var data= new Blob([JSON.stringify({"author" :"WebGoat"})], {type : 'application/json'});
|
||||||
|
navigator.sendBeacon("http://localhost:8083", data)
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
[quote, Eduardo Vela]
|
||||||
|
____
|
||||||
|
I think Content-Type restrictions are useful for websites that are accidentally safe against CSRF. They are not meant to be, but they are because they happen to only accept XML or JSON payloads.
|
||||||
|
|
||||||
|
That said, it's somewhat obvious the websites depending on this behavior should be fixed, and any reputable pentesters will point that out. The issue is whether it's the browser responsibility to act as a nanny to weak websites, or we should leave weak websites as sacrifice for great justice. Survival of the fittest.
|
||||||
|
|
||||||
|
IMHO, the answer is somewhere in between, and a good first step would be to document all these Same Origin Policy gotchas that websites might depend upon for security.
|
||||||
|
|
||||||
|
But wrt to this bug in specific, if it never got fixed, I don't think it would be the end of the world. But then again, on this day and age, maybe there's a way to launch nuclear missiles with a XML RPC interface, so maybe it would be the end of the world.
|
||||||
|
____
|
||||||
|
|
||||||
|
{nbsp} +
|
||||||
|
Both Firefox and Chrome fixed this issue, but it shows why you should implement a CSRF protection instead
|
||||||
|
of relying on the content-type of your APIs.
|
@ -0,0 +1,24 @@
|
|||||||
|
:blank: pass:[ +]
|
||||||
|
|
||||||
|
== Login CSRF attack
|
||||||
|
|
||||||
|
In a login CSRF attack, the attacker forges a login request to an honest site using the attacker’s username
|
||||||
|
and password at that site. If the forgery succeeds, the honest server responds with a `Set-Cookie` header
|
||||||
|
that instructs the browser to mutate its state by storing a session cookie, logging the user into
|
||||||
|
the honest site as the attacker. This session cookie is used to bind subsequent requests to the user’s session and hence
|
||||||
|
to the attacker’s authentication credentials. Login CSRF attacks can have serious consequences, for example
|
||||||
|
see the picture below where an attacker created an account at google.com the victim visits the malicious
|
||||||
|
website and the user is logged in as the attacker. The attacker could then later on gather information about
|
||||||
|
the activities of the user.
|
||||||
|
|
||||||
|
{blank}
|
||||||
|
|
||||||
|
image::images/login-csrf.png[caption="Figure: ", title="Login CSRF from Robust Defenses for Cross-Site Request Forgery", width="800", height="500", style="lesson-image" link="http://seclab.stanford.edu/websec/csrf/csrf.pdf"]
|
||||||
|
|
||||||
|
{blank}
|
||||||
|
For more information read the following http://seclab.stanford.edu/websec/csrf/csrf.pdf[paper]
|
||||||
|
|
||||||
|
In this assignment try to see if WebGoat is also vulnerable for a login CSRF attack. First create a user
|
||||||
|
based on your own username prefixed with csrf. So if your username is `tom` you must create
|
||||||
|
a new user called `csrf-tom`
|
||||||
|
|
@ -1,9 +1,9 @@
|
|||||||
== Post a review on someone else's behalf
|
== Post a review on someone else's behalf
|
||||||
|
|
||||||
The page below simulates a comment/review page. The difference here is that you have to inititate the submission elsewhere as you might
|
The page below simulates a comment/review page. The difference here is that you have to initiate the submission elsewhere as you might
|
||||||
with a CSRF attack and like the previous exercise. It's easier than you think. In most cases, the trickier part is
|
with a CSRF attack and like the previous exercise. It's easier than you think. In most cases, the trickier part is
|
||||||
finding somewhere that you want to execute the CSRF attack. The classic example is account/wire transfers in someone's bank account.
|
finding somewhere that you want to execute the CSRF attack. The classic example is account/wire transfers in someone's bank account.
|
||||||
|
|
||||||
But we're keepoing it simple here. In this case, you just need to trigger a review submission on behalf of the currently
|
But we're keeping it simple here. In this case, you just need to trigger a review submission on behalf of the currently
|
||||||
logged in user.
|
logged in user.
|
||||||
|
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
|
import org.hamcrest.core.StringContains;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.owasp.webgoat.plugins.LessonTest;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
|
||||||
|
import javax.servlet.http.Cookie;
|
||||||
|
|
||||||
|
import static org.hamcrest.core.Is.is;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author nbaars
|
||||||
|
* @since 11/17/17.
|
||||||
|
*/
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
public class CSRFFeedbackTest extends LessonTest {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws Exception {
|
||||||
|
CSRF csrf = new CSRF();
|
||||||
|
when(webSession.getCurrentLesson()).thenReturn(csrf);
|
||||||
|
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||||
|
when(webSession.getUserName()).thenReturn("unit-test");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void postingJsonMessageThroughWebGoatShouldWork() throws Exception {
|
||||||
|
mockMvc.perform(post("/csrf/feedback/message")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("{\"name\": \"Test\", \"email\": \"test1233@dfssdf.de\", \"subject\": \"service\", \"message\":\"dsaffd\"}"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void csrfAttack() throws Exception {
|
||||||
|
mockMvc.perform(post("/csrf/feedback/message")
|
||||||
|
.contentType(MediaType.TEXT_PLAIN)
|
||||||
|
.cookie(new Cookie("JSESSIONID", "test"))
|
||||||
|
.header("host", "localhost:8080")
|
||||||
|
.header("referer", "webgoat.org")
|
||||||
|
.content("{\"name\": \"Test\", \"email\": \"test1233@dfssdf.de\", \"subject\": \"service\", \"message\":\"dsaffd\"}"))
|
||||||
|
.andExpect(jsonPath("lessonCompleted", is(true)))
|
||||||
|
.andExpect(jsonPath("feedback", StringContains.containsString("the flag is: ")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,55 +0,0 @@
|
|||||||
##### To include lesson template in build #####
|
|
||||||
1. edit theh webgoat-server/pom.xml file and uncomment the section under ...
|
|
||||||
<!--uncommment below to run/include lesson template in WebGoat Build-->
|
|
||||||
|
|
||||||
2. Also uncomment in webgoat-lessons/pom.xml where it says ...
|
|
||||||
<!-- uncomment below to include lesson template in build, also uncomment the dependency in webgoat-server/pom.xml-->
|
|
||||||
|
|
||||||
##### To add a lesson to WebGoat #####
|
|
||||||
|
|
||||||
There are a number of moving parts and this sample lesson will help you navigate those parts. Most of your work will be done in two directories. To start though, you can copy this directory with the name of your-lesson in the webgoat-lessons directory.
|
|
||||||
|
|
||||||
0. The POM file
|
|
||||||
a. change the ...
|
|
||||||
<artifactId>webgoat-lesson-template</artifactId>
|
|
||||||
... line to give your lesson its own artifactId.That should be all you need to do there
|
|
||||||
|
|
||||||
1. The Base Class ...
|
|
||||||
In webgoat-lessons/{your-lesson}/src/main/java, refactor the LessonTemplate.java class, changing ...
|
|
||||||
a. the category in which you want your lesson to be in. You can create a new category if you want, or put in an issue to have one added
|
|
||||||
b. The 'defaultRanking' will move your lesson up or down in the categories list
|
|
||||||
c. implement a new key name pair "lesson-template.title" (the key) and update the same key/value pair (your.key=your value) in src/main/resources/i18n/WebGoatLabels.properties
|
|
||||||
d. Implement a new value for the getId method, which leads us to ...
|
|
||||||
|
|
||||||
2. The HTML content framing ...
|
|
||||||
a. Rename the provided file in src/main/resources/html using your value from the getId method in your lesson's base class (e.g. public String getId() { return "your-lesson"; } >> "your-lesson.html")
|
|
||||||
b. Modify that file following the commented instructions in there
|
|
||||||
c. In conjunction with this file you
|
|
||||||
|
|
||||||
3. Assignment Endpoints
|
|
||||||
a. In the above html file, you will see an example of an 'attack form'. You can create endpoints to handle these attacks and provide the user feedback and simulated output. See the example file here as well as other existing lessons for ways to extend these. You will extend the AssignmentEndpoint as the example will show
|
|
||||||
b. You can also create supporting (non-assignment) endpoints, that are not evaluated/graded.
|
|
||||||
c. See other lesson examples for creating unit/integration tests for your project as well
|
|
||||||
|
|
||||||
|
|
||||||
4. Getting your lesson to show up
|
|
||||||
a. modify the webgoat-lessons/pom.xml to include your project in the <modules> section
|
|
||||||
<modules>
|
|
||||||
<!-- ... -->
|
|
||||||
<module>webgoat-lesson-template</module>
|
|
||||||
<!-- ... -->
|
|
||||||
</modules>
|
|
||||||
|
|
||||||
b. modify the webgoat-server/pom.xml to add your project as a dependency in the <dependencies> section ...
|
|
||||||
<dependencies>
|
|
||||||
<!-- .... >
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
|
||||||
<artifactId>your-artfifact-id-here</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- .... >
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
|
|
||||||
5. You should be ready to run and test your project. Please create issues at https://github.com/WebGoat/WebGoat if there errors or confusion with this documentation/template
|
|
@ -1,62 +0,0 @@
|
|||||||
package org.owasp.webgoat.plugin;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
|
||||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
|
||||||
import org.owasp.webgoat.assignments.AttackResult;
|
|
||||||
import org.owasp.webgoat.session.UserSessionData;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by jason on 1/5/17.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@AssignmentPath("/lesson-template/sample-attack")
|
|
||||||
public class SampleAttack extends AssignmentEndpoint {
|
|
||||||
|
|
||||||
String secretValue = "secr37Value";
|
|
||||||
|
|
||||||
//UserSessionData is bound to session and can be used to persist data across multiple assignments
|
|
||||||
@Autowired
|
|
||||||
UserSessionData userSessionData;
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping(produces = {"application/json"})
|
|
||||||
public @ResponseBody
|
|
||||||
AttackResult completed(String param1, String param2, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
|
||||||
|
|
||||||
|
|
||||||
if (userSessionData.getValue("some-value") != null) {
|
|
||||||
// do any session updating you want here ... or not, just comment/example here
|
|
||||||
//return trackProgress(failed().feedback("lesson-template.sample-attack.failure-2").build());
|
|
||||||
}
|
|
||||||
|
|
||||||
//overly simple example for success. See other existing lesssons for ways to detect 'success' or 'failure'
|
|
||||||
if (secretValue.equals(param1)) {
|
|
||||||
return trackProgress(success()
|
|
||||||
.output("Custom Output ...if you want, for success")
|
|
||||||
.feedback("lesson-template.sample-attack.success")
|
|
||||||
.build());
|
|
||||||
//lesson-template.sample-attack.success is defined in src/main/resources/i18n/WebGoatLabels.properties
|
|
||||||
}
|
|
||||||
|
|
||||||
// else
|
|
||||||
return trackProgress(failed()
|
|
||||||
.feedback("lesson-template.sample-attack.failure-2")
|
|
||||||
.output("Custom output for this failure scenario, usually html that will get rendered directly ... yes, you can self-xss if you want")
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
<html xmlns:th="http://www.thymeleaf.org">
|
|
||||||
|
|
||||||
<div class="lesson-page-wrapper">
|
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
|
||||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
|
||||||
which go in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
|
||||||
<div class="adoc-content" th:replace="doc:lesson-template-intro.adoc"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="lesson-page-wrapper">
|
|
||||||
<!-- reuse the above lesson-page-wrapper block for each 'page' of content in your lesson -->
|
|
||||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
|
||||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
|
||||||
<div class="adoc-content" th:replace="doc:lesson-template-video.adoc"></div>
|
|
||||||
<!-- can use multiple adoc's in a page-wrapper if you want ... or not-->
|
|
||||||
<div class="adoc-content" th:replace="doc:lesson-template-attack.adoc"></div>
|
|
||||||
|
|
||||||
<!-- WebGoat will automatically style and scaffold some functionality by using the div.attack-container as below -->
|
|
||||||
<div class="attack-container">
|
|
||||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
|
||||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
|
||||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
|
||||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
|
||||||
|
|
||||||
<!-- modify the action to point to the intended endpoint and set other attributes as desired -->
|
|
||||||
<script th:src="@{/lesson_js/idor.js}" />
|
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
|
||||||
method="GET" name="form"
|
|
||||||
action="/WebGoat/lesson-template/sample-attack"
|
|
||||||
enctype="application/json;charset=UTF-8">
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>two random params</td>
|
|
||||||
<td>parameter 1:<input name="param1" value="" type="TEXT" /></td>
|
|
||||||
<td>parameter 2:<input name="param2" value="" type="TEXT" /></td>
|
|
||||||
<td>
|
|
||||||
<input
|
|
||||||
name="submit" value="Submit" type="SUBMIT"/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
|
||||||
<!-- the attack response will include a 'feedback' and that will automatically go here -->
|
|
||||||
<div class="attack-feedback"></div>
|
|
||||||
<!-- output is intended to be a simulation of what the screen would display in an attack -->
|
|
||||||
<div class="attack-output"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- repeat and mix-and-match the lesson-page-wrappers with or wihtout the attack-containers as you like ...
|
|
||||||
see other lessons for other more complex examples -->
|
|
||||||
|
|
||||||
</html>
|
|
@ -1,7 +0,0 @@
|
|||||||
lesson-template.title=Lesson Template
|
|
||||||
|
|
||||||
lesson-template.sample-attack.failure-1=Sample failure message
|
|
||||||
lesson-template.sample-attack.failure-2=Sample failure message 2
|
|
||||||
|
|
||||||
lesson-template.sample-attack.success=Sample success message
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 200 KiB |
@ -1,18 +0,0 @@
|
|||||||
// need custom js for this?
|
|
||||||
|
|
||||||
webgoat.customjs.idorViewProfile = function(data) {
|
|
||||||
webgoat.customjs.jquery('#idor-profile').html(
|
|
||||||
'name:' + data.name + '<br/>'+
|
|
||||||
'color:' + data.color + '<br/>'+
|
|
||||||
'size:' + data.size + '<br/>'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var onViewProfile = function () {
|
|
||||||
console.warn("on view profile activated")
|
|
||||||
webgoat.customjs.jquery.ajax({
|
|
||||||
method: "GET",
|
|
||||||
url: "/WebGoat/IDOR/profile",
|
|
||||||
contentType: 'application/json; charset=UTF-8'
|
|
||||||
}).then(webgoat.customjs.idorViewProfile);
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
=== Attack Explanation
|
|
||||||
|
|
||||||
Explanation of attack here ... Instructions etc.
|
|
@ -1,19 +0,0 @@
|
|||||||
|
|
||||||
== Lesson Template Intro
|
|
||||||
|
|
||||||
This is the lesson template intro.
|
|
||||||
|
|
||||||
=== Sub-heading
|
|
||||||
|
|
||||||
Check asciidoc for syntax, but more = means smaller headings. You can *bold* text and other things.
|
|
||||||
|
|
||||||
=== Structuring files
|
|
||||||
|
|
||||||
You should set up all content so that it is these *.adoc files.
|
|
||||||
|
|
||||||
=== Images
|
|
||||||
|
|
||||||
Images can be refereneced as below including setting style (recommended to use lesson-image as the style). The root is {lesson}/src/main/resources
|
|
||||||
|
|
||||||
image::images/firefox-proxy-config.png[Firefox Proxy Config,510,634,style="lesson-image"]
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
|||||||
=== More Content, Video too ...
|
|
||||||
|
|
||||||
You can structure and format the content however you like. You can even include video if you like (but may be subject to browser support). You may want to make it more pertinent to web application security than this though.
|
|
||||||
|
|
||||||
video::video/sample-video.m4v[width=480,start=5]
|
|
||||||
|
|
||||||
see http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/#videos for more detail on video syntax
|
|
Binary file not shown.
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||||
<artifactId>webgoat-lessons-parent</artifactId>
|
<artifactId>webgoat-lessons-parent</artifactId>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||||
<artifactId>webgoat-lessons-parent</artifactId>
|
<artifactId>webgoat-lessons-parent</artifactId>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -8,6 +8,7 @@ http-basics.hints.http_basic_quiz.1=Turn on Show Parameters or other features
|
|||||||
http-basics.hints.http_basic_quiz.2=Try to intercept the request with <a href='https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project' title='Link to ZAP'>OWASP ZAP</a>
|
http-basics.hints.http_basic_quiz.2=Try to intercept the request with <a href='https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project' title='Link to ZAP'>OWASP ZAP</a>
|
||||||
|
|
||||||
|
|
||||||
|
http-basics.empty=Try again, name cannot be empty.
|
||||||
http-basics.reversed=The server has reversed your name: {0}
|
http-basics.reversed=The server has reversed your name: {0}
|
||||||
|
|
||||||
http-basics.close=Try again: but this time enter a value before hitting go.
|
http-basics.close=Try again: but this time enter a value before hitting go.
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
Enter your name in the input field below and press "Go!" to submit. The server will accept the request, reverse the input and display it back to the user, illustrating the basics of handling an HTTP request.
|
Enter your name in the input field below and press "Go!" to submit. The server will accept the request, reverse the
|
||||||
|
input and display it back to the user, illustrating the basics of handling an HTTP request.
|
||||||
The user should become familiar with the features of WebGoat by manipulating the above buttons to view hints, show the HTTP request parameters, the HTTP request cookies, and the Java source code. You may also try using OWASP ZAP Attack Proxy to see the HTTP data.
|
|
||||||
|
|
||||||
== Try It!
|
== Try It!
|
||||||
|
|
||||||
Enter your name in the input field below and press "Go!" to submit. The server will accept the request, reverse the input and display it back to the user, illustrating the basics of handling an HTTP request.
|
Enter your name in the input field below and press "Go!" to submit. The server will accept the request, reverse the input
|
||||||
|
and display it back to the user, illustrating the basics of handling an HTTP request.
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||||
<artifactId>webgoat-lessons-parent</artifactId>
|
<artifactId>webgoat-lessons-parent</artifactId>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
== HTTP Proxy Overview
|
== HTTP Proxy Overview
|
||||||
|
|
||||||
Many times proxies are used as a way of accessing otherwise blocked content. A user might connect to server A, which relays content from server B
|
Many times proxies are used as a way of accessing otherwise blocked content. A user might connect to server A, which relays content from server B
|
||||||
... Because Server B is blocked wihtin the user's network. That's not the use case we will be dealing with here, but the concept is the same.
|
... Because Server B is blocked within the user's network. That's not the use case we will be dealing with here, but the concept is the same.
|
||||||
HTTP Proxies receive requests from a client and relay them. They also typically record them. They act as a man-in-the-middle (keep that in mind if you decide to
|
HTTP Proxies receive requests from a client and relay them. They also typically record them. They act as a man-in-the-middle (keep that in mind if you decide to
|
||||||
use a proxy server to connect to some other system that is otherwise blocked). We won't get into HTTP vs HTTPS just yet, but that's an important topic in
|
use a proxy server to connect to some other system that is otherwise blocked). We won't get into HTTP vs HTTPS just yet, but that's an important topic in
|
||||||
relationship to proxies.
|
relationship to proxies.
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||||
<artifactId>webgoat-lessons-parent</artifactId>
|
<artifactId>webgoat-lessons-parent</artifactId>
|
||||||
<version>8.0-SNAPSHOT</version>
|
<version>v8.0.0.M14</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -4,5 +4,5 @@ Older apps may follow different patterns, but RESTful apps (which is what's goin
|
|||||||
to perform different functions.
|
to perform different functions.
|
||||||
|
|
||||||
Use that knowledge to take the same base request, change its method, path and body (payload) to modify another user's (Buffalo Bill's) profile.
|
Use that knowledge to take the same base request, change its method, path and body (payload) to modify another user's (Buffalo Bill's) profile.
|
||||||
Change the role to something lower (since higher privilege roles and users are ususally lower numbers). Also change modify the
|
Change the role to something lower (since higher privilege roles and users are ususally lower numbers). Also change the
|
||||||
user's color to 'red'.
|
user's color to 'red'.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user