Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
f7a9995fe0 | |||
d6c4e8e454 | |||
26628a39e1 | |||
2d26a318d1 | |||
dc16e9a0fb | |||
88a321c268 | |||
8450c5a5be | |||
ba75e10efd | |||
d1e44bbc98 | |||
5a4974f3c2 | |||
4fc1d1fb22 | |||
084a105c69 | |||
7485cb8b9a | |||
c312ae989f | |||
5fde7fbf29 | |||
a32c56bfc7 | |||
6fd3eb57eb | |||
1743d017ff | |||
2b2638943b | |||
45c26d8aaf | |||
be30551850 | |||
49862f6b90 | |||
4009785bb8 | |||
d8341c86a1 | |||
055578893d | |||
b89ebd70ad | |||
7b81247dd1 | |||
3bc2e57c9c | |||
c3ec168d59 | |||
a67fbf5a5a | |||
3365c8d447 | |||
368c046779 | |||
8749137d1e | |||
786cabd251 | |||
dda8b10f55 | |||
d6ca083529 | |||
7c92d625dd | |||
4ba818533c | |||
a9b1fd66b8 |
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@ -8,6 +8,8 @@ updates:
|
|||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
|
ignore:
|
||||||
|
- dependency-name: "org.webjars:bootstrap" # First the WebWolf UI needs to be refactored due to breaking changes
|
||||||
- package-ecosystem: "docker"
|
- package-ecosystem: "docker"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
|
54
.github/workflows/branchbuild.yml
vendored
Normal file
54
.github/workflows/branchbuild.yml
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
name: "Branch build"
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "*"
|
||||||
|
- "!main"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
branch-build:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||||
|
java-version: [ 17, 21 ]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Set up JDK ${{ matrix.java-version }}
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: ${{ matrix.java-version }}
|
||||||
|
architecture: x64
|
||||||
|
- name: Cache Maven packages
|
||||||
|
uses: actions/cache@v3.3.1
|
||||||
|
with:
|
||||||
|
path: ~/.m2
|
||||||
|
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||||
|
restore-keys: ${{ runner.os }}-m2-
|
||||||
|
- name: Build with Maven
|
||||||
|
run: mvn --no-transfer-progress verify
|
||||||
|
- name: "Set up QEMU"
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
uses: docker/setup-qemu-action@v2.2.0
|
||||||
|
- name: "Set up Docker Buildx"
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
- name: "Verify Docker WebGoat build"
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
uses: docker/build-push-action@v5.1.0
|
||||||
|
with:
|
||||||
|
context: ./
|
||||||
|
file: ./Dockerfile
|
||||||
|
push: false
|
||||||
|
build-args: |
|
||||||
|
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
||||||
|
- name: "Verify Docker WebGoat desktop build"
|
||||||
|
uses: docker/build-push-action@v5.1.0
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
with:
|
||||||
|
context: ./
|
||||||
|
file: ./Dockerfile_desktop
|
||||||
|
push: false
|
||||||
|
build-args: |
|
||||||
|
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@ -39,10 +39,10 @@ jobs:
|
|||||||
uses: docker/setup-qemu-action@v2.2.0
|
uses: docker/setup-qemu-action@v2.2.0
|
||||||
- name: "Set up Docker Buildx"
|
- name: "Set up Docker Buildx"
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: "Verify Docker WebGoat build"
|
- name: "Verify Docker WebGoat build"
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
uses: docker/build-push-action@v4.1.1
|
uses: docker/build-push-action@v5.1.0
|
||||||
with:
|
with:
|
||||||
context: ./
|
context: ./
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
@ -50,7 +50,7 @@ jobs:
|
|||||||
build-args: |
|
build-args: |
|
||||||
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
||||||
- name: "Verify Docker WebGoat desktop build"
|
- name: "Verify Docker WebGoat desktop build"
|
||||||
uses: docker/build-push-action@v4.1.1
|
uses: docker/build-push-action@v5.1.0
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
with:
|
with:
|
||||||
context: ./
|
context: ./
|
||||||
|
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@ -77,16 +77,16 @@ jobs:
|
|||||||
platforms: all
|
platforms: all
|
||||||
|
|
||||||
- name: "Set up Docker Buildx"
|
- name: "Set up Docker Buildx"
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: "Login to dockerhub"
|
- name: "Login to dockerhub"
|
||||||
uses: docker/login-action@v2.2.0
|
uses: docker/login-action@v3.0.0
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: "Build and push WebGoat"
|
- name: "Build and push WebGoat"
|
||||||
uses: docker/build-push-action@v4.1.1
|
uses: docker/build-push-action@v5.1.0
|
||||||
with:
|
with:
|
||||||
context: ./
|
context: ./
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
@ -99,7 +99,7 @@ jobs:
|
|||||||
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
||||||
|
|
||||||
- name: "Build and push WebGoat desktop"
|
- name: "Build and push WebGoat desktop"
|
||||||
uses: docker/build-push-action@v4.1.1
|
uses: docker/build-push-action@v5.1.0
|
||||||
with:
|
with:
|
||||||
context: ./
|
context: ./
|
||||||
file: ./Dockerfile_desktop
|
file: ./Dockerfile_desktop
|
||||||
|
2
.github/workflows/welcome.yml
vendored
2
.github/workflows/welcome.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
|||||||
if: github.repository == 'WebGoat/WebGoat'
|
if: github.repository == 'WebGoat/WebGoat'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/first-interaction@v1.1.1
|
- uses: actions/first-interaction@v1.2.0
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
issue-message: 'Thanks for submitting your first issue, we will have a look as quickly as possible.'
|
issue-message: 'Thanks for submitting your first issue, we will have a look as quickly as possible.'
|
||||||
|
@ -8,7 +8,7 @@ and 2023.01 in the `pom.xml`.
|
|||||||
### Release notes:
|
### Release notes:
|
||||||
|
|
||||||
Update the release notes with the correct version. Use `git shortlog -s -n --since "JAN 06 2023"` for the list of
|
Update the release notes with the correct version. Use `git shortlog -s -n --since "JAN 06 2023"` for the list of
|
||||||
committers.
|
committers. In order to fetch the list of issues included use: `git log --graph --pretty='%C(auto)%d%Creset%s' v2023.4..origin/main`
|
||||||
|
|
||||||
```
|
```
|
||||||
mvn versions:set
|
mvn versions:set
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# WebGoat 8: A deliberately insecure Web Application
|
# WebGoat: A deliberately insecure Web Application
|
||||||
|
|
||||||
[](https://github.com/WebGoat/WebGoat/actions/workflows/build.yml)
|
[](https://github.com/WebGoat/WebGoat/actions/workflows/build.yml)
|
||||||
[](https://jdk.java.net/)
|
[](https://jdk.java.net/)
|
||||||
@ -71,7 +71,7 @@ docker run -p 127.0.0.1:3000:3000 webgoat/webgoat-desktop
|
|||||||
Download the latest WebGoat release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases)
|
Download the latest WebGoat release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases)
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
java -Dfile.encoding=UTF-8 -Dwebgoat.port=8080 -Dwebwolf.port=9090 -jar webgoat-2023.3.jar
|
java -Dfile.encoding=UTF-8 -Dwebgoat.port=8080 -Dwebwolf.port=9090 -jar webgoat-2023.4.jar
|
||||||
```
|
```
|
||||||
|
|
||||||
Click the link in the log to start WebGoat.
|
Click the link in the log to start WebGoat.
|
||||||
@ -134,7 +134,7 @@ For instance running as a jar on a Linux/macOS it will look like this:
|
|||||||
```Shell
|
```Shell
|
||||||
export EXCLUDE_CATEGORIES="CLIENT_SIDE,GENERAL,CHALLENGE"
|
export EXCLUDE_CATEGORIES="CLIENT_SIDE,GENERAL,CHALLENGE"
|
||||||
export EXCLUDE_LESSONS="SqlInjectionAdvanced,SqlInjectionMitigations"
|
export EXCLUDE_LESSONS="SqlInjectionAdvanced,SqlInjectionMitigations"
|
||||||
java -jar target/webgoat-2023.3-SNAPSHOT.jar
|
java -jar target/webgoat-2023.4-SNAPSHOT.jar
|
||||||
```
|
```
|
||||||
|
|
||||||
Or in a docker run it would (once this version is pushed into docker hub) look like this:
|
Or in a docker run it would (once this version is pushed into docker hub) look like this:
|
||||||
|
@ -1,5 +1,40 @@
|
|||||||
# WebGoat release notes
|
# WebGoat release notes
|
||||||
|
|
||||||
|
## Version 2023.5
|
||||||
|
|
||||||
|
### New functionality
|
||||||
|
|
||||||
|
- Implement JWT jku example (#1552)
|
||||||
|
- Java 21 initial support (#1622)
|
||||||
|
- improve MFAC lesson hint texts for a better user experience (#1424)
|
||||||
|
- upgrade to Spring Boot version 3 (#1477)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
- typo in WebGoad.txt (#1667)
|
||||||
|
- search box moved and jwt encode/decode with little delay (#1664)
|
||||||
|
- skip validation for JWT (#1663)
|
||||||
|
- fixed issue in JWT test tool and added robot test (#1658)
|
||||||
|
- Password reset link test condition more strict and move all WebWolf links to /WebWolf (#1645)
|
||||||
|
- fix servers id (#1619)
|
||||||
|
- potential NPE in the stored XSS assignment
|
||||||
|
- crypto basics broken links
|
||||||
|
- fixes the default change in trailing slash matching and address the affected assignments
|
||||||
|
- hint that was breaking the template, causing hints from different assignments to mix (#1424)
|
||||||
|
- HijackSession lesson template deprecated Tymeleaf attribute
|
||||||
|
- Fix NPE in IDOR lesson
|
||||||
|
- Add new assignment IT tests
|
||||||
|
- XSS mitigation
|
||||||
|
- Stored Cross-Site Scripting Lesson
|
||||||
|
- Add Assignment7 Tests
|
||||||
|
- Fix IDOR lesson
|
||||||
|
- remove steps from release script (#1509)
|
||||||
|
- robotframework fails due to updated dependencies (#1508)
|
||||||
|
- fix Java image inside Docker file The image now downloads the correct Java version based on the architecture.
|
||||||
|
- Fix typo of HijackSession_content0.adoc
|
||||||
|
- Restrict SSRF Regexes
|
||||||
|
- update challenge code - Flags are now wired through a Spring config - Introduced Flag class - Removed Flags from the FlagController
|
||||||
|
|
||||||
## Version 2023.4
|
## Version 2023.4
|
||||||
|
|
||||||
### New functionality
|
### New functionality
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
With this image you have WebGoat and ZAP and a browser available to you in a browser running on Ubuntu.
|
With this image you have WebGoat and ZAP and a browser available to you in a browser running on Ubuntu.
|
||||||
You can start WebGoat and ZAP by opening a terminal and type:
|
You can start WebGoat and ZAP by opening a terminal and type:
|
||||||
|
|
||||||
./start-webgoat.sh
|
./start_webgoat.sh
|
||||||
./start_zap.sh
|
./start_zap.sh
|
||||||
|
|
||||||
Happy hacking,
|
Happy hacking,
|
||||||
|
69
pom.xml
69
pom.xml
@ -5,12 +5,12 @@
|
|||||||
<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>3.1.0</version>
|
<version>3.1.5</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>org.owasp.webgoat</groupId>
|
<groupId>org.owasp.webgoat</groupId>
|
||||||
<artifactId>webgoat</artifactId>
|
<artifactId>webgoat</artifactId>
|
||||||
<version>2023.5-SNAPSHOT</version>
|
<version>2023.5</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>WebGoat</name>
|
<name>WebGoat</name>
|
||||||
@ -110,29 +110,28 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<!-- Shared properties with plugins and version numbers across submodules-->
|
<!-- Shared properties with plugins and version numbers across submodules-->
|
||||||
<asciidoctorj.version>2.5.10</asciidoctorj.version>
|
<asciidoctorj.version>2.5.10</asciidoctorj.version>
|
||||||
<!-- Upgrading needs UI work in WebWolf -->
|
<bootstrap.version>5.3.1</bootstrap.version>
|
||||||
<bootstrap.version>3.3.7</bootstrap.version>
|
|
||||||
<cglib.version>3.3.0</cglib.version>
|
<cglib.version>3.3.0</cglib.version>
|
||||||
<!-- do not update necessary for lesson -->
|
<!-- do not update necessary for lesson -->
|
||||||
<checkstyle.version>3.3.0</checkstyle.version>
|
<checkstyle.version>3.3.1</checkstyle.version>
|
||||||
<commons-collections.version>3.2.1</commons-collections.version>
|
<commons-collections.version>3.2.1</commons-collections.version>
|
||||||
<commons-io.version>2.11.0</commons-io.version>
|
<commons-io.version>2.14.0</commons-io.version>
|
||||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||||
<commons-text.version>1.10.0</commons-text.version>
|
<commons-text.version>1.10.0</commons-text.version>
|
||||||
<guava.version>32.1.1-jre</guava.version>
|
<guava.version>32.1.3-jre</guava.version>
|
||||||
<jacoco.version>0.8.10</jacoco.version>
|
<jacoco.version>0.8.11</jacoco.version>
|
||||||
<java.version>17</java.version>
|
<java.version>17</java.version>
|
||||||
<jaxb.version>2.3.1</jaxb.version>
|
<jaxb.version>2.3.1</jaxb.version>
|
||||||
<jjwt.version>0.9.1</jjwt.version>
|
<jjwt.version>0.9.1</jjwt.version>
|
||||||
<jose4j.version>0.9.3</jose4j.version>
|
<jose4j.version>0.9.3</jose4j.version>
|
||||||
<jquery.version>3.6.4</jquery.version>
|
<jquery.version>3.7.0</jquery.version>
|
||||||
<jsoup.version>1.16.1</jsoup.version>
|
<jsoup.version>1.16.1</jsoup.version>
|
||||||
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
||||||
<maven-failsafe-plugin.version>2.22.0</maven-failsafe-plugin.version>
|
<maven-failsafe-plugin.version>2.22.0</maven-failsafe-plugin.version>
|
||||||
<maven-jar-plugin.version>3.1.2</maven-jar-plugin.version>
|
<maven-jar-plugin.version>3.1.2</maven-jar-plugin.version>
|
||||||
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version>
|
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version>
|
||||||
<maven-source-plugin.version>3.1.0</maven-source-plugin.version>
|
<maven-source-plugin.version>3.1.0</maven-source-plugin.version>
|
||||||
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>3.2.1</maven-surefire-plugin.version>
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>17</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<pmd.version>3.15.0</pmd.version>
|
<pmd.version>3.15.0</pmd.version>
|
||||||
@ -140,8 +139,11 @@
|
|||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<thymeleaf.version>3.1.1.RELEASE</thymeleaf.version>
|
<thymeleaf.version>3.1.1.RELEASE</thymeleaf.version>
|
||||||
<webdriver.version>5.3.2</webdriver.version>
|
<webdriver.version>5.3.3</webdriver.version>
|
||||||
|
<webgoat.context>/</webgoat.context>
|
||||||
<webgoat.port>8080</webgoat.port>
|
<webgoat.port>8080</webgoat.port>
|
||||||
|
<webjars-locator-core.version>0.53</webjars-locator-core.version>
|
||||||
|
<webwolf.context>/</webwolf.context>
|
||||||
<webwolf.port>9090</webwolf.port>
|
<webwolf.port>9090</webwolf.port>
|
||||||
<wiremock.version>2.27.2</wiremock.version>
|
<wiremock.version>2.27.2</wiremock.version>
|
||||||
<xml-resolver.version>1.2</xml-resolver.version>
|
<xml-resolver.version>1.2</xml-resolver.version>
|
||||||
@ -200,6 +202,17 @@
|
|||||||
<artifactId>jjwt</artifactId>
|
<artifactId>jjwt</artifactId>
|
||||||
<version>${jjwt.version}</version>
|
<version>${jjwt.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.auth0</groupId>
|
||||||
|
<artifactId>jwks-rsa</artifactId>
|
||||||
|
<version>0.22.1</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.auth0</groupId>
|
||||||
|
<artifactId>java-jwt</artifactId>
|
||||||
|
<version>4.4.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.guava</groupId>
|
<groupId>com.google.guava</groupId>
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
@ -230,6 +243,11 @@
|
|||||||
<artifactId>jquery</artifactId>
|
<artifactId>jquery</artifactId>
|
||||||
<version>${jquery.version}</version>
|
<version>${jquery.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.webjars</groupId>
|
||||||
|
<artifactId>webjars-locator-core</artifactId>
|
||||||
|
<version>${webjars-locator-core.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.tomakehurst</groupId>
|
<groupId>com.github.tomakehurst</groupId>
|
||||||
<artifactId>wiremock</artifactId>
|
<artifactId>wiremock</artifactId>
|
||||||
@ -243,12 +261,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-compress</artifactId>
|
<artifactId>commons-compress</artifactId>
|
||||||
<version>1.23.0</version>
|
<version>1.25.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jruby</groupId>
|
<groupId>org.jruby</groupId>
|
||||||
<artifactId>jruby</artifactId>
|
<artifactId>jruby</artifactId>
|
||||||
<version>9.4.2.0</version>
|
<version>9.4.3.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
@ -310,6 +328,10 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-oauth2-client</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.thymeleaf.extras</groupId>
|
<groupId>org.thymeleaf.extras</groupId>
|
||||||
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
|
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
|
||||||
@ -346,6 +368,15 @@
|
|||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt</artifactId>
|
<artifactId>jjwt</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.auth0</groupId>
|
||||||
|
<artifactId>jwks-rsa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.auth0</groupId>
|
||||||
|
<artifactId>java-jwt</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.guava</groupId>
|
<groupId>com.google.guava</groupId>
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
@ -374,6 +405,10 @@
|
|||||||
<groupId>org.webjars</groupId>
|
<groupId>org.webjars</groupId>
|
||||||
<artifactId>jquery</artifactId>
|
<artifactId>jquery</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.webjars</groupId>
|
||||||
|
<artifactId>webjars-locator-core</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.xml.bind</groupId>
|
<groupId>jakarta.xml.bind</groupId>
|
||||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||||
@ -481,7 +516,7 @@
|
|||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
<logback.configurationFile>${basedir}/src/test/resources/logback-test.xml</logback.configurationFile>
|
<logback.configurationFile>${basedir}/src/test/resources/logback-test.xml</logback.configurationFile>
|
||||||
</systemPropertyVariables>
|
</systemPropertyVariables>
|
||||||
<argLine>-Xmx512m -Dwebgoatport=${webgoat.port} -Dwebwolfport=${webwolf.port}</argLine>
|
<argLine>-Xmx512m -Dwebgoatport=${webgoat.port} -Dwebwolfport=${webwolf.port} -Dwebwolfcontext=${webwolf.context} -Dwebgoatcontext=${webgoat.context}</argLine>
|
||||||
<includes>org/owasp/webgoat/*Test</includes>
|
<includes>org/owasp/webgoat/*Test</includes>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
@ -504,6 +539,7 @@
|
|||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>${maven-surefire-plugin.version}</version>
|
<version>${maven-surefire-plugin.version}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<forkedProcessTimeoutInSeconds>600</forkedProcessTimeoutInSeconds>
|
||||||
<argLine>--add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED
|
<argLine>--add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED
|
||||||
--add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED
|
--add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED
|
||||||
--add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED
|
--add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED
|
||||||
@ -677,7 +713,9 @@
|
|||||||
<argument>-Dwebgoat.user.directory=${java.io.tmpdir}/webgoat_${webgoat.port}</argument>
|
<argument>-Dwebgoat.user.directory=${java.io.tmpdir}/webgoat_${webgoat.port}</argument>
|
||||||
<argument>-Dspring.main.banner-mode=off</argument>
|
<argument>-Dspring.main.banner-mode=off</argument>
|
||||||
<argument>-Dwebgoat.port=${webgoat.port}</argument>
|
<argument>-Dwebgoat.port=${webgoat.port}</argument>
|
||||||
|
<argument>-Dwebgoat.context=${webgoat.context}</argument>
|
||||||
<argument>-Dwebwolf.port=${webwolf.port}</argument>
|
<argument>-Dwebwolf.port=${webwolf.port}</argument>
|
||||||
|
<argument>-Dwebwolf.context=${webwolf.context}</argument>
|
||||||
<argument>--add-opens</argument>
|
<argument>--add-opens</argument>
|
||||||
<argument>java.base/java.lang=ALL-UNNAMED</argument>
|
<argument>java.base/java.lang=ALL-UNNAMED</argument>
|
||||||
<argument>--add-opens</argument>
|
<argument>--add-opens</argument>
|
||||||
@ -703,6 +741,7 @@
|
|||||||
<argument>${project.build.directory}/webgoat-${project.version}.jar</argument>
|
<argument>${project.build.directory}/webgoat-${project.version}.jar</argument>
|
||||||
</arguments>
|
</arguments>
|
||||||
<waitForInterrupt>false</waitForInterrupt>
|
<waitForInterrupt>false</waitForInterrupt>
|
||||||
|
<waitAfterLaunch>120</waitAfterLaunch>
|
||||||
<healthcheckUrl>http://localhost:${webgoat.port}/WebGoat/actuator/health</healthcheckUrl>
|
<healthcheckUrl>http://localhost:${webgoat.port}/WebGoat/actuator/health</healthcheckUrl>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
@ -728,7 +767,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-maven</artifactId>
|
<artifactId>dependency-check-maven</artifactId>
|
||||||
<version>6.5.1</version>
|
<version>8.4.3</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<failBuildOnCVSS>7</failBuildOnCVSS>
|
<failBuildOnCVSS>7</failBuildOnCVSS>
|
||||||
<skipProvidedScope>false</skipProvidedScope>
|
<skipProvidedScope>false</skipProvidedScope>
|
||||||
|
@ -12,8 +12,10 @@ Then see security settings and allow the file to run
|
|||||||
pip3 install virtualenv --user
|
pip3 install virtualenv --user
|
||||||
python3 -m virtualenv .venv
|
python3 -m virtualenv .venv
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
pip install robotframework
|
pip install --upgrade robotframework
|
||||||
pip install robotframework-SeleniumLibrary
|
pip install --upgrade robotframework-SeleniumLibrary
|
||||||
pip install webdriver-manager
|
pip install --upgrade webdriver-manager
|
||||||
|
brew upgrade
|
||||||
robot --variable HEADLESS:"0" --variable ENDPOINT:"http://127.0.0.1:8080/WebGoat" goat.robot
|
robot --variable HEADLESS:"0" --variable ENDPOINT:"http://127.0.0.1:8080/WebGoat" goat.robot
|
||||||
|
|
||||||
|
Make sure that the Chrome version, the webdriver version and all related components are up-to-date and compatible!
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
Documentation Setup WebGoat Robotframework tests
|
Documentation Setup WebGoat Robotframework tests
|
||||||
Library SeleniumLibrary timeout=100 run_on_failure=Capture Page Screenshot
|
Library SeleniumLibrary timeout=100 run_on_failure=Capture Page Screenshot
|
||||||
Library String
|
Library String
|
||||||
|
Library OperatingSystem
|
||||||
|
|
||||||
Suite Setup Initial_Page ${ENDPOINT} ${BROWSER}
|
Suite Setup Initial_Page ${ENDPOINT} ${BROWSER}
|
||||||
Suite Teardown Close_Page
|
Suite Teardown Close_Page
|
||||||
@ -11,7 +12,7 @@ ${BROWSER} chrome
|
|||||||
${SLEEP} 100
|
${SLEEP} 100
|
||||||
${DELAY} 0.25
|
${DELAY} 0.25
|
||||||
${ENDPOINT} http://127.0.0.1:8080/WebGoat
|
${ENDPOINT} http://127.0.0.1:8080/WebGoat
|
||||||
${ENDPOINT_WOLF} http://127.0.0.1:9090
|
${ENDPOINT_WOLF} http://127.0.0.1:9090/WebWolf
|
||||||
${USERNAME} robotuser
|
${USERNAME} robotuser
|
||||||
${PASSWORD} password
|
${PASSWORD} password
|
||||||
${HEADLESS} ${FALSE}
|
${HEADLESS} ${FALSE}
|
||||||
@ -22,22 +23,25 @@ Initial_Page
|
|||||||
[Arguments] ${ENDPOINT} ${BROWSER}
|
[Arguments] ${ENDPOINT} ${BROWSER}
|
||||||
Log To Console Start WebGoat UI Testing
|
Log To Console Start WebGoat UI Testing
|
||||||
IF ${HEADLESS}
|
IF ${HEADLESS}
|
||||||
Open Browser ${ENDPOINT} ${BROWSER} options=add_argument("-headless");add_argument("--start-maximized");add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webgoat
|
Open Browser ${ENDPOINT} ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'});add_argument("-headless");add_argument("--start-maximized") alias=webgoat
|
||||||
ELSE
|
ELSE
|
||||||
Open Browser ${ENDPOINT} ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webgoat
|
Open Browser ${ENDPOINT} ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webgoat
|
||||||
END
|
END
|
||||||
IF ${HEADLESS}
|
|
||||||
Open Browser ${ENDPOINT_WOLF}/WebWolf ${BROWSER} options=add_argument("-headless");add_argument("--start-maximized");add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webwolf
|
|
||||||
ELSE
|
|
||||||
Open Browser ${ENDPOINT_WOLF}/WebWolf ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webwolf
|
|
||||||
END
|
|
||||||
Switch Browser webgoat
|
Switch Browser webgoat
|
||||||
Maximize Browser Window
|
Maximize Browser Window
|
||||||
Set Window Size ${1400} ${1000}
|
Set Window Size ${1400} ${1000}
|
||||||
|
Set Window Position ${0} ${0}
|
||||||
|
Set Selenium Speed ${DELAY}
|
||||||
|
Log To Console Start WebWolf UI Testing
|
||||||
|
IF ${HEADLESS}
|
||||||
|
Open Browser ${ENDPOINT_WOLF} ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'});add_argument("-headless");add_argument("--start-maximized") alias=webwolf
|
||||||
|
ELSE
|
||||||
|
Open Browser ${ENDPOINT_WOLF} ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webwolf
|
||||||
|
END
|
||||||
Switch Browser webwolf
|
Switch Browser webwolf
|
||||||
Maximize Browser Window
|
Maximize Browser Window
|
||||||
Set Window Size ${1400} ${1000}
|
Set Window Size ${1400} ${1000}
|
||||||
Set Window Position ${400} ${200}
|
Set Window Position ${500} ${0}
|
||||||
Set Selenium Speed ${DELAY}
|
Set Selenium Speed ${DELAY}
|
||||||
|
|
||||||
Close_Page
|
Close_Page
|
||||||
@ -53,6 +57,7 @@ Close_Page
|
|||||||
*** Test Cases ***
|
*** Test Cases ***
|
||||||
|
|
||||||
Check_Initial_Page
|
Check_Initial_Page
|
||||||
|
[Tags] WebGoatTests
|
||||||
Switch Browser webgoat
|
Switch Browser webgoat
|
||||||
Page Should Contain Username
|
Page Should Contain Username
|
||||||
Click Button Sign in
|
Click Button Sign in
|
||||||
@ -60,6 +65,7 @@ Check_Initial_Page
|
|||||||
Click Link /WebGoat/registration
|
Click Link /WebGoat/registration
|
||||||
|
|
||||||
Check_Registration_Page
|
Check_Registration_Page
|
||||||
|
[Tags] WebGoatTests
|
||||||
Page Should Contain Username
|
Page Should Contain Username
|
||||||
Input Text username ${USERNAME}
|
Input Text username ${USERNAME}
|
||||||
Input Text password ${PASSWORD}
|
Input Text password ${PASSWORD}
|
||||||
@ -68,6 +74,7 @@ Check_Registration_Page
|
|||||||
Click Button Sign up
|
Click Button Sign up
|
||||||
|
|
||||||
Check_Welcome_Page
|
Check_Welcome_Page
|
||||||
|
[Tags] WebGoatTests
|
||||||
Page Should Contain WebGoat
|
Page Should Contain WebGoat
|
||||||
Go To ${ENDPOINT}/login
|
Go To ${ENDPOINT}/login
|
||||||
Page Should Contain Username
|
Page Should Contain Username
|
||||||
@ -77,6 +84,7 @@ Check_Welcome_Page
|
|||||||
Page Should Contain WebGoat
|
Page Should Contain WebGoat
|
||||||
|
|
||||||
Check_Menu_Page
|
Check_Menu_Page
|
||||||
|
[Tags] WebGoatTests
|
||||||
Click Element css=a[category='Introduction']
|
Click Element css=a[category='Introduction']
|
||||||
Click Element Introduction-WebGoat
|
Click Element Introduction-WebGoat
|
||||||
CLick Element Introduction-WebWolf
|
CLick Element Introduction-WebWolf
|
||||||
@ -93,9 +101,29 @@ Check_Menu_Page
|
|||||||
|
|
||||||
Check_WebWolf
|
Check_WebWolf
|
||||||
Switch Browser webwolf
|
Switch Browser webwolf
|
||||||
location should be ${ENDPOINT_WOLF}/WebWolf
|
location should be ${ENDPOINT_WOLF}/login
|
||||||
Go To ${ENDPOINT_WOLF}/mail
|
|
||||||
Input Text username ${USERNAME}
|
Input Text username ${USERNAME}
|
||||||
Input Text password ${PASSWORD}
|
Input Text password ${PASSWORD}
|
||||||
Click Button Sign In
|
Click Button Sign In
|
||||||
|
Go To ${ENDPOINT_WOLF}/mail
|
||||||
|
Go To ${ENDPOINT_WOLF}/requests
|
||||||
|
Go To ${ENDPOINT_WOLF}/files
|
||||||
|
|
||||||
|
Check_JWT_Page
|
||||||
|
Go To ${ENDPOINT_WOLF}/jwt
|
||||||
|
Click Element token
|
||||||
|
Wait Until Element Is Enabled token 5s
|
||||||
|
Input Text token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
|
||||||
|
Click Element secretKey
|
||||||
|
Input Text secretKey none
|
||||||
|
Sleep 2s # Pause before reading the result
|
||||||
|
${OUT_VALUE} Get Value xpath=//textarea[@id='token']
|
||||||
|
Log To Console Found token ${OUT_VALUE}
|
||||||
|
${OUT_RESULT} Evaluate "ImuPnHvLdU7ULKfbD4aJU" in """${OUT_VALUE}"""
|
||||||
|
Log To Console Found token ${OUT_RESULT}
|
||||||
|
Capture Page Screenshot
|
||||||
|
|
||||||
|
Check_Files_Page
|
||||||
|
Go To ${ENDPOINT_WOLF}/files
|
||||||
|
Choose File css:input[type="file"] ${CURDIR}/goat.robot
|
||||||
|
Click Button Upload files
|
||||||
|
@ -25,7 +25,7 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(url("/WebGoat/access-control/users-admin-fix"))
|
.get(url("access-control/users-admin-fix"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(HttpStatus.SC_FORBIDDEN);
|
.statusCode(HttpStatus.SC_FORBIDDEN);
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
|||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body(String.format(userTemplate, this.getUser(), this.getUser()))
|
.body(String.format(userTemplate, this.getUser(), this.getUser()))
|
||||||
.post(url("/WebGoat/access-control/users"))
|
.post(url("access-control/users"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(HttpStatus.SC_OK);
|
.statusCode(HttpStatus.SC_OK);
|
||||||
|
|
||||||
@ -51,15 +51,14 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(url("/WebGoat/access-control/users-admin-fix"))
|
.get(url("access-control/users-admin-fix"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.jsonPath()
|
.jsonPath()
|
||||||
.get("find { it.username == \"Jerry\" }.userHash");
|
.get("find { it.username == \"Jerry\" }.userHash");
|
||||||
|
|
||||||
checkAssignment(
|
checkAssignment(url("access-control/user-hash-fix"), Map.of("userHash", userHash), true);
|
||||||
url("/WebGoat/access-control/user-hash-fix"), Map.of("userHash", userHash), true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assignment2() {
|
private void assignment2() {
|
||||||
@ -69,18 +68,18 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(url("/WebGoat/access-control/users"))
|
.get(url("access-control/users"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.jsonPath()
|
.jsonPath()
|
||||||
.get("find { it.username == \"Jerry\" }.userHash");
|
.get("find { it.username == \"Jerry\" }.userHash");
|
||||||
|
|
||||||
checkAssignment(url("/WebGoat/access-control/user-hash"), Map.of("userHash", userHash), true);
|
checkAssignment(url("access-control/user-hash"), Map.of("userHash", userHash), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assignment1() {
|
private void assignment1() {
|
||||||
var params = Map.of("hiddenMenu1", "Users", "hiddenMenu2", "Config");
|
var params = Map.of("hiddenMenu1", "Users", "hiddenMenu2", "Config");
|
||||||
checkAssignment(url("/WebGoat/access-control/hidden-menu"), params, true);
|
checkAssignment(url("access-control/hidden-menu"), params, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,12 +64,12 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
public void init() {
|
public void init() {
|
||||||
startLesson("CSRF");
|
startLesson("CSRF");
|
||||||
webwolfFileDir = getWebWolfFileServerLocation();
|
webwolfFileDir = getWebWolfFileServerLocation();
|
||||||
uploadTrickHtml("csrf3.html", trickHTML3.replace("WEBGOATURL", url("/csrf/basic-get-flag")));
|
uploadTrickHtml("csrf3.html", trickHTML3.replace("WEBGOATURL", url("csrf/basic-get-flag")));
|
||||||
uploadTrickHtml("csrf4.html", trickHTML4.replace("WEBGOATURL", url("/csrf/review")));
|
uploadTrickHtml("csrf4.html", trickHTML4.replace("WEBGOATURL", url("csrf/review")));
|
||||||
uploadTrickHtml("csrf7.html", trickHTML7.replace("WEBGOATURL", url("/csrf/feedback/message")));
|
uploadTrickHtml("csrf7.html", trickHTML7.replace("WEBGOATURL", url("csrf/feedback/message")));
|
||||||
uploadTrickHtml(
|
uploadTrickHtml(
|
||||||
"csrf8.html",
|
"csrf8.html",
|
||||||
trickHTML8.replace("WEBGOATURL", url("/login")).replace("USERNAME", this.getUser()));
|
trickHTML8.replace("WEBGOATURL", url("login")).replace("USERNAME", this.getUser()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestFactory
|
@TestFactory
|
||||||
@ -103,7 +103,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.multiPart("file", htmlName, htmlContent.getBytes())
|
.multiPart("file", htmlName, htmlContent.getBytes())
|
||||||
.post(webWolfUrl("/WebWolf/fileupload"))
|
.post(webWolfUrl("fileupload"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -118,7 +118,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(webWolfUrl("/files/" + this.getUser() + "/" + htmlName))
|
.get(webWolfUrl("files/" + this.getUser() + "/" + htmlName))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -136,7 +136,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("Referer", webWolfUrl("/files/fake.html"))
|
.header("Referer", webWolfUrl("files/fake.html"))
|
||||||
.post(goatURL)
|
.post(goatURL)
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
@ -146,7 +146,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("confirmFlagVal", flag);
|
params.put("confirmFlagVal", flag);
|
||||||
checkAssignment(url("/WebGoat/csrf/confirm-flag-1"), params, true);
|
checkAssignment(url("csrf/confirm-flag-1"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAssignment4(String goatURL) {
|
private void checkAssignment4(String goatURL) {
|
||||||
@ -163,7 +163,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("Referer", webWolfUrl("/files/fake.html"))
|
.header("Referer", webWolfUrl("files/fake.html"))
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.post(goatURL)
|
.post(goatURL)
|
||||||
.then()
|
.then()
|
||||||
@ -184,7 +184,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("Referer", webWolfUrl("/files/fake.html"))
|
.header("Referer", webWolfUrl("files/fake.html"))
|
||||||
.contentType(ContentType.TEXT)
|
.contentType(ContentType.TEXT)
|
||||||
.body(
|
.body(
|
||||||
"{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is"
|
"{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is"
|
||||||
@ -198,7 +198,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("confirmFlagVal", flag);
|
params.put("confirmFlagVal", flag);
|
||||||
checkAssignment(url("/WebGoat/csrf/feedback"), params, true);
|
checkAssignment(url("csrf/feedback"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAssignment8(String goatURL) {
|
private void checkAssignment8(String goatURL) {
|
||||||
@ -217,7 +217,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("Referer", webWolfUrl("/files/fake.html"))
|
.header("Referer", webWolfUrl("files/fake.html"))
|
||||||
.params(params)
|
.params(params)
|
||||||
.post(goatURL)
|
.post(goatURL)
|
||||||
.then()
|
.then()
|
||||||
@ -239,7 +239,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", newCookie)
|
.cookie("JSESSIONID", newCookie)
|
||||||
.post(url("/csrf/login"))
|
.post(url("csrf/login"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -253,7 +253,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
Overview[] assignments =
|
Overview[] assignments =
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/service/lessonoverview.mvc"))
|
.get(url("service/lessonoverview.mvc"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.jsonPath()
|
.jsonPath()
|
||||||
|
@ -22,7 +22,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/WebGoat/challenge/logo"))
|
.get(url("challenge/logo"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -34,14 +34,14 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
params.put("username", "admin");
|
params.put("username", "admin");
|
||||||
params.put("password", "!!webgoat_admin_1234!!".replace("1234", pincode));
|
params.put("password", "!!webgoat_admin_1234!!".replace("1234", pincode));
|
||||||
|
|
||||||
checkAssignment(url("/WebGoat/challenge/1"), params, true);
|
checkAssignment(url("challenge/1"), params, true);
|
||||||
String result =
|
String result =
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.post(url("/WebGoat/challenge/1"))
|
.post(url("challenge/1"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -50,7 +50,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("flag", flag);
|
params.put("flag", flag);
|
||||||
checkAssignment(url("/WebGoat/challenge/flag"), params, true);
|
checkAssignment(url("challenge/flag"), params, true);
|
||||||
|
|
||||||
checkResults("/challenge/1");
|
checkResults("/challenge/1");
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/WebGoat/scoreboard-data"))
|
.get(url("scoreboard-data"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -83,7 +83,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.post(url("/WebGoat/challenge/5"))
|
.post(url("challenge/5"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -92,7 +92,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("flag", flag);
|
params.put("flag", flag);
|
||||||
checkAssignment(url("/WebGoat/challenge/flag"), params, true);
|
checkAssignment(url("challenge/flag"), params, true);
|
||||||
|
|
||||||
checkResults("/challenge/5");
|
checkResults("/challenge/5");
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/WebGoat/scoreboard-data"))
|
.get(url("scoreboard-data"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -120,7 +120,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/WebGoat/challenge/7/.git"))
|
.get(url("challenge/7/.git"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -132,7 +132,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams("email", getUser() + "@webgoat.org")
|
.formParams("email", getUser() + "@webgoat.org")
|
||||||
.post(url("/WebGoat/challenge/7"))
|
.post(url("challenge/7"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -144,7 +144,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(webWolfUrl("/mail"))
|
.get(webWolfUrl("mail"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -158,13 +158,13 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/challenge/7/reset-password/{link}"), "375afe1104f4a487a73823c50a9292a2")
|
.get(url("challenge/7/reset-password/{link}"), "375afe1104f4a487a73823c50a9292a2")
|
||||||
.then()
|
.then()
|
||||||
.statusCode(HttpStatus.ACCEPTED.value())
|
.statusCode(HttpStatus.ACCEPTED.value())
|
||||||
.extract()
|
.extract()
|
||||||
.asString();
|
.asString();
|
||||||
|
|
||||||
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
||||||
checkAssignment(url("/WebGoat/challenge/flag"), Map.of("flag", flag), true);
|
checkAssignment(url("challenge/flag"), Map.of("flag", flag), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/crypto/encoding/basic"))
|
.get(url("crypto/encoding/basic"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.asString();
|
.asString();
|
||||||
@ -64,7 +64,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("answer_user", answer_user);
|
params.put("answer_user", answer_user);
|
||||||
params.put("answer_pwd", answer_pwd);
|
params.put("answer_pwd", answer_pwd);
|
||||||
checkAssignment(url("/crypto/encoding/basic-auth"), params, true);
|
checkAssignment(url("crypto/encoding/basic-auth"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAssignment3() {
|
private void checkAssignment3() {
|
||||||
@ -72,7 +72,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("answer_pwd1", answer_1);
|
params.put("answer_pwd1", answer_1);
|
||||||
checkAssignment(url("/crypto/encoding/xor"), params, true);
|
checkAssignment(url("crypto/encoding/xor"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAssignment4() throws NoSuchAlgorithmException {
|
private void checkAssignment4() throws NoSuchAlgorithmException {
|
||||||
@ -82,7 +82,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/crypto/hashing/md5"))
|
.get(url("crypto/hashing/md5"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.asString();
|
.asString();
|
||||||
@ -92,7 +92,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/crypto/hashing/sha256"))
|
.get(url("crypto/hashing/sha256"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.asString();
|
.asString();
|
||||||
@ -112,7 +112,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("answer_pwd1", answer_1);
|
params.put("answer_pwd1", answer_1);
|
||||||
params.put("answer_pwd2", answer_2);
|
params.put("answer_pwd2", answer_2);
|
||||||
checkAssignment(url("/WebGoat/crypto/hashing"), params, true);
|
checkAssignment(url("crypto/hashing"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAssignmentSigning() throws NoSuchAlgorithmException, InvalidKeySpecException {
|
private void checkAssignmentSigning() throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||||
@ -122,7 +122,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/crypto/signing/getprivate"))
|
.get(url("crypto/signing/getprivate"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.asString();
|
.asString();
|
||||||
@ -135,7 +135,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("modulus", modulus);
|
params.put("modulus", modulus);
|
||||||
params.put("signature", signature);
|
params.put("signature", signature);
|
||||||
checkAssignment(url("/crypto/signing/verify"), params, true);
|
checkAssignment(url("crypto/signing/verify"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAssignmentDefaults() {
|
private void checkAssignmentDefaults() {
|
||||||
@ -151,6 +151,6 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("secretText", text);
|
params.put("secretText", text);
|
||||||
params.put("secretFileName", "default_secret");
|
params.put("secretFileName", "default_secret");
|
||||||
checkAssignment(url("/crypto/secure/defaults"), params, true);
|
checkAssignment(url("crypto/secure/defaults"), params, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ public class DeserializationIntegrationTest extends IntegrationTest {
|
|||||||
params.put(
|
params.put(
|
||||||
"token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5")));
|
"token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5")));
|
||||||
}
|
}
|
||||||
checkAssignment(url("/WebGoat/InsecureDeserialization/task"), params, true);
|
checkAssignment(url("InsecureDeserialization/task"), params, true);
|
||||||
|
|
||||||
checkResults("/InsecureDeserialization/");
|
checkResults("/InsecureDeserialization/");
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.put(
|
params.put(
|
||||||
"question_3_solution",
|
"question_3_solution",
|
||||||
"Solution 2: The systems security is compromised even if only one goal is harmed.");
|
"Solution 2: The systems security is compromised even if only one goal is harmed.");
|
||||||
checkAssignment(url("/WebGoat/cia/quiz"), params, true);
|
checkAssignment(url("cia/quiz"), params, true);
|
||||||
checkResults("/cia/");
|
checkResults("/cia/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("payload", solution);
|
params.put("payload", solution);
|
||||||
checkAssignment(url("/WebGoat/VulnerableComponents/attack1"), params, true);
|
checkAssignment(url("VulnerableComponents/attack1"), params, true);
|
||||||
checkResults("/VulnerableComponents/");
|
checkResults("/VulnerableComponents/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("username", "CaptainJack");
|
params.put("username", "CaptainJack");
|
||||||
params.put("password", "BlackPearl");
|
params.put("password", "BlackPearl");
|
||||||
checkAssignment(url("/WebGoat/InsecureLogin/task"), params, true);
|
checkAssignment(url("InsecureLogin/task"), params, true);
|
||||||
checkResults("/InsecureLogin/");
|
checkResults("/InsecureLogin/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("password", "ajnaeliclm^&&@kjn.");
|
params.put("password", "ajnaeliclm^&&@kjn.");
|
||||||
checkAssignment(url("/WebGoat/SecurePasswords/assignment"), params, true);
|
checkAssignment(url("SecurePasswords/assignment"), params, true);
|
||||||
checkResults("SecurePasswords/");
|
checkResults("SecurePasswords/");
|
||||||
|
|
||||||
startLesson("AuthBypass");
|
startLesson("AuthBypass");
|
||||||
@ -127,7 +127,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.put("jsEnabled", "1");
|
params.put("jsEnabled", "1");
|
||||||
params.put("verifyMethod", "SEC_QUESTIONS");
|
params.put("verifyMethod", "SEC_QUESTIONS");
|
||||||
params.put("userId", "12309746");
|
params.put("userId", "12309746");
|
||||||
checkAssignment(url("/WebGoat/auth-bypass/verify-account"), params, true);
|
checkAssignment(url("auth-bypass/verify-account"), params, true);
|
||||||
checkResults("/auth-bypass/");
|
checkResults("/auth-bypass/");
|
||||||
|
|
||||||
startLesson("HttpProxies");
|
startLesson("HttpProxies");
|
||||||
@ -138,8 +138,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("x-request-intercepted", "true")
|
.header("x-request-intercepted", "true")
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(
|
.get(url("HttpProxies/intercept-request?changeMe=Requests are tampered easily"))
|
||||||
url("/WebGoat/HttpProxies/intercept-request?changeMe=Requests are tampered easily"))
|
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -165,7 +164,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
.header("webgoat-requested-by", "dom-xss-vuln")
|
.header("webgoat-requested-by", "dom-xss-vuln")
|
||||||
.header("X-Requested-With", "XMLHttpRequest")
|
.header("X-Requested-With", "XMLHttpRequest")
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.post(url("/WebGoat/CrossSiteScripting/phone-home-xss"))
|
.post(url("CrossSiteScripting/phone-home-xss"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -174,12 +173,12 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("successMessage", secretNumber);
|
params.put("successMessage", secretNumber);
|
||||||
checkAssignment(url("/WebGoat/ChromeDevTools/dummy"), params, true);
|
checkAssignment(url("ChromeDevTools/dummy"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("number", "24");
|
params.put("number", "24");
|
||||||
params.put("network_num", "24");
|
params.put("network_num", "24");
|
||||||
checkAssignment(url("/WebGoat/ChromeDevTools/network"), params, true);
|
checkAssignment(url("ChromeDevTools/network"), params, true);
|
||||||
|
|
||||||
checkResults("/ChromeDevTools/");
|
checkResults("/ChromeDevTools/");
|
||||||
}
|
}
|
||||||
@ -194,7 +193,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.put("jsEnabled", "1");
|
params.put("jsEnabled", "1");
|
||||||
params.put("verifyMethod", "SEC_QUESTIONS");
|
params.put("verifyMethod", "SEC_QUESTIONS");
|
||||||
params.put("userId", "12309746");
|
params.put("userId", "12309746");
|
||||||
checkAssignment(url("/auth-bypass/verify-account"), params, true);
|
checkAssignment(url("auth-bypass/verify-account"), params, true);
|
||||||
checkResults("/auth-bypass/");
|
checkResults("/auth-bypass/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +204,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("param1", "secr37Value");
|
params.put("param1", "secr37Value");
|
||||||
params.put("param2", "Main");
|
params.put("param2", "Main");
|
||||||
checkAssignment(url("/lesson-template/sample-attack"), params, true);
|
checkAssignment(url("lesson-template/sample-attack"), params, true);
|
||||||
checkResults("/lesson-template/");
|
checkResults("/lesson-template/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,9 @@ import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
|||||||
|
|
||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import org.hamcrest.CoreMatchers;
|
import org.hamcrest.CoreMatchers;
|
||||||
import org.hamcrest.MatcherAssert;
|
import org.hamcrest.MatcherAssert;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
@ -19,7 +17,6 @@ import org.junit.jupiter.api.TestFactory;
|
|||||||
public class IDORIntegrationTest extends IntegrationTest {
|
public class IDORIntegrationTest extends IntegrationTest {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
@SneakyThrows
|
|
||||||
public void init() {
|
public void init() {
|
||||||
startLesson("IDOR");
|
startLesson("IDOR");
|
||||||
}
|
}
|
||||||
@ -27,56 +24,63 @@ public class IDORIntegrationTest extends IntegrationTest {
|
|||||||
@TestFactory
|
@TestFactory
|
||||||
Iterable<DynamicTest> testIDORLesson() {
|
Iterable<DynamicTest> testIDORLesson() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
dynamicTest("login", () -> loginIDOR()), dynamicTest("profile", () -> profile()));
|
dynamicTest("assignment 2 - login", this::loginIDOR),
|
||||||
|
dynamicTest("profile", this::profile));
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void shutdown() throws IOException {
|
public void shutdown() {
|
||||||
checkResults("/IDOR");
|
checkResults("/IDOR");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loginIDOR() throws IOException {
|
private void loginIDOR() {
|
||||||
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
|
||||||
params.put("username", "tom");
|
params.put("username", "tom");
|
||||||
params.put("password", "cat");
|
params.put("password", "cat");
|
||||||
|
|
||||||
checkAssignment(url("/WebGoat/IDOR/login"), params, true);
|
checkAssignment(url("IDOR/login"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void profile() {
|
private void profile() {
|
||||||
|
|
||||||
|
// View profile - assignment 3a
|
||||||
MatcherAssert.assertThat(
|
MatcherAssert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/WebGoat/IDOR/profile"))
|
.get(url("IDOR/profile"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.path("userId"),
|
.path("userId"),
|
||||||
CoreMatchers.is("2342384"));
|
CoreMatchers.is("2342384"));
|
||||||
|
|
||||||
|
// Show difference - assignment 3b
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
|
||||||
params.put("attributes", "userId,role");
|
params.put("attributes", "userId,role");
|
||||||
checkAssignment(url("/WebGoat/IDOR/diff-attributes"), params, true);
|
checkAssignment(url("IDOR/diff-attributes"), params, true);
|
||||||
|
|
||||||
|
// View profile another way - assignment 4
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("url", "WebGoat/IDOR/profile/2342384");
|
params.put("url", "WebGoat/IDOR/profile/2342384");
|
||||||
checkAssignment(url("/WebGoat/IDOR/profile/alt-path"), params, true);
|
checkAssignment(url("IDOR/profile/alt-path"), params, true);
|
||||||
|
|
||||||
|
// assignment 5a
|
||||||
MatcherAssert.assertThat(
|
MatcherAssert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/WebGoat/IDOR/profile/2342388"))
|
.get(url("IDOR/profile/2342388"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.path("lessonCompleted"),
|
.path("lessonCompleted"),
|
||||||
CoreMatchers.is(true));
|
CoreMatchers.is(true));
|
||||||
|
|
||||||
|
// assignment 5b
|
||||||
MatcherAssert.assertThat(
|
MatcherAssert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
@ -86,7 +90,7 @@ public class IDORIntegrationTest extends IntegrationTest {
|
|||||||
.body(
|
.body(
|
||||||
"{\"role\":\"1\", \"color\":\"red\", \"size\":\"large\", \"name\":\"Buffalo Bill\","
|
"{\"role\":\"1\", \"color\":\"red\", \"size\":\"large\", \"name\":\"Buffalo Bill\","
|
||||||
+ " \"userId\":\"2342388\"}")
|
+ " \"userId\":\"2342388\"}")
|
||||||
.put(url("/WebGoat/IDOR/profile/2342388"))
|
.put(url("IDOR/profile/2342388"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
|
@ -15,34 +15,39 @@ import org.springframework.http.HttpStatus;
|
|||||||
|
|
||||||
public abstract class IntegrationTest {
|
public abstract class IntegrationTest {
|
||||||
|
|
||||||
private static String webGoatPort = Objects.requireNonNull(System.getProperty("webgoatport"));
|
private static String webGoatPort =
|
||||||
|
Objects.requireNonNull(System.getProperty("webgoatport", "8080"));
|
||||||
|
private static String webGoatContext =
|
||||||
|
Objects.requireNonNull(System.getProperty("webgoatcontext", "/WebGoat/"));
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static String webWolfPort = Objects.requireNonNull(System.getProperty("webwolfport"));
|
private static String webWolfPort =
|
||||||
|
Objects.requireNonNull(System.getProperty("webwolfport", "9090"));
|
||||||
|
|
||||||
|
private static String webWolfContext =
|
||||||
|
Objects.requireNonNull(System.getProperty("webwolfcontext", "/WebWolf/"));
|
||||||
|
|
||||||
private static boolean useSSL = false;
|
private static boolean useSSL = false;
|
||||||
private static String webgoatUrl =
|
private static String webgoatUrl =
|
||||||
(useSSL ? "https:" : "http:") + "//localhost:" + webGoatPort + "/WebGoat/";
|
(useSSL ? "https:" : "http:") + "//localhost:" + webGoatPort + webGoatContext;
|
||||||
private static String webWolfUrl =
|
private static String webWolfUrl =
|
||||||
(useSSL ? "https:" : "http:") + "//localhost:" + webWolfPort + "/";
|
(useSSL ? "https:" : "http:") + "//localhost:" + webWolfPort + webWolfContext;
|
||||||
@Getter private String webGoatCookie;
|
@Getter private String webGoatCookie;
|
||||||
@Getter private String webWolfCookie;
|
@Getter private String webWolfCookie;
|
||||||
@Getter private final String user = "webgoat";
|
@Getter private final String user = "webgoat";
|
||||||
|
|
||||||
protected String url(String url) {
|
protected String url(String url) {
|
||||||
url = url.replaceFirst("/WebGoat/", "");
|
|
||||||
url = url.replaceFirst("/WebGoat", "");
|
|
||||||
url = url.startsWith("/") ? url.replaceFirst("/", "") : url;
|
|
||||||
return webgoatUrl + url;
|
return webgoatUrl + url;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String webWolfUrl(String url) {
|
protected String webWolfUrl(String url) {
|
||||||
url = url.replaceFirst("/WebWolf/", "");
|
|
||||||
url = url.replaceFirst("/WebWolf", "");
|
|
||||||
url = url.startsWith("/") ? url.replaceFirst("/", "") : url;
|
|
||||||
return webWolfUrl + url;
|
return webWolfUrl + url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String webWolfFileUrl(String fileName) {
|
||||||
|
return webWolfUrl("files") + "/" + getUser() + "/" + fileName;
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void login() {
|
public void login() {
|
||||||
String location =
|
String location =
|
||||||
@ -231,7 +236,7 @@ public abstract class IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(webWolfUrl("/file-server-location"))
|
.get(webWolfUrl("file-server-location"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -246,7 +251,7 @@ public abstract class IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/server-directory"))
|
.get(url("server-directory"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -259,7 +264,7 @@ public abstract class IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.delete(webWolfUrl("/mail"))
|
.delete(webWolfUrl("mail"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(HttpStatus.ACCEPTED.value());
|
.statusCode(HttpStatus.ACCEPTED.value());
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,10 @@ import io.restassured.RestAssured;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@ -23,6 +26,8 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.hamcrest.CoreMatchers;
|
import org.hamcrest.CoreMatchers;
|
||||||
import org.hamcrest.MatcherAssert;
|
import org.hamcrest.MatcherAssert;
|
||||||
|
import org.jose4j.jwk.JsonWebKeySet;
|
||||||
|
import org.jose4j.jwk.RsaJsonWebKey;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.owasp.webgoat.lessons.jwt.JWTSecretKeyEndpoint;
|
import org.owasp.webgoat.lessons.jwt.JWTSecretKeyEndpoint;
|
||||||
|
|
||||||
@ -40,7 +45,9 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
buyAsTom();
|
buyAsTom();
|
||||||
|
|
||||||
deleteTom();
|
deleteTomThroughKidClaim();
|
||||||
|
|
||||||
|
deleteTomThroughJkuClaim();
|
||||||
|
|
||||||
quiz();
|
quiz();
|
||||||
|
|
||||||
@ -81,7 +88,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParam("jwt-encode-user", "user")
|
.formParam("jwt-encode-user", "user")
|
||||||
.post(url("/WebGoat/JWT/decode"))
|
.post(url("JWT/decode"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -96,7 +103,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/WebGoat/JWT/secret/gettoken"))
|
.get(url("JWT/secret/gettoken"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -110,7 +117,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParam("token", generateToken(secret))
|
.formParam("token", generateToken(secret))
|
||||||
.post(url("/WebGoat/JWT/secret"))
|
.post(url("JWT/secret"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -124,7 +131,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/WebGoat/JWT/votings/login?user=Tom"))
|
.get(url("JWT/votings/login?user=Tom"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.cookie("access_token");
|
.cookie("access_token");
|
||||||
@ -157,7 +164,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.cookie("access_token", replacedToken)
|
.cookie("access_token", replacedToken)
|
||||||
.post(url("/WebGoat/JWT/votings"))
|
.post(url("JWT/votings"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -198,7 +205,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("Authorization", "Bearer " + replacedToken)
|
.header("Authorization", "Bearer " + replacedToken)
|
||||||
.post(url("/WebGoat/JWT/refresh/checkout"))
|
.post(url("JWT/refresh/checkout"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -206,8 +213,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
CoreMatchers.is(true));
|
CoreMatchers.is(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteTom() {
|
private void deleteTomThroughKidClaim() {
|
||||||
|
|
||||||
Map<String, Object> header = new HashMap();
|
Map<String, Object> header = new HashMap();
|
||||||
header.put(Header.TYPE, Header.JWT_TYPE);
|
header.put(Header.TYPE, Header.JWT_TYPE);
|
||||||
header.put(
|
header.put(
|
||||||
@ -232,7 +238,54 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.post(url("/WebGoat/JWT/final/delete?token=" + token))
|
.post(url("JWT/kid/delete?token=" + token))
|
||||||
|
.then()
|
||||||
|
.statusCode(200)
|
||||||
|
.extract()
|
||||||
|
.path("lessonCompleted"),
|
||||||
|
CoreMatchers.is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteTomThroughJkuClaim() throws NoSuchAlgorithmException {
|
||||||
|
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||||
|
keyPairGenerator.initialize(2048);
|
||||||
|
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
||||||
|
var jwks = new JsonWebKeySet(new RsaJsonWebKey((RSAPublicKey) keyPair.getPublic()));
|
||||||
|
RestAssured.given()
|
||||||
|
.when()
|
||||||
|
.relaxedHTTPSValidation()
|
||||||
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
|
.multiPart("file", "jwks.json", jwks.toJson().getBytes())
|
||||||
|
.post(webWolfUrl("fileupload"))
|
||||||
|
.then()
|
||||||
|
.extract()
|
||||||
|
.response()
|
||||||
|
.getBody()
|
||||||
|
.asString();
|
||||||
|
|
||||||
|
Map<String, Object> header = new HashMap();
|
||||||
|
header.put(Header.TYPE, Header.JWT_TYPE);
|
||||||
|
header.put(JwsHeader.JWK_SET_URL, webWolfFileUrl("jwks.json"));
|
||||||
|
String token =
|
||||||
|
Jwts.builder()
|
||||||
|
.setHeader(header)
|
||||||
|
.setIssuer("WebGoat Token Builder")
|
||||||
|
.setAudience("webgoat.org")
|
||||||
|
.setIssuedAt(Calendar.getInstance().getTime())
|
||||||
|
.setExpiration(Date.from(Instant.now().plusSeconds(60)))
|
||||||
|
.setSubject("tom@webgoat.org")
|
||||||
|
.claim("username", "Tom")
|
||||||
|
.claim("Email", "tom@webgoat.org")
|
||||||
|
.claim("Role", new String[] {"Manager", "Project Administrator"})
|
||||||
|
.signWith(SignatureAlgorithm.RS256, keyPair.getPrivate())
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
MatcherAssert.assertThat(
|
||||||
|
RestAssured.given()
|
||||||
|
.when()
|
||||||
|
.relaxedHTTPSValidation()
|
||||||
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
|
.post(url("JWT/jku/delete?token=" + token))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -245,6 +298,6 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.put("question_0_solution", "Solution 1");
|
params.put("question_0_solution", "Solution 1");
|
||||||
params.put("question_1_solution", "Solution 2");
|
params.put("question_1_solution", "Solution 2");
|
||||||
|
|
||||||
checkAssignment(url("/WebGoat/JWT/quiz"), params, true);
|
checkAssignment(url("JWT/quiz"), params, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,13 @@ import org.junit.jupiter.api.AfterEach;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.DynamicTest;
|
import org.junit.jupiter.api.DynamicTest;
|
||||||
import org.junit.jupiter.api.TestFactory;
|
import org.junit.jupiter.api.TestFactory;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
|
||||||
public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void init() {
|
public void init() {
|
||||||
startLesson("/PasswordReset");
|
startLesson("PasswordReset");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestFactory
|
@TestFactory
|
||||||
@ -85,7 +86,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(webWolfUrl("/WebWolf/mail"))
|
.get(webWolfUrl("mail"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -119,7 +120,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(webWolfUrl("/WebWolf/requests"))
|
.get(webWolfUrl("requests"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -136,7 +137,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
|||||||
private void clickForgotEmailLink(String user) {
|
private void clickForgotEmailLink(String user) {
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.header("host", String.format("%s:%s", "localhost", getWebWolfPort()))
|
.header(HttpHeaders.HOST, String.format("%s:%s", "127.0.0.1", getWebWolfPort()))
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams("email", user)
|
.formParams("email", user)
|
||||||
|
@ -55,7 +55,7 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.multiPart("uploadedFile", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
|
.multiPart("uploadedFile", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
|
||||||
.param("fullName", "../John Doe")
|
.param("fullName", "../John Doe")
|
||||||
.post(url("/WebGoat/PathTraversal/profile-upload"))
|
.post(url("PathTraversal/profile-upload"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -71,7 +71,7 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.multiPart("uploadedFileFix", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
|
.multiPart("uploadedFileFix", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
|
||||||
.param("fullNameFix", "..././John Doe")
|
.param("fullNameFix", "..././John Doe")
|
||||||
.post(url("/WebGoat/PathTraversal/profile-upload-fix"))
|
.post(url("PathTraversal/profile-upload-fix"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -89,7 +89,7 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
"uploadedFileRemoveUserInput",
|
"uploadedFileRemoveUserInput",
|
||||||
"../test.jpg",
|
"../test.jpg",
|
||||||
Files.readAllBytes(fileToUpload.toPath()))
|
Files.readAllBytes(fileToUpload.toPath()))
|
||||||
.post(url("/WebGoat/PathTraversal/profile-upload-remove-user-input"))
|
.post(url("PathTraversal/profile-upload-remove-user-input"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -98,7 +98,7 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void assignment4() throws IOException {
|
private void assignment4() throws IOException {
|
||||||
var uri = "/WebGoat/PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2Fpath-traversal-secret";
|
var uri = "PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2Fpath-traversal-secret";
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.urlEncodingEnabled(false)
|
.urlEncodingEnabled(false)
|
||||||
.when()
|
.when()
|
||||||
@ -110,7 +110,7 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
.body(CoreMatchers.is("You found it submit the SHA-512 hash of your username as answer"));
|
.body(CoreMatchers.is("You found it submit the SHA-512 hash of your username as answer"));
|
||||||
|
|
||||||
checkAssignment(
|
checkAssignment(
|
||||||
url("/WebGoat/PathTraversal/random"),
|
url("PathTraversal/random"),
|
||||||
Map.of("secret", Sha512DigestUtils.shaHex(this.getUser())),
|
Map.of("secret", Sha512DigestUtils.shaHex(this.getUser())),
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
@ -133,8 +133,10 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.multiPart("uploadedFileZipSlip", "upload.zip", Files.readAllBytes(zipFile.toPath()))
|
.multiPart("uploadedFileZipSlip", "upload.zip", Files.readAllBytes(zipFile.toPath()))
|
||||||
.post(url("/WebGoat/PathTraversal/zip-slip"))
|
.post(url("PathTraversal/zip-slip"))
|
||||||
.then()
|
.then()
|
||||||
|
.log()
|
||||||
|
.all()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.path("lessonCompleted"),
|
.path("lessonCompleted"),
|
||||||
|
@ -29,7 +29,7 @@ public class ProgressRaceConditionIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams(Map.of("flag", "test"))
|
.formParams(Map.of("flag", "test"))
|
||||||
.post(url("/challenge/flag"));
|
.post(url("challenge/flag"));
|
||||||
};
|
};
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_PARALLEL_THREADS);
|
ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_PARALLEL_THREADS);
|
||||||
List<? extends Callable<Response>> flagCalls =
|
List<? extends Callable<Response>> flagCalls =
|
||||||
|
@ -15,11 +15,11 @@ public class SSRFIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("url", "images/jerry.png");
|
params.put("url", "images/jerry.png");
|
||||||
|
|
||||||
checkAssignment(url("/WebGoat/SSRF/task1"), params, true);
|
checkAssignment(url("SSRF/task1"), params, true);
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("url", "http://ifconfig.pro");
|
params.put("url", "http://ifconfig.pro");
|
||||||
|
|
||||||
checkAssignment(url("/WebGoat/SSRF/task2"), params, true);
|
checkAssignment(url("SSRF/task2"), params, true);
|
||||||
|
|
||||||
checkResults("/SSRF/");
|
checkResults("/SSRF/");
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
*/
|
*/
|
||||||
class SessionManagementIT extends IntegrationTest {
|
class SessionManagementIT extends IntegrationTest {
|
||||||
|
|
||||||
private static final String HIJACK_LOGIN_CONTEXT_PATH = "/WebGoat/HijackSession/login";
|
private static final String HIJACK_LOGIN_CONTEXT_PATH = "HijackSession/login";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void hijackSessionTest() {
|
void hijackSessionTest() {
|
||||||
|
@ -16,27 +16,27 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
|
|||||||
params.put("password_reg", "password");
|
params.put("password_reg", "password");
|
||||||
params.put("email_reg", "someone@microsoft.com");
|
params.put("email_reg", "someone@microsoft.com");
|
||||||
params.put("confirm_password", "password");
|
params.put("confirm_password", "password");
|
||||||
checkAssignmentWithPUT(url("/WebGoat/SqlInjectionAdvanced/challenge"), params, true);
|
checkAssignmentWithPUT(url("SqlInjectionAdvanced/challenge"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("username_login", "tom");
|
params.put("username_login", "tom");
|
||||||
params.put("password_login", "thisisasecretfortomonly");
|
params.put("password_login", "thisisasecretfortomonly");
|
||||||
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/challenge_Login"), params, true);
|
checkAssignment(url("SqlInjectionAdvanced/challenge_Login"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("userid_6a", "'; SELECT * FROM user_system_data;--");
|
params.put("userid_6a", "'; SELECT * FROM user_system_data;--");
|
||||||
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true);
|
checkAssignment(url("SqlInjectionAdvanced/attack6a"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put(
|
params.put(
|
||||||
"userid_6a",
|
"userid_6a",
|
||||||
"Smith' union select userid,user_name, user_name,user_name,password,cookie,userid from"
|
"Smith' union select userid,user_name, user_name,user_name,password,cookie,userid from"
|
||||||
+ " user_system_data --");
|
+ " user_system_data --");
|
||||||
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true);
|
checkAssignment(url("SqlInjectionAdvanced/attack6a"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("userid_6b", "passW0rD");
|
params.put("userid_6b", "passW0rD");
|
||||||
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6b"), params, true);
|
checkAssignment(url("SqlInjectionAdvanced/attack6b"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put(
|
params.put(
|
||||||
@ -54,7 +54,7 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
|
|||||||
params.put(
|
params.put(
|
||||||
"question_4_solution",
|
"question_4_solution",
|
||||||
"Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
|
"Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
|
||||||
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/quiz"), params, true);
|
checkAssignment(url("SqlInjectionAdvanced/quiz"), params, true);
|
||||||
|
|
||||||
checkResults("/SqlInjectionAdvanced/");
|
checkResults("/SqlInjectionAdvanced/");
|
||||||
}
|
}
|
||||||
|
@ -34,44 +34,44 @@ public class SqlInjectionLessonIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("query", sql_2);
|
params.put("query", sql_2);
|
||||||
checkAssignment(url("/WebGoat/SqlInjection/attack2"), params, true);
|
checkAssignment(url("SqlInjection/attack2"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("query", sql_3);
|
params.put("query", sql_3);
|
||||||
checkAssignment(url("/WebGoat/SqlInjection/attack3"), params, true);
|
checkAssignment(url("SqlInjection/attack3"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("query", sql_4_add);
|
params.put("query", sql_4_add);
|
||||||
checkAssignment(url("/WebGoat/SqlInjection/attack4"), params, true);
|
checkAssignment(url("SqlInjection/attack4"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("query", sql_5);
|
params.put("query", sql_5);
|
||||||
checkAssignment(url("/WebGoat/SqlInjection/attack5"), params, true);
|
checkAssignment(url("SqlInjection/attack5"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("operator", sql_9_operator);
|
params.put("operator", sql_9_operator);
|
||||||
params.put("account", sql_9_account);
|
params.put("account", sql_9_account);
|
||||||
params.put("injection", sql_9_injection);
|
params.put("injection", sql_9_injection);
|
||||||
checkAssignment(url("/WebGoat/SqlInjection/assignment5a"), params, true);
|
checkAssignment(url("SqlInjection/assignment5a"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("login_count", sql_10_login_count);
|
params.put("login_count", sql_10_login_count);
|
||||||
params.put("userid", sql_10_userid);
|
params.put("userid", sql_10_userid);
|
||||||
checkAssignment(url("/WebGoat/SqlInjection/assignment5b"), params, true);
|
checkAssignment(url("SqlInjection/assignment5b"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("name", sql_11_a);
|
params.put("name", sql_11_a);
|
||||||
params.put("auth_tan", sql_11_b);
|
params.put("auth_tan", sql_11_b);
|
||||||
checkAssignment(url("/WebGoat/SqlInjection/attack8"), params, true);
|
checkAssignment(url("SqlInjection/attack8"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("name", sql_12_a);
|
params.put("name", sql_12_a);
|
||||||
params.put("auth_tan", sql_12_b);
|
params.put("auth_tan", sql_12_b);
|
||||||
checkAssignment(url("/WebGoat/SqlInjection/attack9"), params, true);
|
checkAssignment(url("SqlInjection/attack9"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("action_string", sql_13);
|
params.put("action_string", sql_13);
|
||||||
checkAssignment(url("/WebGoat/SqlInjection/attack10"), params, true);
|
checkAssignment(url("SqlInjection/attack10"), params, true);
|
||||||
|
|
||||||
checkResults("/SqlInjection/");
|
checkResults("/SqlInjection/");
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
|||||||
params.put("field5", "?");
|
params.put("field5", "?");
|
||||||
params.put("field6", "prep.setString(1,\"\")");
|
params.put("field6", "prep.setString(1,\"\")");
|
||||||
params.put("field7", "prep.setString(2,\\\"\\\")");
|
params.put("field7", "prep.setString(2,\\\"\\\")");
|
||||||
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10a"), params, true);
|
checkAssignment(url("SqlInjectionMitigations/attack10a"), params, true);
|
||||||
|
|
||||||
params.put(
|
params.put(
|
||||||
"editor",
|
"editor",
|
||||||
@ -37,18 +37,18 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
|||||||
+ "} catch (Exception e) {\r\n"
|
+ "} catch (Exception e) {\r\n"
|
||||||
+ " System.out.println(\"Oops. Something went wrong!\");\r\n"
|
+ " System.out.println(\"Oops. Something went wrong!\");\r\n"
|
||||||
+ "}");
|
+ "}");
|
||||||
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10b"), params, true);
|
checkAssignment(url("SqlInjectionMitigations/attack10b"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put(
|
params.put(
|
||||||
"userid_sql_only_input_validation", "Smith';SELECT/**/*/**/from/**/user_system_data;--");
|
"userid_sql_only_input_validation", "Smith';SELECT/**/*/**/from/**/user_system_data;--");
|
||||||
checkAssignment(url("/WebGoat/SqlOnlyInputValidation/attack"), params, true);
|
checkAssignment(url("SqlOnlyInputValidation/attack"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put(
|
params.put(
|
||||||
"userid_sql_only_input_validation_on_keywords",
|
"userid_sql_only_input_validation_on_keywords",
|
||||||
"Smith';SESELECTLECT/**/*/**/FRFROMOM/**/user_system_data;--");
|
"Smith';SESELECTLECT/**/*/**/FRFROMOM/**/user_system_data;--");
|
||||||
checkAssignment(url("/WebGoat/SqlOnlyInputValidationOnKeywords/attack"), params, true);
|
checkAssignment(url("SqlOnlyInputValidationOnKeywords/attack"), params, true);
|
||||||
|
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
@ -57,7 +57,7 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
|||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(
|
.get(
|
||||||
url(
|
url(
|
||||||
"/WebGoat/SqlInjectionMitigations/servers?column=(case when (true) then hostname"
|
"SqlInjectionMitigations/servers?column=(case when (true) then hostname"
|
||||||
+ " else id end)"))
|
+ " else id end)"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200);
|
.statusCode(200);
|
||||||
@ -67,7 +67,7 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(url("/WebGoat/SqlInjectionMitigations/servers?column=unknown"))
|
.get(url("SqlInjectionMitigations/servers?column=unknown"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(500)
|
.statusCode(500)
|
||||||
.body(
|
.body(
|
||||||
@ -78,7 +78,7 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("ip", "104.130.219.202");
|
params.put("ip", "104.130.219.202");
|
||||||
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack12a"), params, true);
|
checkAssignment(url("SqlInjectionMitigations/attack12a"), params, true);
|
||||||
|
|
||||||
checkResults();
|
checkResults();
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package org.owasp.webgoat;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -11,21 +10,20 @@ import org.junit.jupiter.api.Test;
|
|||||||
public class WebWolfIntegrationTest extends IntegrationTest {
|
public class WebWolfIntegrationTest extends IntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void runTests() throws IOException {
|
public void runTests() {
|
||||||
startLesson("WebWolfIntroduction");
|
startLesson("WebWolfIntroduction");
|
||||||
|
|
||||||
// Assignment 3
|
// Assignment 3
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
|
||||||
params.put("email", this.getUser() + "@webgoat.org");
|
params.put("email", this.getUser() + "@webgoat.org");
|
||||||
checkAssignment(url("/WebGoat/WebWolf/mail/send"), params, false);
|
checkAssignment(url("WebWolf/mail/send"), params, false);
|
||||||
|
|
||||||
String responseBody =
|
String responseBody =
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(webWolfUrl("/WebWolf/mail"))
|
.get(webWolfUrl("mail"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -39,7 +37,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
|||||||
uniqueCode.lastIndexOf("your unique code is: ") + (21 + this.getUser().length()));
|
uniqueCode.lastIndexOf("your unique code is: ") + (21 + this.getUser().length()));
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("uniqueCode", uniqueCode);
|
params.put("uniqueCode", uniqueCode);
|
||||||
checkAssignment(url("/WebGoat/WebWolf/mail"), params, true);
|
checkAssignment(url("WebWolf/mail"), params, true);
|
||||||
|
|
||||||
// Assignment 4
|
// Assignment 4
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
@ -47,7 +45,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.queryParams(params)
|
.queryParams(params)
|
||||||
.get(url("/WebGoat/WebWolf/landing/password-reset"))
|
.get(url("WebWolf/landing/password-reset"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200);
|
.statusCode(200);
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
@ -55,7 +53,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.queryParams(params)
|
.queryParams(params)
|
||||||
.get(webWolfUrl("/landing"))
|
.get(webWolfUrl("landing"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200);
|
.statusCode(200);
|
||||||
responseBody =
|
responseBody =
|
||||||
@ -63,7 +61,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(webWolfUrl("/WebWolf/requests"))
|
.get(webWolfUrl("requests"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -72,7 +70,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
|||||||
assertTrue(responseBody.contains(uniqueCode));
|
assertTrue(responseBody.contains(uniqueCode));
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("uniqueCode", uniqueCode);
|
params.put("uniqueCode", uniqueCode);
|
||||||
checkAssignment(url("/WebGoat/WebWolf/landing"), params, true);
|
checkAssignment(url("WebWolf/landing"), params, true);
|
||||||
|
|
||||||
checkResults("/WebWolf");
|
checkResults("/WebWolf");
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ public class XSSIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("checkboxAttack1", "value");
|
params.put("checkboxAttack1", "value");
|
||||||
checkAssignment(url("/CrossSiteScripting/attack1"), params, true);
|
checkAssignment(url("CrossSiteScripting/attack1"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("QTY1", "1");
|
params.put("QTY1", "1");
|
||||||
@ -23,11 +23,11 @@ public class XSSIntegrationTest extends IntegrationTest {
|
|||||||
params.put("QTY4", "1");
|
params.put("QTY4", "1");
|
||||||
params.put("field1", "<script>alert('XSS+Test')</script>");
|
params.put("field1", "<script>alert('XSS+Test')</script>");
|
||||||
params.put("field2", "111");
|
params.put("field2", "111");
|
||||||
checkAssignmentWithGet(url("/CrossSiteScripting/attack5a"), params, true);
|
checkAssignmentWithGet(url("CrossSiteScripting/attack5a"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("DOMTestRoute", "start.mvc#test");
|
params.put("DOMTestRoute", "start.mvc#test");
|
||||||
checkAssignment(url("/CrossSiteScripting/attack6a"), params, true);
|
checkAssignment(url("CrossSiteScripting/attack6a"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("param1", "42");
|
params.put("param1", "42");
|
||||||
@ -41,7 +41,7 @@ public class XSSIntegrationTest extends IntegrationTest {
|
|||||||
.header("webgoat-requested-by", "dom-xss-vuln")
|
.header("webgoat-requested-by", "dom-xss-vuln")
|
||||||
.header("X-Requested-With", "XMLHttpRequest")
|
.header("X-Requested-With", "XMLHttpRequest")
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.post(url("/CrossSiteScripting/phone-home-xss"))
|
.post(url("CrossSiteScripting/phone-home-xss"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -50,7 +50,7 @@ public class XSSIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("successMessage", secretNumber);
|
params.put("successMessage", secretNumber);
|
||||||
checkAssignment(url("/CrossSiteScripting/dom-follow-up"), params, true);
|
checkAssignment(url("CrossSiteScripting/dom-follow-up"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put(
|
params.put(
|
||||||
@ -73,8 +73,44 @@ public class XSSIntegrationTest extends IntegrationTest {
|
|||||||
"question_4_solution",
|
"question_4_solution",
|
||||||
"Solution 4: No there are many other ways. Like HTML, Flash or any other type of code that"
|
"Solution 4: No there are many other ways. Like HTML, Flash or any other type of code that"
|
||||||
+ " the browser executes.");
|
+ " the browser executes.");
|
||||||
checkAssignment(url("/CrossSiteScripting/quiz"), params, true);
|
checkAssignment(url("CrossSiteScripting/quiz"), params, true);
|
||||||
|
|
||||||
checkResults("/CrossSiteScripting/");
|
params.clear();
|
||||||
|
params.put(
|
||||||
|
"editor",
|
||||||
|
"<%@ taglib uri=\"https://www.owasp.org/index.php/OWASP_Java_Encoder_Project\" %>"
|
||||||
|
+ "<html>"
|
||||||
|
+ "<head>"
|
||||||
|
+ "<title>Using GET and POST Method to Read Form Data</title>"
|
||||||
|
+ "</head>"
|
||||||
|
+ "<body>"
|
||||||
|
+ "<h1>Using POST Method to Read Form Data</h1>"
|
||||||
|
+ "<table>"
|
||||||
|
+ "<tbody>"
|
||||||
|
+ "<tr>"
|
||||||
|
+ "<td><b>First Name:</b></td>"
|
||||||
|
+ "<td>${e:forHtml(param.first_name)}</td>"
|
||||||
|
+ "</tr>"
|
||||||
|
+ "<tr>"
|
||||||
|
+ "<td><b>Last Name:</b></td>"
|
||||||
|
+ "<td>${e:forHtml(param.last_name)}</td>"
|
||||||
|
+ "</tr>"
|
||||||
|
+ "</tbody>"
|
||||||
|
+ "</table>"
|
||||||
|
+ "</body>"
|
||||||
|
+ "</html>");
|
||||||
|
checkAssignment(url("CrossSiteScripting/attack3"), params, true);
|
||||||
|
|
||||||
|
params.clear();
|
||||||
|
params.put(
|
||||||
|
"editor2",
|
||||||
|
"Policy.getInstance(\"antisamy-slashdot.xml\");"
|
||||||
|
+ "Sammy s = new AntiSamy();"
|
||||||
|
+ "s.scan(newComment,\"\");"
|
||||||
|
+ "CleanResults();"
|
||||||
|
+ "MyCommentDAO.addComment(threadID, userID).getCleanHTML());");
|
||||||
|
checkAssignment(url("CrossSiteScripting/attack4"), params, true);
|
||||||
|
|
||||||
|
checkResults("/CrossSiteScripting");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,10 +45,10 @@ public class XXEIntegrationTest extends IntegrationTest {
|
|||||||
.get(url("service/enable-security.mvc"))
|
.get(url("service/enable-security.mvc"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200);
|
.statusCode(200);
|
||||||
checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, false);
|
checkAssignment(url("xxe/simple"), ContentType.XML, xxe3, false);
|
||||||
checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, false);
|
checkAssignment(url("xxe/content-type"), ContentType.XML, xxe4, false);
|
||||||
checkAssignment(
|
checkAssignment(
|
||||||
url("/WebGoat/xxe/blind"),
|
url("xxe/blind"),
|
||||||
ContentType.XML,
|
ContentType.XML,
|
||||||
"<comment><text>" + getSecret() + "</text></comment>",
|
"<comment><text>" + getSecret() + "</text></comment>",
|
||||||
false);
|
false);
|
||||||
@ -68,7 +68,7 @@ public class XXEIntegrationTest extends IntegrationTest {
|
|||||||
}
|
}
|
||||||
String secretFile = webGoatHomeDirectory.concat("/XXE/" + getUser() + "/secret.txt");
|
String secretFile = webGoatHomeDirectory.concat("/XXE/" + getUser() + "/secret.txt");
|
||||||
String dtd7String =
|
String dtd7String =
|
||||||
dtd7.replace("WEBWOLFURL", webWolfUrl("/landing")).replace("SECRET", secretFile);
|
dtd7.replace("WEBWOLFURL", webWolfUrl("landing")).replace("SECRET", secretFile);
|
||||||
|
|
||||||
// upload DTD
|
// upload DTD
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
@ -76,7 +76,7 @@ public class XXEIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.multiPart("file", "blind.dtd", dtd7String.getBytes())
|
.multiPart("file", "blind.dtd", dtd7String.getBytes())
|
||||||
.post(webWolfUrl("/fileupload"))
|
.post(webWolfUrl("fileupload"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -84,8 +84,8 @@ public class XXEIntegrationTest extends IntegrationTest {
|
|||||||
.asString();
|
.asString();
|
||||||
// upload attack
|
// upload attack
|
||||||
String xxe7String =
|
String xxe7String =
|
||||||
xxe7.replace("WEBWOLFURL", webWolfUrl("/files")).replace("USERNAME", this.getUser());
|
xxe7.replace("WEBWOLFURL", webWolfUrl("files")).replace("USERNAME", this.getUser());
|
||||||
checkAssignment(url("/WebGoat/xxe/blind"), ContentType.XML, xxe7String, false);
|
checkAssignment(url("xxe/blind"), ContentType.XML, xxe7String, false);
|
||||||
|
|
||||||
// read results from WebWolf
|
// read results from WebWolf
|
||||||
String result =
|
String result =
|
||||||
@ -93,7 +93,7 @@ public class XXEIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(webWolfUrl("/WebWolf/requests"))
|
.get(webWolfUrl("requests"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -114,10 +114,10 @@ public class XXEIntegrationTest extends IntegrationTest {
|
|||||||
startLesson("XXE", true);
|
startLesson("XXE", true);
|
||||||
webGoatHomeDirectory = webGoatServerDirectory();
|
webGoatHomeDirectory = webGoatServerDirectory();
|
||||||
webWolfFileServerLocation = getWebWolfFileServerLocation();
|
webWolfFileServerLocation = getWebWolfFileServerLocation();
|
||||||
checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, true);
|
checkAssignment(url("xxe/simple"), ContentType.XML, xxe3, true);
|
||||||
checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, true);
|
checkAssignment(url("xxe/content-type"), ContentType.XML, xxe4, true);
|
||||||
checkAssignment(
|
checkAssignment(
|
||||||
url("/WebGoat/xxe/blind"),
|
url("xxe/blind"),
|
||||||
ContentType.XML,
|
ContentType.XML,
|
||||||
"<comment><text>" + getSecret() + "</text></comment>",
|
"<comment><text>" + getSecret() + "</text></comment>",
|
||||||
true);
|
true);
|
||||||
|
@ -242,6 +242,7 @@ public class MvcConfiguration implements WebMvcConfigurer {
|
|||||||
@Override
|
@Override
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
registry.addInterceptor(localeChangeInterceptor());
|
registry.addInterceptor(localeChangeInterceptor());
|
||||||
|
registry.addInterceptor(new UserInterceptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
package org.owasp.webgoat.container;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.owasp.webgoat.container.asciidoc.EnvironmentExposure;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
public class UserInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
private Environment env = EnvironmentExposure.getEnv();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||||
|
throws Exception {
|
||||||
|
// Do nothing
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postHandle(
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
Object handler,
|
||||||
|
ModelAndView modelAndView)
|
||||||
|
throws Exception {
|
||||||
|
if (null != modelAndView) {
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (null != authentication) {
|
||||||
|
modelAndView.getModel().put("username", authentication.getName());
|
||||||
|
}
|
||||||
|
if (null != env) {
|
||||||
|
String githubClientId =
|
||||||
|
env.getProperty("spring.security.oauth2.client.registration.github.client-id");
|
||||||
|
if (null != githubClientId && !githubClientId.equals("dummy")) {
|
||||||
|
modelAndView.getModel().put("oauth", Boolean.TRUE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
modelAndView.getModel().put("oauth", Boolean.FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(
|
||||||
|
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
|
||||||
|
throws Exception {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,9 @@ package org.owasp.webgoat.container;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import org.owasp.webgoat.container.session.UserSessionData;
|
import org.owasp.webgoat.container.session.UserSessionData;
|
||||||
import org.owasp.webgoat.container.session.WebSession;
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
|
import org.owasp.webgoat.container.users.UserRepository;
|
||||||
|
import org.owasp.webgoat.container.users.WebGoatUser;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -42,6 +45,8 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.context.annotation.PropertySource;
|
import org.springframework.context.annotation.PropertySource;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.context.annotation.ScopedProxyMode;
|
import org.springframework.context.annotation.ScopedProxyMode;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ -50,6 +55,8 @@ import org.springframework.web.client.RestTemplate;
|
|||||||
@EnableAutoConfiguration
|
@EnableAutoConfiguration
|
||||||
public class WebGoat {
|
public class WebGoat {
|
||||||
|
|
||||||
|
@Autowired private UserRepository userRepository;
|
||||||
|
|
||||||
@Bean(name = "pluginTargetDirectory")
|
@Bean(name = "pluginTargetDirectory")
|
||||||
public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) {
|
public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) {
|
||||||
return new File(webgoatHome);
|
return new File(webgoatHome);
|
||||||
@ -58,7 +65,14 @@ public class WebGoat {
|
|||||||
@Bean
|
@Bean
|
||||||
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||||
public WebSession webSession() {
|
public WebSession webSession() {
|
||||||
return new WebSession();
|
WebGoatUser webGoatUser = null;
|
||||||
|
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
if (principal instanceof WebGoatUser) {
|
||||||
|
webGoatUser = (WebGoatUser) principal;
|
||||||
|
} else if (principal instanceof DefaultOAuth2User) {
|
||||||
|
webGoatUser = userRepository.findByUsername(((DefaultOAuth2User) principal).getName());
|
||||||
|
}
|
||||||
|
return new WebSession(webGoatUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -54,32 +54,41 @@ public class WebSecurityConfig {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http.authorizeHttpRequests(
|
return http.authorizeHttpRequests(
|
||||||
auth ->
|
auth ->
|
||||||
auth.requestMatchers(
|
auth.requestMatchers(
|
||||||
|
"/",
|
||||||
|
"/favicon.ico",
|
||||||
"/css/**",
|
"/css/**",
|
||||||
"/images/**",
|
"/images/**",
|
||||||
"/js/**",
|
"/js/**",
|
||||||
"fonts/**",
|
"fonts/**",
|
||||||
"/plugins/**",
|
"/plugins/**",
|
||||||
"/registration",
|
"/registration",
|
||||||
"/register.mvc",
|
"/register.mvc")
|
||||||
"/actuator/**")
|
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.anyRequest()
|
.anyRequest()
|
||||||
.authenticated());
|
.authenticated())
|
||||||
http.formLogin()
|
.formLogin(
|
||||||
|
login ->
|
||||||
|
login
|
||||||
.loginPage("/login")
|
.loginPage("/login")
|
||||||
.defaultSuccessUrl("/welcome.mvc", true)
|
.defaultSuccessUrl("/welcome.mvc", true)
|
||||||
.usernameParameter("username")
|
.usernameParameter("username")
|
||||||
.passwordParameter("password")
|
.passwordParameter("password")
|
||||||
.permitAll();
|
.permitAll())
|
||||||
http.logout().deleteCookies("JSESSIONID").invalidateHttpSession(true);
|
.oauth2Login(
|
||||||
http.csrf().disable();
|
oidc -> {
|
||||||
|
oidc.defaultSuccessUrl("/login-oauth.mvc");
|
||||||
http.headers().cacheControl().disable();
|
oidc.loginPage("/login");
|
||||||
http.exceptionHandling().authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login"));
|
})
|
||||||
return http.build();
|
.logout(logout -> logout.deleteCookies("JSESSIONID").invalidateHttpSession(true))
|
||||||
|
.csrf(csrf -> csrf.disable())
|
||||||
|
.headers(headers -> headers.disable())
|
||||||
|
.exceptionHandling(
|
||||||
|
handling ->
|
||||||
|
handling.authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login")))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -98,7 +107,6 @@ public class WebSecurityConfig {
|
|||||||
return authenticationConfiguration.getAuthenticationManager();
|
return authenticationConfiguration.getAuthenticationManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Bean
|
@Bean
|
||||||
public NoOpPasswordEncoder passwordEncoder() {
|
public NoOpPasswordEncoder passwordEncoder() {
|
||||||
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
|
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
|
||||||
|
@ -16,7 +16,7 @@ public class EnvironmentExposure implements ApplicationContextAware {
|
|||||||
private static ApplicationContext context;
|
private static ApplicationContext context;
|
||||||
|
|
||||||
public static Environment getEnv() {
|
public static Environment getEnv() {
|
||||||
return context.getEnvironment();
|
return (null != context) ? context.getEnvironment() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -3,7 +3,6 @@ package org.owasp.webgoat.container.session;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import org.owasp.webgoat.container.lessons.Lesson;
|
import org.owasp.webgoat.container.lessons.Lesson;
|
||||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
import org.owasp.webgoat.container.users.WebGoatUser;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* *************************************************************************************************
|
* *************************************************************************************************
|
||||||
@ -40,13 +39,12 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
|||||||
public class WebSession implements Serializable {
|
public class WebSession implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = -4270066103101711560L;
|
private static final long serialVersionUID = -4270066103101711560L;
|
||||||
private final WebGoatUser currentUser;
|
private WebGoatUser currentUser;
|
||||||
private transient Lesson currentLesson;
|
private transient Lesson currentLesson;
|
||||||
private boolean securityEnabled;
|
private boolean securityEnabled;
|
||||||
|
|
||||||
public WebSession() {
|
public WebSession(WebGoatUser webGoatUser) {
|
||||||
this.currentUser =
|
this.currentUser = webGoatUser;
|
||||||
(WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,8 +3,10 @@ package org.owasp.webgoat.container.users;
|
|||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
import java.util.UUID;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -44,4 +46,12 @@ public class RegistrationController {
|
|||||||
|
|
||||||
return "redirect:/attack";
|
return "redirect:/attack";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/login-oauth.mvc")
|
||||||
|
public String registrationOAUTH(Authentication authentication, HttpServletRequest request)
|
||||||
|
throws ServletException {
|
||||||
|
log.info("register oauth user in database");
|
||||||
|
userService.addUser(authentication.getName(), UUID.randomUUID().toString());
|
||||||
|
return "redirect:/welcome.mvc";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,8 @@ public class IDORViewOtherProfile extends AssignmentEndpoint {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
public AttackResult completed(@PathVariable("userId") String userId, HttpServletResponse resp) {
|
public AttackResult completed(@PathVariable("userId") String userId, HttpServletResponse resp) {
|
||||||
|
|
||||||
if (userSessionData.getValue("idor-authenticated-as").equals("tom")) {
|
Object obj = userSessionData.getValue("idor-authenticated-as");
|
||||||
|
if (obj != null && obj.equals("tom")) {
|
||||||
// going to use session auth to view this one
|
// going to use session auth to view this one
|
||||||
String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id");
|
String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id");
|
||||||
if (userId != null && !userId.equals(authUserId)) {
|
if (userId != null && !userId.equals(authUserId)) {
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
package org.owasp.webgoat.lessons.jwt.claimmisuse;
|
||||||
|
|
||||||
|
import com.auth0.jwk.JwkException;
|
||||||
|
import com.auth0.jwk.JwkProvider;
|
||||||
|
import com.auth0.jwk.JwkProviderBuilder;
|
||||||
|
import com.auth0.jwt.JWT;
|
||||||
|
import com.auth0.jwt.algorithms.Algorithm;
|
||||||
|
import com.auth0.jwt.exceptions.JWTVerificationException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||||
|
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||||
|
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RequestMapping("/JWT/jku")
|
||||||
|
@RestController
|
||||||
|
@AssignmentHints({
|
||||||
|
"jwt-jku-hint1",
|
||||||
|
"jwt-jku-hint2",
|
||||||
|
"jwt-jku-hint3",
|
||||||
|
"jwt-jku-hint4",
|
||||||
|
"jwt-jku-hint5"
|
||||||
|
})
|
||||||
|
public class JWTHeaderJKUEndpoint extends AssignmentEndpoint {
|
||||||
|
|
||||||
|
@PostMapping("/follow/{user}")
|
||||||
|
public @ResponseBody String follow(@PathVariable("user") String user) {
|
||||||
|
if ("Jerry".equals(user)) {
|
||||||
|
return "Following yourself seems redundant";
|
||||||
|
} else {
|
||||||
|
return "You are now following Tom";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public @ResponseBody AttackResult resetVotes(@RequestParam("token") String token) {
|
||||||
|
if (StringUtils.isEmpty(token)) {
|
||||||
|
return failed(this).feedback("jwt-invalid-token").build();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
var decodedJWT = JWT.decode(token);
|
||||||
|
var jku = decodedJWT.getHeaderClaim("jku");
|
||||||
|
JwkProvider jwkProvider = new JwkProviderBuilder(new URL(jku.asString())).build();
|
||||||
|
var jwk = jwkProvider.get(decodedJWT.getKeyId());
|
||||||
|
var algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey());
|
||||||
|
JWT.require(algorithm).build().verify(decodedJWT);
|
||||||
|
|
||||||
|
String username = decodedJWT.getClaims().get("username").asString();
|
||||||
|
if ("Jerry".equals(username)) {
|
||||||
|
return failed(this).feedback("jwt-final-jerry-account").build();
|
||||||
|
}
|
||||||
|
if ("Tom".equals(username)) {
|
||||||
|
return success(this).build();
|
||||||
|
} else {
|
||||||
|
return failed(this).feedback("jwt-final-not-tom").build();
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException | JWTVerificationException | JwkException e) {
|
||||||
|
return failed(this).feedback("jwt-invalid-token").output(e.toString()).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,7 @@
|
|||||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.owasp.webgoat.lessons.jwt;
|
package org.owasp.webgoat.lessons.jwt.claimmisuse;
|
||||||
|
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.JwsHeader;
|
import io.jsonwebtoken.JwsHeader;
|
||||||
@ -38,28 +38,30 @@ import org.owasp.webgoat.container.assignments.AssignmentHints;
|
|||||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@AssignmentHints({
|
@AssignmentHints({
|
||||||
"jwt-final-hint1",
|
"jwt-kid-hint1",
|
||||||
"jwt-final-hint2",
|
"jwt-kid-hint2",
|
||||||
"jwt-final-hint3",
|
"jwt-kid-hint3",
|
||||||
"jwt-final-hint4",
|
"jwt-kid-hint4",
|
||||||
"jwt-final-hint5",
|
"jwt-kid-hint5",
|
||||||
"jwt-final-hint6"
|
"jwt-kid-hint6"
|
||||||
})
|
})
|
||||||
public class JWTFinalEndpoint extends AssignmentEndpoint {
|
@RequestMapping("/JWT/kid")
|
||||||
|
public class JWTHeaderKIDEndpoint extends AssignmentEndpoint {
|
||||||
|
|
||||||
private final LessonDataSource dataSource;
|
private final LessonDataSource dataSource;
|
||||||
|
|
||||||
private JWTFinalEndpoint(LessonDataSource dataSource) {
|
private JWTHeaderKIDEndpoint(LessonDataSource dataSource) {
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/JWT/final/follow/{user}")
|
@PostMapping("/follow/{user}")
|
||||||
public @ResponseBody String follow(@PathVariable("user") String user) {
|
public @ResponseBody String follow(@PathVariable("user") String user) {
|
||||||
if ("Jerry".equals(user)) {
|
if ("Jerry".equals(user)) {
|
||||||
return "Following yourself seems redundant";
|
return "Following yourself seems redundant";
|
||||||
@ -68,7 +70,7 @@ public class JWTFinalEndpoint extends AssignmentEndpoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/JWT/final/delete")
|
@PostMapping("/delete")
|
||||||
public @ResponseBody AttackResult resetVotes(@RequestParam("token") String token) {
|
public @ResponseBody AttackResult resetVotes(@RequestParam("token") String token) {
|
||||||
if (StringUtils.isEmpty(token)) {
|
if (StringUtils.isEmpty(token)) {
|
||||||
return failed(this).feedback("jwt-invalid-token").build();
|
return failed(this).feedback("jwt-invalid-token").build();
|
@ -39,7 +39,8 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
"access-control.hash.hint9",
|
"access-control.hash.hint9",
|
||||||
"access-control.hash.hint10",
|
"access-control.hash.hint10",
|
||||||
"access-control.hash.hint11",
|
"access-control.hash.hint11",
|
||||||
"access-control.hash.hint12"
|
"access-control.hash.hint12",
|
||||||
|
"access-control.hash.hint13"
|
||||||
})
|
})
|
||||||
public class MissingFunctionACYourHashAdmin extends AssignmentEndpoint {
|
public class MissingFunctionACYourHashAdmin extends AssignmentEndpoint {
|
||||||
|
|
||||||
|
@ -48,16 +48,19 @@ public class ResetLinkAssignmentForgotPassword extends AssignmentEndpoint {
|
|||||||
private final RestTemplate restTemplate;
|
private final RestTemplate restTemplate;
|
||||||
private String webWolfHost;
|
private String webWolfHost;
|
||||||
private String webWolfPort;
|
private String webWolfPort;
|
||||||
|
private String webWolfURL;
|
||||||
private final String webWolfMailURL;
|
private final String webWolfMailURL;
|
||||||
|
|
||||||
public ResetLinkAssignmentForgotPassword(
|
public ResetLinkAssignmentForgotPassword(
|
||||||
RestTemplate restTemplate,
|
RestTemplate restTemplate,
|
||||||
@Value("${webwolf.host}") String webWolfHost,
|
@Value("${webwolf.host}") String webWolfHost,
|
||||||
@Value("${webwolf.port}") String webWolfPort,
|
@Value("${webwolf.port}") String webWolfPort,
|
||||||
|
@Value("${webwolf.url}") String webWolfURL,
|
||||||
@Value("${webwolf.mail.url}") String webWolfMailURL) {
|
@Value("${webwolf.mail.url}") String webWolfMailURL) {
|
||||||
this.restTemplate = restTemplate;
|
this.restTemplate = restTemplate;
|
||||||
this.webWolfHost = webWolfHost;
|
this.webWolfHost = webWolfHost;
|
||||||
this.webWolfPort = webWolfPort;
|
this.webWolfPort = webWolfPort;
|
||||||
|
this.webWolfURL = webWolfURL;
|
||||||
this.webWolfMailURL = webWolfMailURL;
|
this.webWolfMailURL = webWolfMailURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,12 +70,12 @@ public class ResetLinkAssignmentForgotPassword extends AssignmentEndpoint {
|
|||||||
@RequestParam String email, HttpServletRequest request) {
|
@RequestParam String email, HttpServletRequest request) {
|
||||||
String resetLink = UUID.randomUUID().toString();
|
String resetLink = UUID.randomUUID().toString();
|
||||||
ResetLinkAssignment.resetLinks.add(resetLink);
|
ResetLinkAssignment.resetLinks.add(resetLink);
|
||||||
String host = request.getHeader("host");
|
String host = request.getHeader(HttpHeaders.HOST);
|
||||||
if (ResetLinkAssignment.TOM_EMAIL.equals(email)
|
if (ResetLinkAssignment.TOM_EMAIL.equals(email)
|
||||||
&& (host.contains(webWolfPort)
|
&& (host.contains(webWolfPort)
|
||||||
|| host.contains(webWolfHost))) { // User indeed changed the host header.
|
&& host.contains(webWolfHost))) { // User indeed changed the host header.
|
||||||
ResetLinkAssignment.userToTomResetLink.put(getWebSession().getUserName(), resetLink);
|
ResetLinkAssignment.userToTomResetLink.put(getWebSession().getUserName(), resetLink);
|
||||||
fakeClickingLinkEmail(host, resetLink);
|
fakeClickingLinkEmail(webWolfURL, resetLink);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
sendMailToUser(email, host, resetLink);
|
sendMailToUser(email, host, resetLink);
|
||||||
@ -97,13 +100,13 @@ public class ResetLinkAssignmentForgotPassword extends AssignmentEndpoint {
|
|||||||
this.restTemplate.postForEntity(webWolfMailURL, mail, Object.class);
|
this.restTemplate.postForEntity(webWolfMailURL, mail, Object.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fakeClickingLinkEmail(String host, String resetLink) {
|
private void fakeClickingLinkEmail(String webWolfURL, String resetLink) {
|
||||||
try {
|
try {
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
HttpEntity httpEntity = new HttpEntity(httpHeaders);
|
HttpEntity httpEntity = new HttpEntity(httpHeaders);
|
||||||
new RestTemplate()
|
new RestTemplate()
|
||||||
.exchange(
|
.exchange(
|
||||||
String.format("http://%s/PasswordReset/reset/reset-password/%s", host, resetLink),
|
String.format("%s/PasswordReset/reset/reset-password/%s", webWolfURL, resetLink),
|
||||||
HttpMethod.GET,
|
HttpMethod.GET,
|
||||||
httpEntity,
|
httpEntity,
|
||||||
Void.class);
|
Void.class);
|
||||||
|
@ -58,7 +58,8 @@ public class LandingAssignment extends AssignmentEndpoint {
|
|||||||
public ModelAndView openPasswordReset(HttpServletRequest request) throws URISyntaxException {
|
public ModelAndView openPasswordReset(HttpServletRequest request) throws URISyntaxException {
|
||||||
URI uri = new URI(request.getRequestURL().toString());
|
URI uri = new URI(request.getRequestURL().toString());
|
||||||
ModelAndView modelAndView = new ModelAndView();
|
ModelAndView modelAndView = new ModelAndView();
|
||||||
modelAndView.addObject("webwolfUrl", landingPageUrl);
|
modelAndView.addObject(
|
||||||
|
"webwolfLandingPageUrl", landingPageUrl.replace("//landing", "/landing"));
|
||||||
modelAndView.addObject("uniqueCode", StringUtils.reverse(getWebSession().getUserName()));
|
modelAndView.addObject("uniqueCode", StringUtils.reverse(getWebSession().getUserName()));
|
||||||
|
|
||||||
modelAndView.setViewName("lessons/webwolfintroduction/templates/webwolfPasswordReset.html");
|
modelAndView.setViewName("lessons/webwolfintroduction/templates/webwolfPasswordReset.html");
|
||||||
|
@ -35,6 +35,6 @@ public class CrossSiteScripting extends Lesson {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return "xss.title";
|
return "4.xss.title";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
* 02111-1307, USA.
|
* 02111-1307, USA.
|
||||||
*
|
*
|
||||||
* Getting Source ==============
|
* Getting Source
|
||||||
|
* ==============
|
||||||
*
|
*
|
||||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
||||||
*/
|
*/
|
||||||
@ -30,12 +31,9 @@ import org.owasp.webgoat.container.assignments.AttackResult;
|
|||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
// @RestController
|
@RestController
|
||||||
@Deprecated
|
|
||||||
// TODO This assignment seems not to be in use in the UI
|
|
||||||
// it is there to make sure the lesson can be marked complete
|
|
||||||
// in order to restore it, make it accessible through the UI and uncomment RestController
|
|
||||||
@AssignmentHints(
|
@AssignmentHints(
|
||||||
value = {
|
value = {
|
||||||
"xss-mitigation-3-hint1",
|
"xss-mitigation-3-hint1",
|
||||||
@ -60,9 +58,9 @@ public class CrossSiteScriptingLesson3 extends AssignmentEndpoint {
|
|||||||
String lastNameElement =
|
String lastNameElement =
|
||||||
doc.select("body > table > tbody > tr:nth-child(2) > td:nth-child(2)").first().text();
|
doc.select("body > table > tbody > tr:nth-child(2) > td:nth-child(2)").first().text();
|
||||||
|
|
||||||
Boolean includeCorrect = false;
|
boolean includeCorrect = false;
|
||||||
Boolean firstNameCorrect = false;
|
boolean firstNameCorrect = false;
|
||||||
Boolean lastNameCorrect = false;
|
boolean lastNameCorrect = false;
|
||||||
|
|
||||||
if (include.contains("<%@")
|
if (include.contains("<%@")
|
||||||
&& include.contains("taglib")
|
&& include.contains("taglib")
|
||||||
|
@ -22,20 +22,15 @@
|
|||||||
|
|
||||||
package org.owasp.webgoat.lessons.xss;
|
package org.owasp.webgoat.lessons.xss;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
// @RestController
|
@RestController
|
||||||
@Deprecated
|
|
||||||
// TODO This assignment seems not to be in use in the UI
|
|
||||||
// it is there to make sure the lesson can be marked complete
|
|
||||||
// in order to restore it, make it accessible through the UI and uncomment RestController@Slf4j
|
|
||||||
@Slf4j
|
|
||||||
@AssignmentHints(value = {"xss-mitigation-4-hint1"})
|
@AssignmentHints(value = {"xss-mitigation-4-hint1"})
|
||||||
public class CrossSiteScriptingLesson4 extends AssignmentEndpoint {
|
public class CrossSiteScriptingLesson4 extends AssignmentEndpoint {
|
||||||
|
|
||||||
@ -44,7 +39,6 @@ public class CrossSiteScriptingLesson4 extends AssignmentEndpoint {
|
|||||||
public AttackResult completed(@RequestParam String editor2) {
|
public AttackResult completed(@RequestParam String editor2) {
|
||||||
|
|
||||||
String editor = editor2.replaceAll("\\<.*?>", "");
|
String editor = editor2.replaceAll("\\<.*?>", "");
|
||||||
log.debug(editor);
|
|
||||||
|
|
||||||
if ((editor.contains("Policy.getInstance(\"antisamy-slashdot.xml\"")
|
if ((editor.contains("Policy.getInstance(\"antisamy-slashdot.xml\"")
|
||||||
|| editor.contains(".scan(newComment, \"antisamy-slashdot.xml\"")
|
|| editor.contains(".scan(newComment, \"antisamy-slashdot.xml\"")
|
||||||
@ -54,10 +48,8 @@ public class CrossSiteScriptingLesson4 extends AssignmentEndpoint {
|
|||||||
&& editor.contains("CleanResults")
|
&& editor.contains("CleanResults")
|
||||||
&& editor.contains("MyCommentDAO.addComment(threadID, userID")
|
&& editor.contains("MyCommentDAO.addComment(threadID, userID")
|
||||||
&& editor.contains(".getCleanHTML());")) {
|
&& editor.contains(".getCleanHTML());")) {
|
||||||
log.debug("true");
|
|
||||||
return success(this).feedback("xss-mitigation-4-success").build();
|
return success(this).feedback("xss-mitigation-4-success").build();
|
||||||
} else {
|
} else {
|
||||||
log.debug("false");
|
|
||||||
return failed(this).feedback("xss-mitigation-4-failed").build();
|
return failed(this).feedback("xss-mitigation-4-failed").build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
* 02111-1307, USA.
|
* 02111-1307, USA.
|
||||||
*
|
*
|
||||||
* Getting Source ==============
|
* Getting Source
|
||||||
|
* ==============
|
||||||
*
|
*
|
||||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
||||||
*/
|
*/
|
||||||
@ -24,7 +25,9 @@ package org.owasp.webgoat.lessons.xss;
|
|||||||
|
|
||||||
import org.owasp.webgoat.container.lessons.Category;
|
import org.owasp.webgoat.container.lessons.Category;
|
||||||
import org.owasp.webgoat.container.lessons.Lesson;
|
import org.owasp.webgoat.container.lessons.Lesson;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
public class CrossSiteScriptingMitigation extends Lesson {
|
public class CrossSiteScriptingMitigation extends Lesson {
|
||||||
@Override
|
@Override
|
||||||
public Category getDefaultCategory() {
|
public Category getDefaultCategory() {
|
||||||
@ -33,6 +36,6 @@ public class CrossSiteScriptingMitigation extends Lesson {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return "xss-mitigation.title";
|
return "6.xss-mitigation.title";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,9 @@ package org.owasp.webgoat.lessons.xss.stored;
|
|||||||
|
|
||||||
import org.owasp.webgoat.container.lessons.Category;
|
import org.owasp.webgoat.container.lessons.Category;
|
||||||
import org.owasp.webgoat.container.lessons.Lesson;
|
import org.owasp.webgoat.container.lessons.Lesson;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
public class CrossSiteScriptingStored extends Lesson {
|
public class CrossSiteScriptingStored extends Lesson {
|
||||||
@Override
|
@Override
|
||||||
public Category getDefaultCategory() {
|
public Category getDefaultCategory() {
|
||||||
@ -33,6 +35,6 @@ public class CrossSiteScriptingStored extends Lesson {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return "xss-stored.title";
|
return "5.xss-stored.title";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,21 +34,15 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RestController
|
@RestController
|
||||||
public class StoredCrossSiteScriptingVerifier extends AssignmentEndpoint {
|
public class StoredCrossSiteScriptingVerifier extends AssignmentEndpoint {
|
||||||
|
|
||||||
// TODO This assignment seems not to be in use in the UI
|
|
||||||
@PostMapping("/CrossSiteScriptingStored/stored-xss-follow-up")
|
@PostMapping("/CrossSiteScriptingStored/stored-xss-follow-up")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public AttackResult completed(@RequestParam String successMessage) {
|
public AttackResult completed(@RequestParam String successMessage) {
|
||||||
UserSessionData userSessionData = getUserSessionData();
|
UserSessionData userSessionData = getUserSessionData();
|
||||||
|
|
||||||
if (successMessage.equals(userSessionData.getValue("randValue").toString())) {
|
if (successMessage.equals(userSessionData.getValue("randValue"))) {
|
||||||
return success(this).feedback("xss-stored-callback-success").build();
|
return success(this).feedback("xss-stored-callback-success").build();
|
||||||
} else {
|
} else {
|
||||||
return failed(this).feedback("xss-stored-callback-failure").build();
|
return failed(this).feedback("xss-stored-callback-failure").build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// something like ...
|
|
||||||
// http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere%3Cscript%3Ewebgoat.customjs.phoneHome();%3C%2Fscript%3E
|
|
||||||
// or
|
|
||||||
// http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere<script>webgoat.customjs.phoneHome();<%2Fscript>
|
|
||||||
|
@ -72,7 +72,6 @@ public class StoredXssComments extends AssignmentEndpoint {
|
|||||||
"Can you post a comment, calling webgoat.customjs.phoneHome() ?"));
|
"Can you post a comment, calling webgoat.customjs.phoneHome() ?"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO This assignment seems not to be in use in the UI
|
|
||||||
@GetMapping(
|
@GetMapping(
|
||||||
path = "/CrossSiteScriptingStored/stored-xss",
|
path = "/CrossSiteScriptingStored/stored-xss",
|
||||||
produces = MediaType.APPLICATION_JSON_VALUE,
|
produces = MediaType.APPLICATION_JSON_VALUE,
|
||||||
@ -89,7 +88,6 @@ public class StoredXssComments extends AssignmentEndpoint {
|
|||||||
return allComments;
|
return allComments;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO This assignment seems not to be in use in the UI
|
|
||||||
@PostMapping("/CrossSiteScriptingStored/stored-xss")
|
@PostMapping("/CrossSiteScriptingStored/stored-xss")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public AttackResult createNewComment(@RequestBody String commentStr) {
|
public AttackResult createNewComment(@RequestBody String commentStr) {
|
||||||
|
@ -25,14 +25,12 @@
|
|||||||
|
|
||||||
package org.owasp.webgoat.server;
|
package org.owasp.webgoat.server;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.owasp.webgoat.container.WebGoat;
|
import org.owasp.webgoat.container.WebGoat;
|
||||||
import org.owasp.webgoat.webwolf.WebWolf;
|
import org.owasp.webgoat.webwolf.WebWolf;
|
||||||
import org.springframework.boot.Banner;
|
import org.springframework.boot.Banner;
|
||||||
import org.springframework.boot.WebApplicationType;
|
import org.springframework.boot.WebApplicationType;
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class StartWebGoat {
|
public class StartWebGoat {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -15,16 +15,18 @@ public class StartupMessage {
|
|||||||
|
|
||||||
private String port;
|
private String port;
|
||||||
private String address;
|
private String address;
|
||||||
|
private String contextPath;
|
||||||
|
|
||||||
@EventListener
|
@EventListener
|
||||||
void onStartup(ApplicationReadyEvent event) {
|
void onStartup(ApplicationReadyEvent event) {
|
||||||
if (StringUtils.hasText(port)
|
|
||||||
&& !StringUtils.hasText(System.getProperty("running.in.docker"))) {
|
|
||||||
log.info("Please browse to http://{}:{}/WebGoat to get started...", address, port);
|
|
||||||
}
|
|
||||||
if (event.getApplicationContext().getApplicationName().contains("WebGoat")) {
|
|
||||||
port = event.getApplicationContext().getEnvironment().getProperty("server.port");
|
port = event.getApplicationContext().getEnvironment().getProperty("server.port");
|
||||||
address = event.getApplicationContext().getEnvironment().getProperty("server.address");
|
address = event.getApplicationContext().getEnvironment().getProperty("server.address");
|
||||||
|
contextPath =
|
||||||
|
event.getApplicationContext().getEnvironment().getProperty("server.servlet.context-path");
|
||||||
|
if (StringUtils.hasText(port)
|
||||||
|
&& !StringUtils.hasText(System.getProperty("running.in.docker"))) {
|
||||||
|
log.warn("Please browse to http://{}:{}{} to get started...", address, port, contextPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,10 +32,9 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.owasp.webgoat.webwolf.user.WebGoatUser;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.ModelMap;
|
import org.springframework.ui.ModelMap;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -58,6 +57,9 @@ public class FileServer {
|
|||||||
@Value("${server.address}")
|
@Value("${server.address}")
|
||||||
private String server;
|
private String server;
|
||||||
|
|
||||||
|
@Value("${server.servlet.context-path}")
|
||||||
|
private String contextPath;
|
||||||
|
|
||||||
@Value("${server.port}")
|
@Value("${server.port}")
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
@ -71,9 +73,11 @@ public class FileServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/fileupload")
|
@PostMapping(value = "/fileupload")
|
||||||
public ModelAndView importFile(@RequestParam("file") MultipartFile myFile) throws IOException {
|
public ModelAndView importFile(
|
||||||
var user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
@RequestParam("file") MultipartFile myFile, Authentication authentication)
|
||||||
var destinationDir = new File(fileLocation, user.getUsername());
|
throws IOException {
|
||||||
|
String username = authentication.getName();
|
||||||
|
var destinationDir = new File(fileLocation, username);
|
||||||
destinationDir.mkdirs();
|
destinationDir.mkdirs();
|
||||||
myFile.transferTo(new File(destinationDir, myFile.getOriginalFilename()));
|
myFile.transferTo(new File(destinationDir, myFile.getOriginalFilename()));
|
||||||
log.debug("File saved to {}", new File(destinationDir, myFile.getOriginalFilename()));
|
log.debug("File saved to {}", new File(destinationDir, myFile.getOriginalFilename()));
|
||||||
@ -92,15 +96,13 @@ public class FileServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/files")
|
@GetMapping(value = "/files")
|
||||||
public ModelAndView getFiles(HttpServletRequest request) {
|
public ModelAndView getFiles(HttpServletRequest request, Authentication authentication) {
|
||||||
WebGoatUser user =
|
String username = (null != authentication) ? authentication.getName() : "anonymous";
|
||||||
(WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
|
||||||
String username = user.getUsername();
|
|
||||||
File destinationDir = new File(fileLocation, username);
|
File destinationDir = new File(fileLocation, username);
|
||||||
|
|
||||||
ModelAndView modelAndView = new ModelAndView();
|
ModelAndView modelAndView = new ModelAndView();
|
||||||
modelAndView.setViewName("files");
|
modelAndView.setViewName("files");
|
||||||
File changeIndicatorFile = new File(destinationDir, user.getUsername() + "_changed");
|
File changeIndicatorFile = new File(destinationDir, username + "_changed");
|
||||||
if (changeIndicatorFile.exists()) {
|
if (changeIndicatorFile.exists()) {
|
||||||
modelAndView.addObject("uploadSuccess", request.getParameter("uploadSuccess"));
|
modelAndView.addObject("uploadSuccess", request.getParameter("uploadSuccess"));
|
||||||
}
|
}
|
||||||
@ -117,7 +119,7 @@ public class FileServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
modelAndView.addObject("files", uploadedFiles);
|
modelAndView.addObject("files", uploadedFiles);
|
||||||
modelAndView.addObject("webwolf_url", "http://" + server + ":" + port);
|
modelAndView.addObject("webwolf_url", "http://" + server + ":" + port + contextPath);
|
||||||
return modelAndView;
|
return modelAndView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,10 @@ package org.owasp.webgoat.webwolf;
|
|||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import org.owasp.webgoat.container.UserInterceptor;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
@ -55,6 +57,12 @@ public class MvcConfiguration implements WebMvcConfigurer {
|
|||||||
public void addViewControllers(ViewControllerRegistry registry) {
|
public void addViewControllers(ViewControllerRegistry registry) {
|
||||||
registry.addViewController("/login").setViewName("webwolf-login");
|
registry.addViewController("/login").setViewName("webwolf-login");
|
||||||
registry.addViewController("/home").setViewName("home");
|
registry.addViewController("/home").setViewName("home");
|
||||||
|
registry.addViewController("/").setViewName("home");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(new UserInterceptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
package org.owasp.webgoat.webwolf;
|
package org.owasp.webgoat.webwolf;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.owasp.webgoat.container.AjaxAuthenticationEntryPoint;
|
||||||
import org.owasp.webgoat.webwolf.user.UserService;
|
import org.owasp.webgoat.webwolf.user.UserService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -46,16 +47,39 @@ public class WebSecurityConfig {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http.authorizeHttpRequests(
|
return http.authorizeHttpRequests(
|
||||||
auth -> auth.requestMatchers(HttpMethod.POST, "/fileupload").authenticated());
|
auth -> {
|
||||||
http.authorizeHttpRequests(
|
auth.requestMatchers("/css/**", "/webjars/**", "/favicon.ico", "/js/**", "/images/**")
|
||||||
auth ->
|
.permitAll();
|
||||||
auth.requestMatchers(HttpMethod.GET, "/files", "/mail", "/requests").authenticated());
|
auth.requestMatchers(
|
||||||
http.authorizeHttpRequests().anyRequest().permitAll();
|
HttpMethod.GET,
|
||||||
http.csrf().disable().formLogin().loginPage("/login").failureUrl("/login?error=true");
|
"/fileupload/**",
|
||||||
http.formLogin().loginPage("/login").defaultSuccessUrl("/home", true).permitAll();
|
"/files/**",
|
||||||
http.logout().permitAll();
|
"/landing/**",
|
||||||
return http.build();
|
"/PasswordReset/**")
|
||||||
|
.permitAll();
|
||||||
|
auth.requestMatchers(HttpMethod.POST, "/files", "/mail", "/requests").permitAll();
|
||||||
|
auth.anyRequest().authenticated();
|
||||||
|
})
|
||||||
|
.csrf(csrf -> csrf.disable())
|
||||||
|
.formLogin(
|
||||||
|
login ->
|
||||||
|
login
|
||||||
|
.loginPage("/login")
|
||||||
|
.failureUrl("/login?error=true")
|
||||||
|
.defaultSuccessUrl("/home", true)
|
||||||
|
.usernameParameter("username")
|
||||||
|
.passwordParameter("password")
|
||||||
|
.permitAll())
|
||||||
|
.oauth2Login(
|
||||||
|
oidc -> {
|
||||||
|
oidc.defaultSuccessUrl("/home");
|
||||||
|
})
|
||||||
|
.logout(logout -> logout.deleteCookies("WEBWOLFSESSION").invalidateHttpSession(true))
|
||||||
|
.exceptionHandling(
|
||||||
|
handling ->
|
||||||
|
handling.authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login")))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package org.owasp.webgoat.webwolf.jwt;
|
package org.owasp.webgoat.webwolf.jwt;
|
||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
import static org.springframework.util.Base64Utils.decodeFromUrlSafeString;
|
|
||||||
import static org.springframework.util.StringUtils.hasText;
|
import static org.springframework.util.StringUtils.hasText;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@ -103,8 +103,8 @@ public class JWTToken {
|
|||||||
var builder = JWTToken.builder().encoded(jwt);
|
var builder = JWTToken.builder().encoded(jwt);
|
||||||
|
|
||||||
if (token.length >= 2) {
|
if (token.length >= 2) {
|
||||||
var header = new String(decodeFromUrlSafeString(token[0]), UTF_8);
|
var header = new String(Base64.getUrlDecoder().decode(token[0]), UTF_8);
|
||||||
var payloadAsString = new String(decodeFromUrlSafeString(token[1]), UTF_8);
|
var payloadAsString = new String(Base64.getUrlDecoder().decode(token[1]), UTF_8);
|
||||||
var headers = parse(header);
|
var headers = parse(header);
|
||||||
var payload = parse(payloadAsString);
|
var payload = parse(payloadAsString);
|
||||||
builder.header(write(header, headers));
|
builder.header(write(header, headers));
|
||||||
|
@ -25,8 +25,8 @@ package org.owasp.webgoat.webwolf.mailbox;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -42,16 +42,16 @@ public class MailboxController {
|
|||||||
private final MailboxRepository mailboxRepository;
|
private final MailboxRepository mailboxRepository;
|
||||||
|
|
||||||
@GetMapping("/mail")
|
@GetMapping("/mail")
|
||||||
public ModelAndView mail() {
|
public ModelAndView mail(Authentication authentication, Model model) {
|
||||||
UserDetails user =
|
String username = (null != authentication) ? authentication.getName() : "anonymous";
|
||||||
(UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
|
||||||
ModelAndView modelAndView = new ModelAndView();
|
ModelAndView modelAndView = new ModelAndView();
|
||||||
List<Email> emails = mailboxRepository.findByRecipientOrderByTimeDesc(user.getUsername());
|
List<Email> emails = mailboxRepository.findByRecipientOrderByTimeDesc(username);
|
||||||
if (emails != null && !emails.isEmpty()) {
|
if (emails != null && !emails.isEmpty()) {
|
||||||
modelAndView.addObject("total", emails.size());
|
modelAndView.addObject("total", emails.size());
|
||||||
modelAndView.addObject("emails", emails);
|
modelAndView.addObject("emails", emails);
|
||||||
}
|
}
|
||||||
modelAndView.setViewName("mailbox");
|
modelAndView.setViewName("mailbox");
|
||||||
|
model.addAttribute("username", username);
|
||||||
return modelAndView;
|
return modelAndView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
|
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@ -64,12 +63,12 @@ public class Requests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public ModelAndView get() {
|
public ModelAndView get(Authentication authentication) {
|
||||||
var model = new ModelAndView("requests");
|
var model = new ModelAndView("requests");
|
||||||
var user = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
String username = (null != authentication) ? authentication.getName() : "anonymous";
|
||||||
var traces =
|
var traces =
|
||||||
traceRepository.findAllTraces().stream()
|
traceRepository.findAllTraces().stream()
|
||||||
.filter(t -> allowedTrace(t, user))
|
.filter(t -> allowedTrace(t, username))
|
||||||
.map(t -> new Tracert(t.getTimestamp(), path(t), toJsonString(t)))
|
.map(t -> new Tracert(t.getTimestamp(), path(t), toJsonString(t)))
|
||||||
.collect(toList());
|
.collect(toList());
|
||||||
model.addObject("traces", traces);
|
model.addObject("traces", traces);
|
||||||
@ -77,17 +76,16 @@ public class Requests {
|
|||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean allowedTrace(HttpExchange t, UserDetails user) {
|
private boolean allowedTrace(HttpExchange t, String username) {
|
||||||
HttpExchange.Request req = t.getRequest();
|
HttpExchange.Request req = t.getRequest();
|
||||||
boolean allowed = true;
|
boolean allowed = true;
|
||||||
/* do not show certain traces to other users in a classroom setup */
|
/* do not show certain traces to other users in a classroom setup */
|
||||||
if (req.getUri().getPath().contains("/files")
|
if (req.getUri().getPath().contains("/files") && !req.getUri().getPath().contains(username)) {
|
||||||
&& !req.getUri().getPath().contains(user.getUsername())) {
|
|
||||||
allowed = false;
|
allowed = false;
|
||||||
} else if (req.getUri().getPath().contains("/landing")
|
} else if (req.getUri().getPath().contains("/landing")
|
||||||
&& req.getUri().getQuery() != null
|
&& req.getUri().getQuery() != null
|
||||||
&& req.getUri().getQuery().contains("uniqueCode")
|
&& req.getUri().getQuery().contains("uniqueCode")
|
||||||
&& !req.getUri().getQuery().contains(StringUtils.reverse(user.getUsername()))) {
|
&& !req.getUri().getQuery().contains(StringUtils.reverse(username))) {
|
||||||
allowed = false;
|
allowed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ package org.owasp.webgoat.webwolf.requests;
|
|||||||
import com.google.common.collect.EvictingQueue;
|
import com.google.common.collect.EvictingQueue;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
|
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
|
||||||
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
|
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
|
||||||
|
|
||||||
@ -36,7 +35,6 @@ import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
|
|||||||
* @author nbaars
|
* @author nbaars
|
||||||
* @since 8/13/17.
|
* @since 8/13/17.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
|
||||||
public class WebWolfTraceRepository implements HttpExchangeRepository {
|
public class WebWolfTraceRepository implements HttpExchangeRepository {
|
||||||
|
|
||||||
private final EvictingQueue<HttpExchange> traces = EvictingQueue.create(10000);
|
private final EvictingQueue<HttpExchange> traces = EvictingQueue.create(10000);
|
||||||
@ -46,7 +44,6 @@ public class WebWolfTraceRepository implements HttpExchangeRepository {
|
|||||||
"/home",
|
"/home",
|
||||||
"/files",
|
"/files",
|
||||||
"/images/",
|
"/images/",
|
||||||
"/favicon.ico",
|
|
||||||
"/js/",
|
"/js/",
|
||||||
"/webjars/",
|
"/webjars/",
|
||||||
"/requests",
|
"/requests",
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
server.error.include-stacktrace=always
|
server.error.include-stacktrace=always
|
||||||
server.error.path=/error.html
|
server.error.path=/error.html
|
||||||
server.servlet.context-path=/WebGoat
|
server.servlet.context-path=${webgoat.context}
|
||||||
server.servlet.session.persistent=false
|
server.servlet.session.persistent=false
|
||||||
server.port=${webgoat.port:8080}
|
server.port=${webgoat.port}
|
||||||
server.address=${webgoat.host}
|
server.address=${webgoat.host}
|
||||||
webgoat.host=${WEBGOAT_HOST:127.0.0.1}
|
webgoat.host=${WEBGOAT_HOST:127.0.0.1}
|
||||||
|
webgoat.port=${WEBGOAT_PORT:8080}
|
||||||
|
webgoat.context=${WEBGOAT_CONTEXT:/WebGoat}
|
||||||
spring.application.name=WebGoat
|
spring.application.name=WebGoat
|
||||||
|
|
||||||
server.ssl.key-store-type=${WEBGOAT_KEYSTORE_TYPE:PKCS12}
|
server.ssl.key-store-type=${WEBGOAT_KEYSTORE_TYPE:PKCS12}
|
||||||
@ -27,9 +29,10 @@ logging.level.org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE=INFO
|
|||||||
logging.level.org.springframework.web=INFO
|
logging.level.org.springframework.web=INFO
|
||||||
logging.level.org.springframework=INFO
|
logging.level.org.springframework=INFO
|
||||||
logging.level.org.springframework.boot.devtools=INFO
|
logging.level.org.springframework.boot.devtools=INFO
|
||||||
logging.level.org.owasp=DEBUG
|
logging.level.org.owasp=INFO
|
||||||
logging.level.org.owasp.webgoat=DEBUG
|
logging.level.org.owasp.webgoat=INFO
|
||||||
logging.level.org.hidbernate.SQL=DEBUG
|
logging.level.org.hidbernate.SQL=INFO
|
||||||
|
|
||||||
|
|
||||||
webgoat.server.directory=${user.home}/.webgoat-${webgoat.build.version}/
|
webgoat.server.directory=${user.home}/.webgoat-${webgoat.build.version}/
|
||||||
webgoat.user.directory=${user.home}/.webgoat-${webgoat.build.version}/
|
webgoat.user.directory=${user.home}/.webgoat-${webgoat.build.version}/
|
||||||
@ -43,7 +46,8 @@ webgoat.default.language=en
|
|||||||
|
|
||||||
webwolf.host=${WEBWOLF_HOST:127.0.0.1}
|
webwolf.host=${WEBWOLF_HOST:127.0.0.1}
|
||||||
webwolf.port=${WEBWOLF_PORT:9090}
|
webwolf.port=${WEBWOLF_PORT:9090}
|
||||||
webwolf.url=http://${webwolf.host}:${webwolf.port}
|
webwolf.context=${WEBWOLF_CONTEXT:/WebWolf}
|
||||||
|
webwolf.url=http://${webwolf.host}:${webwolf.port}${webwolf.context}
|
||||||
webwolf.landingpage.url=${webwolf.url}/landing
|
webwolf.landingpage.url=${webwolf.url}/landing
|
||||||
webwolf.mail.url=${webwolf.url}/mail
|
webwolf.mail.url=${webwolf.url}/mail
|
||||||
|
|
||||||
@ -62,3 +66,7 @@ exclude.lessons=${EXCLUDE_LESSONS:none,none}
|
|||||||
management.health.db.enabled=true
|
management.health.db.enabled=true
|
||||||
management.endpoint.health.show-details=always
|
management.endpoint.health.show-details=always
|
||||||
management.endpoints.web.exposure.include=env, health,configprops
|
management.endpoints.web.exposure.include=env, health,configprops
|
||||||
|
|
||||||
|
spring.security.oauth2.client.registration.github.client-id=${WEBGOAT_OAUTH_CLIENTID:dummy}
|
||||||
|
spring.security.oauth2.client.registration.github.client-secret=${WEBGOAT_OAUTH_CLIENTSECRET:dummy}
|
||||||
|
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
server.error.include-stacktrace=always
|
server.error.include-stacktrace=always
|
||||||
server.error.path=/error.html
|
server.error.path=/error.html
|
||||||
server.port=${webwolf.port:9090}
|
server.servlet.context-path=${webwolf.context}
|
||||||
|
server.port=${webwolf.port}
|
||||||
server.address=${webwolf.host}
|
server.address=${webwolf.host}
|
||||||
spring.application.name=WebWolf
|
spring.application.name=WebWolf
|
||||||
|
|
||||||
webwolf.host=${WEBWOLF_HOST:127.0.0.1}
|
webwolf.host=${WEBWOLF_HOST:127.0.0.1}
|
||||||
|
webwolf.port=${WEBWOLF_PORT:9090}
|
||||||
|
webwolf.context=${WEBWOLF_CONTEXT:/WebWolf}
|
||||||
|
|
||||||
management.server.port=-1
|
management.server.port=-1
|
||||||
server.servlet.session.cookie.name=WEBWOLFSESSION
|
server.servlet.session.cookie.name=WEBWOLFSESSION
|
||||||
@ -47,3 +50,6 @@ spring.jackson.serialization.write-dates-as-timestamps=false
|
|||||||
|
|
||||||
#For static file refresh ... and faster dev :D
|
#For static file refresh ... and faster dev :D
|
||||||
spring.devtools.restart.additional-paths=webwolf/src/main/resources/static/
|
spring.devtools.restart.additional-paths=webwolf/src/main/resources/static/
|
||||||
|
|
||||||
|
spring.security.oauth2.client.registration.github.client-id=${WEBWOLF_OAUTH_CLIENTID:dummy}
|
||||||
|
spring.security.oauth2.client.registration.github.client-secret=${WEBWOLF_OAUTH_CLIENTSECRET:dummy}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<form class="attack-form" accept-charset="UNKNOWN" id="verify-account-form"
|
<form class="attack-form" accept-charset="UNKNOWN" id="verify-account-form"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
successCallback="onBypassResponse"
|
successCallback="onBypassResponse"
|
||||||
action="/WebGoat/auth-bypass/verify-account">
|
action="auth-bypass/verify-account">
|
||||||
<p>Verify Your Account by answering the questions below:</p>
|
<p>Verify Your Account by answering the questions below:</p>
|
||||||
|
|
||||||
<p>What is the name of your favorite teacher?</p>
|
<p>What is the name of your favorite teacher?</p>
|
||||||
@ -43,7 +43,7 @@
|
|||||||
<form class="attack-form" accept-charset="UNKNOWN" id="change-password-form"
|
<form class="attack-form" accept-charset="UNKNOWN" id="change-password-form"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
successCallback="onBypassResponse"
|
successCallback="onBypassResponse"
|
||||||
action="/WebGoat/auth-bypass/verify-account"
|
action="auth-bypass/verify-account"
|
||||||
style="display:none"><!-- start off hidden -->
|
style="display:none"><!-- start off hidden -->
|
||||||
<p>Please provide a new password for your account</p>
|
<p>Please provide a new password for your account</p>
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ var onViewProfile = function () {
|
|||||||
console.warn("on view profile activated")
|
console.warn("on view profile activated")
|
||||||
webgoat.customjs.jquery.ajax({
|
webgoat.customjs.jquery.ajax({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: "/WebGoat/IDOR/profile",
|
url: "IDOR/profile",
|
||||||
contentType: 'application/json; charset=UTF-8'
|
contentType: 'application/json; charset=UTF-8'
|
||||||
}).then(webgoat.customjs.idorViewProfile);
|
}).then(webgoat.customjs.idorViewProfile);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" name="fieldRestrictions"
|
<form class="attack-form" accept-charset="UNKNOWN" name="fieldRestrictions"
|
||||||
method="POST"
|
method="POST"
|
||||||
action="/WebGoat/BypassRestrictions/FieldRestrictions">
|
action="BypassRestrictions/FieldRestrictions">
|
||||||
|
|
||||||
<div class="bypass-input-container"><b>Select field with two possible value</b>
|
<div class="bypass-input-container"><b>Select field with two possible value</b>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
@ -66,7 +66,7 @@
|
|||||||
<form class="attack-form" accept-charset="UNKNOWN" name="frontendValidation"
|
<form class="attack-form" accept-charset="UNKNOWN" name="frontendValidation"
|
||||||
id="frontendValidation"
|
id="frontendValidation"
|
||||||
method="POST"
|
method="POST"
|
||||||
action="/WebGoat/BypassRestrictions/frontendValidation/"
|
action="BypassRestrictions/frontendValidation"
|
||||||
onsubmit="return validate()">
|
onsubmit="return validate()">
|
||||||
<div>
|
<div>
|
||||||
<strong>Field 1:</strong> exactly three lowercase characters(^[a-z]{3}$)
|
<strong>Field 1:</strong> exactly three lowercase characters(^[a-z]{3}$)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
The challenges contain more a CTF like lessons where we do not provide any explanations what you need to do, no hints
|
The challenges contain more a CTF like lessons where we do not provide any explanations what you need to do, no hints
|
||||||
will be provided. You can use these challenges in a CTF style where you can run WebGoat on one server and all
|
will be provided. You can use these challenges in a CTF style where you can run WebGoat on one server and all
|
||||||
participants can join and hack the challenges. A scoreboard is available at link:/WebGoat/scoreboard["/WebGoat/scoreboard",window=_blank]
|
participants can join and hack the challenges. A scoreboard is available at link:scoreboard["scoreboard",window=_blank]
|
||||||
|
|
||||||
:hardbreaks:
|
:hardbreaks:
|
||||||
In this CTF you will need to solve a couple of challenges, each challenge will give you a flag which you will
|
In this CTF you will need to solve a couple of challenges, each challenge will give you a flag which you will
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/challenge/1"
|
action="challenge/1"
|
||||||
style="width: 200px;">
|
style="width: 200px;">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -37,7 +37,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/challenge/flag">
|
<form class="attack-form" method="POST" name="form" action="challenge/flag">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/challenge/5" role="form">
|
action="challenge/5" role="form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" name="username_login" id="username4" tabindex="1"
|
<input type="text" name="username_login" id="username4" tabindex="1"
|
||||||
class="form-control" placeholder="Username" value=""/>
|
class="form-control" placeholder="Username" value=""/>
|
||||||
@ -66,7 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/challenge/flag">
|
<form class="attack-form" method="POST" name="form" action="challenge/flag">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/challenge/6" role="form">
|
action="challenge/6" role="form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" name="username_login" id="username4" tabindex="1"
|
<input type="text" name="username_login" id="username4" tabindex="1"
|
||||||
class="form-control" placeholder="Username" value=""/>
|
class="form-control" placeholder="Username" value=""/>
|
||||||
@ -64,7 +64,7 @@
|
|||||||
</form>
|
</form>
|
||||||
<form id="register-form" class="attack-form" accept-charset="UNKNOWN"
|
<form id="register-form" class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="PUT" name="form"
|
method="PUT" name="form"
|
||||||
action="/WebGoat/challenge/6" style="display: none;" role="form">
|
action="challenge/6" style="display: none;" role="form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" name="username_reg" id="username" tabindex="1"
|
<input type="text" name="username_reg" id="username" tabindex="1"
|
||||||
class="form-control" placeholder="Username" value=""/>
|
class="form-control" placeholder="Username" value=""/>
|
||||||
@ -99,7 +99,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/challenge/flag">
|
<form class="attack-form" method="POST" name="form" action="challenge/flag">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
||||||
|
@ -28,7 +28,7 @@ f94008f801fceb8833a30fe56a8b26976347edcf First version of WebGoat Cloud website
|
|||||||
|
|
||||||
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/challenge/7" role="form">
|
action="challenge/7" role="form">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
@ -43,7 +43,7 @@ f94008f801fceb8833a30fe56a8b26976347edcf First version of WebGoat Cloud website
|
|||||||
value="Reset Password" type="submit"/>
|
value="Reset Password" type="submit"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<p>(c) 2017 WebGoat Cloud Platform</p>
|
<p>(c) 2023 WebGoat Cloud Platform</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="hidden" class="hide" name="token" id="token" value=""/>
|
<input type="hidden" class="hide" name="token" id="token" value=""/>
|
||||||
@ -57,7 +57,7 @@ f94008f801fceb8833a30fe56a8b26976347edcf First version of WebGoat Cloud website
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/challenge/flag">
|
<form class="attack-form" method="POST" name="form" action="challenge/flag">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
||||||
|
@ -231,7 +231,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/challenge/flag">
|
<form class="attack-form" method="POST" name="form" action="challenge/flag">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
||||||
|
@ -24,7 +24,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>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="DOMFollowUp"
|
method="POST" name="DOMFollowUp"
|
||||||
action="/WebGoat/ChromeDevTools/dummy">
|
action="ChromeDevTools/dummy">
|
||||||
<input name="successMessage" value="" type="TEXT" />
|
<input name="successMessage" value="" type="TEXT" />
|
||||||
<input name="submitMessage" value="Submit" type="SUBMIT"/>
|
<input name="submitMessage" value="Submit" type="SUBMIT"/>
|
||||||
</form>
|
</form>
|
||||||
@ -45,7 +45,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>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/ChromeDevTools/network">
|
action="ChromeDevTools/network">
|
||||||
<script>
|
<script>
|
||||||
// sample custom javascript in the recommended way ...
|
// sample custom javascript in the recommended way ...
|
||||||
// a namespace has been assigned for it, but you can roll your own if you prefer
|
// a namespace has been assigned for it, but you can roll your own if you prefer
|
||||||
@ -66,7 +66,7 @@
|
|||||||
|
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/ChromeDevTools/network">
|
action="ChromeDevTools/network">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>What is the number you found: </td>
|
<td>What is the number you found: </td>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<input type="hidden" id="user_id" value="102"/>
|
<input type="hidden" id="user_id" value="102"/>
|
||||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" method="POST" name="form"
|
<form class="attack-form" accept-charset="UNKNOWN" method="POST" name="form"
|
||||||
action="/WebGoat/clientSideFiltering/attack1">
|
action="clientSideFiltering/attack1">
|
||||||
<link rel="stylesheet" type="text/css"
|
<link rel="stylesheet" type="text/css"
|
||||||
th:href="@{/lesson_css/clientSideFiltering-stage1.css}"/>
|
th:href="@{/lesson_css/clientSideFiltering-stage1.css}"/>
|
||||||
<script th:src="@{/lesson_js/clientSideFiltering.js}"
|
<script th:src="@{/lesson_js/clientSideFiltering.js}"
|
||||||
@ -83,7 +83,7 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/clientSideFiltering/getItForFree">
|
action="clientSideFiltering/getItForFree">
|
||||||
|
|
||||||
<input id="discount" type="hidden" value="0"/>
|
<input id="discount" type="hidden" value="0"/>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -14,19 +14,19 @@ endif::[]
|
|||||||
|
|
||||||
The goal is to get familiar with the following forms of techniques:
|
The goal is to get familiar with the following forms of techniques:
|
||||||
|
|
||||||
* link:start.mvc#lesson/Crypto.lesson/1[Encoding]
|
* link:start.mvc#lesson/Cryptography.lesson/1[Encoding]
|
||||||
|
|
||||||
* link:start.mvc#lesson/Crypto.lesson/3[Hashing]
|
* link:start.mvc#lesson/Cryptography.lesson/3[Hashing]
|
||||||
|
|
||||||
* link:start.mvc#lesson/Crypto.lesson/4[Encryption]
|
* link:start.mvc#lesson/Cryptography.lesson/4[Encryption]
|
||||||
|
|
||||||
* link:start.mvc#lesson/Crypto.lesson/5[Signing]
|
* link:start.mvc#lesson/Cryptography.lesson/5[Signing]
|
||||||
|
|
||||||
* link:start.mvc#lesson/Crypto.lesson/6[Keystores]
|
* link:start.mvc#lesson/Cryptography.lesson/6[Keystores]
|
||||||
|
|
||||||
* link:start.mvc#lesson/Crypto.lesson/7[Security defaults]
|
* link:start.mvc#lesson/Cryptography.lesson/7[Security defaults]
|
||||||
|
|
||||||
* link:start.mvc#lesson/Crypto.lesson/8[Post quantum crypto]
|
* link:start.mvc#lesson/Cryptography.lesson/8[Post quantum crypto]
|
||||||
|
|
||||||
=== Assignments
|
=== Assignments
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
* JavaScript to load initial assignment tokens
|
* JavaScript to load initial assignment tokens
|
||||||
*/
|
*/
|
||||||
function initialise() {
|
function initialise() {
|
||||||
$("#sha256token").load('/WebGoat/crypto/hashing/sha256');
|
$("#sha256token").load('crypto/hashing/sha256');
|
||||||
$("#md5token").load('/WebGoat/crypto/hashing/md5');
|
$("#md5token").load('crypto/hashing/md5');
|
||||||
$("#basicauthtoken").load('/WebGoat/crypto/encoding/basic');
|
$("#basicauthtoken").load('crypto/encoding/basic');
|
||||||
$("#privatekey").load('/WebGoat/crypto/signing/getprivate');
|
$("#privatekey").load('crypto/signing/getprivate');
|
||||||
}
|
}
|
||||||
$(document).ready(initialise);
|
$(document).ready(initialise);
|
||||||
</script>
|
</script>
|
||||||
@ -28,7 +28,7 @@ $(document).ready(initialise);
|
|||||||
<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>
|
||||||
Now suppose you have intercepted the following header:<br/>
|
Now suppose you have intercepted the following header:<br/>
|
||||||
<div id="basicauthtoken" ></div><br/>
|
<div id="basicauthtoken" ></div><br/>
|
||||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/crypto/encoding/basic-auth">
|
<form class="attack-form" method="POST" name="form" action="crypto/encoding/basic-auth">
|
||||||
Then what was the username
|
Then what was the username
|
||||||
<input name="answer_user" value="" type="TEXT"/>
|
<input name="answer_user" value="" type="TEXT"/>
|
||||||
and what was the password:
|
and what was the password:
|
||||||
@ -45,7 +45,7 @@ $(document).ready(initialise);
|
|||||||
<!-- 3. assignment xor -->
|
<!-- 3. assignment xor -->
|
||||||
<div class="attack-container">
|
<div class="attack-container">
|
||||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/crypto/encoding/xor">
|
<form class="attack-form" method="POST" name="form" action="crypto/encoding/xor">
|
||||||
Suppose you found the database password encoded as {xor}Oz4rPj0+LDovPiwsKDAtOw==<br/>
|
Suppose you found the database password encoded as {xor}Oz4rPj0+LDovPiwsKDAtOw==<br/>
|
||||||
What would be the actual password
|
What would be the actual password
|
||||||
<input name="answer_pwd1" value="" type="TEXT"/><br/>
|
<input name="answer_pwd1" value="" type="TEXT"/><br/>
|
||||||
@ -62,7 +62,7 @@ $(document).ready(initialise);
|
|||||||
<!-- 4. weak hashing exercise -->
|
<!-- 4. weak hashing exercise -->
|
||||||
<div class="attack-container">
|
<div class="attack-container">
|
||||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/crypto/hashing">
|
<form class="attack-form" method="POST" name="form" action="crypto/hashing">
|
||||||
Which password belongs to this hash: <div id="md5token" ></div>
|
Which password belongs to this hash: <div id="md5token" ></div>
|
||||||
<input name="answer_pwd1" value="" type="TEXT"/><br/>
|
<input name="answer_pwd1" value="" type="TEXT"/><br/>
|
||||||
Which password belongs to this hash: <div id="sha256token" ></div>
|
Which password belongs to this hash: <div id="sha256token" ></div>
|
||||||
@ -87,7 +87,7 @@ $(document).ready(initialise);
|
|||||||
<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>
|
||||||
Now suppose you have the following private key:<br/>
|
Now suppose you have the following private key:<br/>
|
||||||
<pre><div id="privatekey" ></div></pre><br/>
|
<pre><div id="privatekey" ></div></pre><br/>
|
||||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/crypto/signing/verify">
|
<form class="attack-form" method="POST" name="form" action="crypto/signing/verify">
|
||||||
Then what was the modulus of the public key
|
Then what was the modulus of the public key
|
||||||
<input name="modulus" value="" type="TEXT"/>
|
<input name="modulus" value="" type="TEXT"/>
|
||||||
and now provide a signature for us based on that modulus
|
and now provide a signature for us based on that modulus
|
||||||
@ -110,7 +110,7 @@ $(document).ready(initialise);
|
|||||||
<!-- 8. assignment -->
|
<!-- 8. assignment -->
|
||||||
<div class="attack-container">
|
<div class="attack-container">
|
||||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/crypto/secure/defaults">
|
<form class="attack-form" method="POST" name="form" action="crypto/secure/defaults">
|
||||||
What is the unencrypted message<br/>
|
What is the unencrypted message<br/>
|
||||||
<input name="secretText" value="" type="TEXT"/><br/>
|
<input name="secretText" value="" type="TEXT"/><br/>
|
||||||
and what is the name of the file that stored the password <br/>
|
and what is the name of the file that stored the password <br/>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
method="POST" name="form1"
|
method="POST" name="form1"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
successCallback=""
|
successCallback=""
|
||||||
action="/WebGoat/csrf/basic-get-flag">
|
action="csrf/basic-get-flag">
|
||||||
<input name="csrf" type="hidden" value="false"/>
|
<input name="csrf" type="hidden" value="false"/>
|
||||||
<input type="submit" name="submit"/>
|
<input type="submit" name="submit"/>
|
||||||
|
|
||||||
@ -35,7 +35,7 @@
|
|||||||
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-1"
|
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-1"
|
||||||
method="POST" name="form2"
|
method="POST" name="form2"
|
||||||
successCallback=""
|
successCallback=""
|
||||||
action="/WebGoat/csrf/confirm-flag-1">
|
action="csrf/confirm-flag-1">
|
||||||
|
|
||||||
Confirm Flag Value:
|
Confirm Flag Value:
|
||||||
<input type="text" length="6" name="confirmFlagVal" value=""/>
|
<input type="text" length="6" name="confirmFlagVal" value=""/>
|
||||||
@ -93,7 +93,7 @@
|
|||||||
<form class="attack-form" accept-charset="UNKNOWN" id="csrf-review"
|
<form class="attack-form" accept-charset="UNKNOWN" id="csrf-review"
|
||||||
method="POST" name="review-form"
|
method="POST" name="review-form"
|
||||||
successCallback=""
|
successCallback=""
|
||||||
action="/WebGoat/csrf/review">
|
action="csrf/review">
|
||||||
<input class="form-control" id="reviewText" name="reviewText" placeholder="Add a Review"
|
<input class="form-control" id="reviewText" name="reviewText" placeholder="Add a Review"
|
||||||
type="text"/>
|
type="text"/>
|
||||||
<input class="form-control" id="reviewStars" name="stars" type="text"/>
|
<input class="form-control" id="reviewStars" name="stars" type="text"/>
|
||||||
@ -146,7 +146,7 @@
|
|||||||
<form class="attack-form" accept-charset="UNKNOWN" id="csrf-feedback"
|
<form class="attack-form" accept-charset="UNKNOWN" id="csrf-feedback"
|
||||||
method="POST"
|
method="POST"
|
||||||
prepareData="feedback"
|
prepareData="feedback"
|
||||||
action="/WebGoat/csrf/feedback/message"
|
action="csrf/feedback/message"
|
||||||
contentType="application/json">
|
contentType="application/json">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@ -212,7 +212,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-feedback"
|
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-feedback"
|
||||||
method="POST" name="form2"
|
method="POST" name="form2"
|
||||||
action="/WebGoat/csrf/feedback">
|
action="csrf/feedback">
|
||||||
|
|
||||||
Confirm Flag Value:
|
Confirm Flag Value:
|
||||||
<input type="text" length="6" name="confirmFlagVal" value=""/>
|
<input type="text" length="6" name="confirmFlagVal" value=""/>
|
||||||
@ -236,7 +236,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-login"
|
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-login"
|
||||||
method="POST" name="form2"
|
method="POST" name="form2"
|
||||||
action="/WebGoat/csrf/login">
|
action="csrf/login">
|
||||||
|
|
||||||
Press the button below when your are logged in as the other user<br/>
|
Press the button below when your are logged in as the other user<br/>
|
||||||
|
|
||||||
|
@ -25,7 +25,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>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
||||||
method="POST"
|
method="POST"
|
||||||
action="/WebGoat/InsecureDeserialization/task">
|
action="InsecureDeserialization/task">
|
||||||
|
|
||||||
<input type="textarea" rows="4" cols="40" value="" name="token" placeholder="token"/>
|
<input type="textarea" rows="4" cols="40" value="" name="token" placeholder="token"/>
|
||||||
<input type="submit" value="Submit" />
|
<input type="submit" value="Submit" />
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div th:include="/lessons/hijacksession/templates/hijackform.html" id="content"></div>
|
<div th:insert="~{/lessons/hijacksession/templates/hijackform.html}" id="content"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="attack-feedback"></div>
|
<div class="attack-feedback"></div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" method="POST"
|
<form class="attack-form" accept-charset="UNKNOWN" method="POST"
|
||||||
action="/WebGoat/HijackSession/login">
|
action="HijackSession/login">
|
||||||
<div style="padding: 20px;" id="password-login">
|
<div style="padding: 20px;" id="password-login">
|
||||||
<h4 style="border-bottom: 1px solid #c5c5c5;">Account Access</h4>
|
<h4 style="border-bottom: 1px solid #c5c5c5;">Account Access</h4>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
@ -13,7 +13,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>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" id="task" name="task"
|
<form class="attack-form" accept-charset="UNKNOWN" id="task" name="task"
|
||||||
method="POST"
|
method="POST"
|
||||||
action="/WebGoat/HtmlTampering/task">
|
action="HtmlTampering/task">
|
||||||
<script>
|
<script>
|
||||||
var regex = /^2999.99$/;
|
var regex = /^2999.99$/;
|
||||||
var price = 2999.99;
|
var price = 2999.99;
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/HttpBasics/attack1">
|
action="HttpBasics/attack1">
|
||||||
<div id="lessonContent">
|
<div id="lessonContent">
|
||||||
<form accept-charset="UNKNOWN" method="POST" name="form"
|
<form accept-charset="UNKNOWN" method="POST" name="form"
|
||||||
action="#attack/307/100">
|
action="#attack/307/100">
|
||||||
@ -51,7 +51,7 @@
|
|||||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/HttpBasics/attack2">
|
action="HttpBasics/attack2">
|
||||||
<script>
|
<script>
|
||||||
// sample custom javascript in the recommended way ...
|
// sample custom javascript in the recommended way ...
|
||||||
// a namespace has been assigned for it, but you can roll your own if you prefer
|
// a namespace has been assigned for it, but you can roll your own if you prefer
|
||||||
|
@ -24,7 +24,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>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" name="intercept-request"
|
<form class="attack-form" accept-charset="UNKNOWN" name="intercept-request"
|
||||||
method="POST"
|
method="POST"
|
||||||
action="/WebGoat/HttpProxies/intercept-request">
|
action="HttpProxies/intercept-request">
|
||||||
|
|
||||||
<input type="text" value="doesn't matter really" name="changeMe" />
|
<input type="text" value="doesn't matter really" name="changeMe" />
|
||||||
<input type="submit" value="Submit" />
|
<input type="submit" value="Submit" />
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
<!-- modify the action to point to the intended endpoint -->
|
<!-- modify the action to point to the intended endpoint -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/IDOR/login">
|
action="IDOR/login">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>user/pass</td>
|
<td>user/pass</td>
|
||||||
@ -57,7 +57,7 @@
|
|||||||
<!-- modify the action to point to the intended endpoint -->
|
<!-- modify the action to point to the intended endpoint -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="GET" name="form"
|
method="GET" name="form"
|
||||||
action="/WebGoat/IDOR/profile">
|
action="IDOR/profile">
|
||||||
<script th:src="@{/lesson_js/idor.js}" />
|
<script th:src="@{/lesson_js/idor.js}" />
|
||||||
|
|
||||||
<input name="View Profile" value="View Profile" type="button" onclick="onViewProfile();" />
|
<input name="View Profile" value="View Profile" type="button" onclick="onViewProfile();" />
|
||||||
@ -107,7 +107,7 @@
|
|||||||
<!-- modify the action to point to the intended endpoint -->
|
<!-- modify the action to point to the intended endpoint -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/IDOR/profile/alt-path">
|
action="IDOR/profile/alt-path">
|
||||||
<div class="adoc-content" th:replace="~{doc:lessons/idor/documentation/IDOR_inputAltPath.adoc}"></div>
|
<div class="adoc-content" th:replace="~{doc:lessons/idor/documentation/IDOR_inputAltPath.adoc}"></div>
|
||||||
<input name="url" value="WebGoat/" type="text"/>
|
<input name="url" value="WebGoat/" type="text"/>
|
||||||
<input name="submit" value="Submit" type="SUBMIT"/>
|
<input name="submit" value="Submit" type="SUBMIT"/>
|
||||||
@ -134,7 +134,7 @@
|
|||||||
<!-- modify the action to point to the intended endpoint -->
|
<!-- modify the action to point to the intended endpoint -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" id="view-other"
|
<form class="attack-form" accept-charset="UNKNOWN" id="view-other"
|
||||||
method="GET" name="view-other-profile"
|
method="GET" name="view-other-profile"
|
||||||
action="/WebGoat/IDOR/profile/{userId}">
|
action="IDOR/profile/{userId}">
|
||||||
<script th:src="@{/lesson_js/idor.js}" />
|
<script th:src="@{/lesson_js/idor.js}" />
|
||||||
|
|
||||||
<input name="View Profile" value="View Profile" type="submit" />
|
<input name="View Profile" value="View Profile" type="submit" />
|
||||||
@ -158,7 +158,7 @@
|
|||||||
<!-- modify the action to point to the intended endpoint -->
|
<!-- modify the action to point to the intended endpoint -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" id="edit-other"
|
<form class="attack-form" accept-charset="UNKNOWN" id="edit-other"
|
||||||
method="GET" name="edit-other-profile"
|
method="GET" name="edit-other-profile"
|
||||||
action="/WebGoat/IDOR/profile/{userId}">
|
action="IDOR/profile/{userId}">
|
||||||
<script th:src="@{/lesson_js/idor.js}" />
|
<script th:src="@{/lesson_js/idor.js}" />
|
||||||
|
|
||||||
<input name="View Profile" value="View Profile" type="submit" />
|
<input name="View Profile" value="View Profile" type="submit" />
|
||||||
|
@ -12,7 +12,7 @@ var onViewProfile = function () {
|
|||||||
console.warn("on view profile activated")
|
console.warn("on view profile activated")
|
||||||
webgoat.customjs.jquery.ajax({
|
webgoat.customjs.jquery.ajax({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: "/WebGoat/IDOR/profile",
|
url: "IDOR/profile",
|
||||||
contentType: 'application/json; charset=UTF-8'
|
contentType: 'application/json; charset=UTF-8'
|
||||||
}).then(webgoat.customjs.idorViewProfile);
|
}).then(webgoat.customjs.idorViewProfile);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<script th:src="@{/lesson_js/credentials.js}"></script>
|
<script th:src="@{/lesson_js/credentials.js}"></script>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
||||||
method="POST"
|
method="POST"
|
||||||
action="/WebGoat/InsecureLogin/task">
|
action="InsecureLogin/task">
|
||||||
|
|
||||||
<button onclick="javascript:submit_secret_credentials();return false;">Log in</button>
|
<button onclick="javascript:submit_secret_credentials();return false;">Log in</button>
|
||||||
|
|
||||||
@ -25,7 +25,7 @@
|
|||||||
<br></br>
|
<br></br>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
||||||
method="POST"
|
method="POST"
|
||||||
action="/WebGoat/InsecureLogin/task">
|
action="InsecureLogin/task">
|
||||||
|
|
||||||
<input type="text" value="" name="username" placeholder="username"/>
|
<input type="text" value="" name="username" placeholder="username"/>
|
||||||
<input type="password" value="" name="password" placeholder="password" />
|
<input type="password" value="" name="password" placeholder="password" />
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
== Attacks
|
||||||
|
|
||||||
|
JSON Web Tokens (JWTs) have gained popularity for securely transmitting information between parties. However, like any technology, they are not immune to certain vulnerabilities and attacks. Here's an overview of various JWT attacks:
|
||||||
|
|
||||||
|
- **Token expiration manipulation**: JWTs typically contain an "exp" claim indicating the expiration time. An attacker might try to manipulate this claim to extend the validity of a token, allowing them to continue using it even after its intended expiration.
|
||||||
|
|
||||||
|
- **Token tampering**: Attackers may try to modify the token's contents, such as claims in the payload or header, to impersonate other users, gain unauthorized access, or modify permissions.
|
||||||
|
|
||||||
|
- **Token leakage**: If JWTs are not securely stored on the client side (e.g., in a cookie, local storage), they might be susceptible to cross-site scripting (XSS) attacks, leading to token leakage and potential unauthorized access.
|
||||||
|
|
||||||
|
- **Brute force attacks**: Since JWTs are self-contained, an attacker could attempt to brute force the signature by trying various combinations of secret keys to forge a valid signature.
|
||||||
|
|
||||||
|
- **Key confusion attack**: If the "kid" (key ID) claim is misused or not properly validated, an attacker could manipulate it to use a different key for signature verification, leading to unauthorized access.
|
||||||
|
|
||||||
|
- **Replay attacks**: An attacker might capture a valid JWT and use it multiple times within its validity period to impersonate the original user or repeat a specific action.
|
||||||
|
|
||||||
|
- **Token side jacking**: If JWTs are transmitted over insecure channels (e.g., unencrypted HTTP), attackers can intercept and steal them, gaining unauthorized access to user accounts.
|
||||||
|
|
||||||
|
- **Algorithm downgrade attack**: An attacker might attempt to change the "alg" claim in the header to force the use of a weaker cryptographic algorithm.
|
||||||
|
|
||||||
|
- **Token forgery**: Attackers could craft their JWTs, potentially bypassing authentication or authorization checks if validation is not robust.
|
||||||
|
|
||||||
|
- **Clock tampering**: If the server's clock can be manipulated, attackers might change the server time to extend the validity of expired tokens.
|
||||||
|
|
||||||
|
This lesson will contain some common attacks, giving you an insight into what can go wrong and how you can protect yourself against them.
|
@ -0,0 +1,21 @@
|
|||||||
|
== JWT claim misuse
|
||||||
|
|
||||||
|
JWT claim misuse refers to the improper or unauthorized manipulation of the claims within a JSON Web Token (JWT). A JWT is a compact and self-contained way to represent information between two parties. It consists of the header, the payload (claims), and the signature.
|
||||||
|
|
||||||
|
JWT claim misuse can happen in different ways:
|
||||||
|
|
||||||
|
- **Unauthorized claims**: A malicious user might try to add unauthorized claims to a JWT to gain access to certain features or resources they are not entitled to—for example, a regular user attempts to modify their JWT to claim administrator privileges.
|
||||||
|
|
||||||
|
- **Tampering claims**: An attacker might try to modify the values of existing claims in the JWT to manipulate their own identity or alter their permissions. For instance, they are changing the "user_id" claim to impersonate a different user.
|
||||||
|
|
||||||
|
- **Excessive claims**: An attacker could try to include many unnecessary or fake claims in a JWT to increase the token size and possibly disrupt the system's performance or cause other issues.
|
||||||
|
|
||||||
|
- **Expired or altered expiration claims**: If an attacker can modify the "exp" claim to extend the token's expiration time, they can effectively gain access beyond their intended session.
|
||||||
|
|
||||||
|
- **Replay attacks**: An attacker might try to reuse a valid JWT from an old session to impersonate the original user or exploit time-limited functionality.
|
||||||
|
|
||||||
|
- **Key claim manipulation**: In some cases, the "kid" (key ID) claim may be misused, as explained in the previous answer. An attacker might try manipulating the "kid" claim to use a different key for signature verification.
|
||||||
|
|
||||||
|
To prevent JWT claim misuse, it is essential to implement proper validation and verification mechanisms on both the client and server sides. Validate the claims to ensure they are valid, authorized, and relevant to the user's context. Additionally, always verify the signature of the JWT to ensure the token's integrity and protect against tampering. Following best practices for JWT implementation, secure key management, and regular key rotation will also help mitigate the risk of JWT claim misuse.
|
||||||
|
|
||||||
|
In the following two sections, we will dive into some examples of header claim misuses to give you an idea of how they work and how to protect an application.
|
@ -0,0 +1,59 @@
|
|||||||
|
== Claim misuse
|
||||||
|
|
||||||
|
Header claims misuse can occur when the header information is tampered with or manipulated inappropriately
|
||||||
|
|
||||||
|
=== JSON Web Key URL (JKU)
|
||||||
|
|
||||||
|
JKU is a part of the JWT specification that allows the JWT consumer to obtain the public key needed to verify the token's signature dynamically.
|
||||||
|
It is a URL that points to a JSON Web Key Set (JWKS) endpoint, which contains the public keys used by the issuer to sign the JWTs.
|
||||||
|
|
||||||
|
An example JKU would look like this:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
{
|
||||||
|
"jku": "https://example.com/.well-known/jwks.json"
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
=== Vulnerability
|
||||||
|
|
||||||
|
JWT claim misuse with JKU The vulnerability arises when a JWT is signed with a weak or predictable key and the server provides a JKU that points to an external location hosting the public key.
|
||||||
|
|
||||||
|
Attackers can exploit this vulnerability by crafting a JWT with malicious claims and using the `jku` to trick the server into verifying the JWT using a weak or manipulated key.
|
||||||
|
It all depends on the library being used inside the application.
|
||||||
|
Some libraries block downloading from a random server by default and use a list of allowed URLs.
|
||||||
|
However, filtering on URLs is quite challenging to implement, and this can be bypassed as well.
|
||||||
|
|
||||||
|
==== Exploitation Steps:
|
||||||
|
|
||||||
|
- **Identify the JKU Endpoint**: The attacker first needs to find the JKU endpoint in the application's JWT handling logic or in any exposed configurations.
|
||||||
|
|
||||||
|
- **Generate a malicious JWT**: craft a JWT with malicious claims, altering or adding claims to gain unauthorized access or escalate privileges.
|
||||||
|
|
||||||
|
- **Sign the JWT**: Using your own private key sign the malicious JWT.
|
||||||
|
|
||||||
|
- **Send the JWT to the server**: Send the crafted JWT with the malicious claims to the server.
|
||||||
|
|
||||||
|
- **Server verification**: The server, upon receiving the JWT, validates the signature using the public key obtained from the JWKS endpoint.
|
||||||
|
|
||||||
|
- **Successful attack**: If the server uses the weak or manipulated key to verify the JWT, the attacker gains unauthorized access or executes their intended exploit.
|
||||||
|
|
||||||
|
=== Mitigation
|
||||||
|
|
||||||
|
To prevent JWT claim misuse with JKU, developers and security professionals should follow these best practices:
|
||||||
|
|
||||||
|
- **Whitelist**: utilize a whitelist to verify whether the received JKU from the token is present in the allowed list.
|
||||||
|
Be careful when comparing urls by using String comparison functions, use a whitelist instead and validate the entire url from the `jku`.
|
||||||
|
|
||||||
|
- **Static keys**: Avoid using JKU with public keys hosted on external endpoints.
|
||||||
|
Instead, use static keys that are securely managed and updated regularly.
|
||||||
|
|
||||||
|
- **Signature verification**: Ensure that the server verifies the JWT signature correctly and rejects tokens with invalid or manipulated signatures.
|
||||||
|
|
||||||
|
- **JWT validation**: Carefully validate and sanitize all JWT claims to prevent injection attacks and unauthorized access.
|
||||||
|
|
||||||
|
- **Audit and monitoring**: Regularly audit JWT usage, monitor for suspicious activity, and implement anomaly detection mechanisms.
|
||||||
|
|
||||||
|
- **Security testing**: Regularly perform security testing, including penetration testing and code reviews, to identify and remediate potential vulnerabilities.
|
||||||
|
|
@ -1,5 +1,4 @@
|
|||||||
== Final challenge
|
== Try it out...
|
||||||
|
|
||||||
Below you see two accounts, one of Jerry and one of Tom. Jerry wants to remove Tom's account from Twitter, but his token
|
Below you see two accounts, one of Jerry and one of Tom. Jerry wants to remove Tom's account from Twitter, but his token
|
||||||
can only delete his account. Can you try to help him and delete Toms account?
|
can only delete his account. Can you try to help him and delete Toms account?
|
||||||
|
|
@ -0,0 +1,73 @@
|
|||||||
|
== Claim misuse
|
||||||
|
|
||||||
|
Next, we will explore the security implications of misusing the Key ID (`kid`) claim in JSON Web Tokens (JWT).
|
||||||
|
|
||||||
|
=== JSON Key ID (kid)
|
||||||
|
|
||||||
|
The Key ID(kid) indicates which key from a JSON Web Key Set (JWKS) should be used to verify the signature of the JWT.
|
||||||
|
When misused, attackers can exploit this vulnerability to gain unauthorized access to sensitive resources or perform privilege escalation.
|
||||||
|
|
||||||
|
An example KID would look like this:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
{
|
||||||
|
"alg": "RS256",
|
||||||
|
"kid": "my_rsa_key"
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
=== Vulnerability
|
||||||
|
|
||||||
|
When the `kid` claim is misused, it usually means that the value of "kid" is manipulated to point to a different key than the one used to sign the token.
|
||||||
|
This manipulation can lead to various security issues:
|
||||||
|
|
||||||
|
* **Key confusion attack**: In this attack, an attacker manipulates the "kid" claim value to point to a different key than the one used to sign the token.
|
||||||
|
As a result, the recipient of the JWT will verify the signature using the wrong key, allowing the attacker to impersonate other users or perform unauthorized actions.
|
||||||
|
|
||||||
|
* **Key enumeration**: If the `kid` claim is not properly protected or is simply an incrementing number or easily predictable value, an attacker might try to guess or enumerate valid "kid" values.
|
||||||
|
By doing so, they can potentially forge JWTs with different `kid` values to find vulnerabilities or weaknesses in the system.
|
||||||
|
|
||||||
|
* **Key spoofing**: In this attack, an attacker crafts a JWT with a forged `kid` claim pointing to a non-existent or invalid key.
|
||||||
|
The intention is to bypass signature verification and potentially gain unauthorized access to resources or features.
|
||||||
|
|
||||||
|
* **Key overwrite**: An attacker might try to overwrite or modify the `kid` claim during token transmission or processing to point to a different key than originally intended.
|
||||||
|
This manipulation can lead to signature verification failures or other security issues.
|
||||||
|
|
||||||
|
* **Kidless tokens**: If a system does not require the presence of the `kid` claim, an attacker could attempt to create a JWT without including the "kid" claim at all.
|
||||||
|
This omission could lead to vulnerabilities if the recipient assumes a default or known key, which may not be secure.
|
||||||
|
|
||||||
|
* **Insecure key storage**: If the "kid" claim is combined with other weak security practices, such as storing keys in plaintext or using weak encryption, an attacker might obtain valid "kid" values and exploit the associated keys.
|
||||||
|
|
||||||
|
|
||||||
|
==== Exploitation steps:
|
||||||
|
|
||||||
|
- Identify the kid endpoint: The attacker must first find the kid endpoint in the application's JWT handling logic or any exposed configurations.
|
||||||
|
|
||||||
|
- Generate a malicious JWT: craft a JWT with malicious claims, altering or adding claims to gain unauthorized access or escalate privileges.
|
||||||
|
|
||||||
|
- Generate a `kid` which enables you to know the verification key.
|
||||||
|
|
||||||
|
- Send the JWT to the Server: Send the crafted JWT with the malicious claims to the server.
|
||||||
|
|
||||||
|
- Server verification: Upon receiving the JWT, the server validates the signature using the "crafted" KID.
|
||||||
|
|
||||||
|
- Successful attack: If the server uses the weak or manipulated key to verify the JWT, the attacker gains unauthorized access or executes their intended exploit.
|
||||||
|
|
||||||
|
=== Mitigation
|
||||||
|
|
||||||
|
To prevent JWT claim misuse with KID, developers and security professionals should follow these best practices:
|
||||||
|
|
||||||
|
- Validation: always validate the "kid" claim and ensure it points to a trusted key appropriate for signature verification.
|
||||||
|
|
||||||
|
- Key rotation: regularly rotate the keys used for signing JWTs and update the corresponding "kid" claims accordingly.
|
||||||
|
|
||||||
|
- Use strong keys: ensure that strong cryptographic keys are used to sign the tokens.
|
||||||
|
|
||||||
|
- Access control: limit access to keys and signing services to authorized personnel only.
|
||||||
|
|
||||||
|
- Rate limiting: implement rate limiting to prevent attackers from iterating through possible "kid" values.
|
||||||
|
|
||||||
|
- Monitoring: monitor and log JWT-related activities to detect potential misuse or suspicious behavior.
|
||||||
|
|
||||||
|
By following these best practices, you can reduce the risk of JWT claim misuse with the "kid" field and enhance the overall security of your system.
|
@ -0,0 +1,6 @@
|
|||||||
|
== Try it out...
|
||||||
|
|
||||||
|
Below you see two accounts, one of Jerry and one of Tom.
|
||||||
|
Jerry wants to remove Tom's account from Twitter, but his token can only delete his account.
|
||||||
|
Can you try to help him and delete Toms account?
|
||||||
|
|
@ -36,3 +36,5 @@ be different including also the transport channel even if HTTP is the most often
|
|||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,11 +9,15 @@
|
|||||||
<div class="adoc-content" th:replace="~{doc:lessons/jwt/documentation/JWT_structure.adoc}"></div>
|
<div class="adoc-content" th:replace="~{doc:lessons/jwt/documentation/JWT_structure.adoc}"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="~{doc:lessons/jwt/documentation/JWT_claim_misuse.adoc}"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="lesson-page-wrapper">
|
<div class="lesson-page-wrapper">
|
||||||
<div class="adoc-content" th:replace="~{doc:lessons/jwt/documentation/JWT_decode.adoc}"></div>
|
<div class="adoc-content" th:replace="~{doc:lessons/jwt/documentation/JWT_decode.adoc}"></div>
|
||||||
<div class="attack-container">
|
<div class="attack-container">
|
||||||
<img th:src="@{/images/wolf-enabled.png}" class="webwolf-enabled"/>
|
<img th:src="@{/images/wolf-enabled.png}" class="webwolf-enabled"/>
|
||||||
<form id="decode" class="attack-form" method="POST" name="form" action="/WebGoat/JWT/decode">
|
<form id="decode" class="attack-form" method="POST" name="form" action="JWT/decode">
|
||||||
<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>
|
||||||
<br>
|
<br>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -49,7 +53,7 @@
|
|||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST"
|
method="POST"
|
||||||
successCallback="jwtSigningCallback"
|
successCallback="jwtSigningCallback"
|
||||||
action="/WebGoat/JWT/votings">
|
action="JWT/votings">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -120,7 +124,7 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<form id="quiz-form" class="attack-form" accept-charset="UNKNOWN"
|
<form id="quiz-form" class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/JWT/quiz"
|
action="JWT/quiz"
|
||||||
role="form">
|
role="form">
|
||||||
<div id="q_container"></div>
|
<div id="q_container"></div>
|
||||||
<br/>
|
<br/>
|
||||||
@ -151,7 +155,7 @@
|
|||||||
|
|
||||||
<div class="attack-container">
|
<div class="attack-container">
|
||||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/JWT/secret">
|
<form class="attack-form" method="POST" name="form" action="JWT/secret">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
||||||
@ -188,7 +192,7 @@
|
|||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST"
|
method="POST"
|
||||||
additionalHeaders="addBearerToken"
|
additionalHeaders="addBearerToken"
|
||||||
action="/WebGoat/JWT/refresh/checkout">
|
action="JWT/refresh/checkout">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 col-md-10 col-md-offset-1">
|
<div class="col-sm-12 col-md-10 col-md-offset-1">
|
||||||
@ -299,7 +303,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="lesson-page-wrapper">
|
<div class="lesson-page-wrapper">
|
||||||
<div class="adoc-content" th:replace="~{doc:lessons/jwt/documentation/JWT_final.adoc}"></div>
|
<div class="adoc-content" th:replace="~{doc:lessons/jwt/documentation/JWT_claim_misuse.adoc}"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="~{doc:lessons/jwt/documentation/JWT_claim_misuse_jku.adoc}"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="~{doc:lessons/jwt/documentation/JWT_claim_misuse_jku_assignment.adoc}"></div>
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/jwt.css}"/>
|
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/jwt.css}"/>
|
||||||
<script th:src="@{/lesson_js/bootstrap.min.js}" language="JavaScript"></script>
|
<script th:src="@{/lesson_js/bootstrap.min.js}" language="JavaScript"></script>
|
||||||
@ -307,7 +319,73 @@
|
|||||||
<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>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST"
|
method="POST"
|
||||||
action="/WebGoat/JWT/final/delete?token=eyJ0eXAiOiJKV1QiLCJraWQiOiJ3ZWJnb2F0X2tleSIsImFsZyI6IkhTMjU2In0.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJqZXJyeUB3ZWJnb2F0LmNvbSIsInVzZXJuYW1lIjoiSmVycnkiLCJFbWFpbCI6ImplcnJ5QHdlYmdvYXQuY29tIiwiUm9sZSI6WyJDYXQiXX0.CgZ27DzgVW8gzc0n6izOU638uUCi6UhiOJKYzoEZGE8">
|
action="JWT/final/delete?token=eyJ0eXAiOiJKV1QiLCJqa3UiOiJodHRwczovL2NvZ25pdG8taWRwLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tL3dlYmdvYXQvLndlbGwta25vd24vandrcy5qc29uIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJqZXJyeUB3ZWJnb2F0LmNvbSIsInVzZXJuYW1lIjoiSmVycnkiLCJFbWFpbCI6ImplcnJ5QHdlYmdvYXQuY29tIiwiUm9sZSI6WyJDYXQiXX0.SabvRaYSCW7xI0ueca19TL1e66cJIJaxRiydK2G5lgFMIbL5gQQjE6022HEha9HcprqFXyHbtXrQWRXAp6Gjaf5zs8LUMBMARWjEr8TS43ihguarmLLmvBCoqjiZY39o4EcEjEH9xAoyIYR_Trh7kXn6JVU-8MM76l9IOcYIJ9c8LqT1ERNmbCqtI4PP0tdqCy99nHhqlxSCVXaGDF0jMHV5kjCDSHNYib9riy9xZ63Sztify-bwPqRvxmaShPYtG4BBM_wOGlg-BYTTuws-6yISMfTB5U1WBDwLr6dLU123TGO26wCVBgTKbA0KKG94-ToOcneWLOTEacEfQQOlIQ">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div id="toast"></div>
|
||||||
|
<div class="col-sm-6 col-md-4 col-lg-3 mt-4">
|
||||||
|
<div class="card card-inverse card-info">
|
||||||
|
<img th:src="@{/images/jerry.png}" class="card-img-top"></img>
|
||||||
|
<div class="card-block">
|
||||||
|
<figure class="profile profile-inline">
|
||||||
|
<img th:src="@{/images/jerry.png}" class="profile-avatar" alt=""></img>
|
||||||
|
</figure>
|
||||||
|
<h4 class="card-title">Jerry</h4>
|
||||||
|
<div class="card-text">
|
||||||
|
Jerry is a small, brown, house mouse.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<small>Last updated 12 minutes ago</small>
|
||||||
|
<button class="btn btn-info float-right btn-sm">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-md-4 col-lg-3 mt-4">
|
||||||
|
<div class="card card-inverse card-info">
|
||||||
|
<img th:src="@{/images/tom.png}" class="card-img-top"></img>
|
||||||
|
<div class="card-block">
|
||||||
|
<figure class="profile profile-inline">
|
||||||
|
<img th:src="@{/images/tom.png}" class="profile-avatar" alt=""></img>
|
||||||
|
</figure>
|
||||||
|
<h4 class="card-title">Tom</h4>
|
||||||
|
<div class="card-text">
|
||||||
|
Tom is a grey and white domestic short hair cat.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<small>Last updated 12 days ago</small>
|
||||||
|
<button type="button" class="btn btn-info float-right btn-sm"
|
||||||
|
onclick="javascript:follow('Tom')">Follow
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-info float-right btn-sm">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<div class="attack-feedback"></div>
|
||||||
|
<div class="attack-output"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="~{doc:lessons/jwt/documentation/JWT_claim_misuse_kid.adoc}"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="~{doc:lessons/jwt/documentation/JWT_claim_misuse_kid_assignment.adoc}"></div>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/jwt.css}"/>
|
||||||
|
<script th:src="@{/lesson_js/bootstrap.min.js}" language="JavaScript"></script>
|
||||||
|
<div class="attack-container">
|
||||||
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
|
method="POST"
|
||||||
|
action="JWT/kid/delete?token=eyJ0eXAiOiJKV1QiLCJraWQiOiJ3ZWJnb2F0X2tleSIsImFsZyI6IkhTMjU2In0.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJqZXJyeUB3ZWJnb2F0LmNvbSIsInVzZXJuYW1lIjoiSmVycnkiLCJFbWFpbCI6ImplcnJ5QHdlYmdvYXQuY29tIiwiUm9sZSI6WyJDYXQiXX0.CgZ27DzgVW8gzc0n6izOU638uUCi6UhiOJKYzoEZGE8">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div id="toast"></div>
|
<div id="toast"></div>
|
||||||
<div class="col-sm-6 col-md-4 col-lg-3 mt-4">
|
<div class="col-sm-6 col-md-4 col-lg-3 mt-4">
|
||||||
|
@ -26,9 +26,15 @@ jwt-refresh-alg-none=Nicely found! You solved the assignment with 'alg: none' ca
|
|||||||
jwt-final-jerry-account=Yikes, you are removing Jerry's account, try to delete the account of Tom
|
jwt-final-jerry-account=Yikes, you are removing Jerry's account, try to delete the account of Tom
|
||||||
jwt-final-not-tom=Username is not Tom try to pass a token for Tom
|
jwt-final-not-tom=Username is not Tom try to pass a token for Tom
|
||||||
|
|
||||||
jwt-final-hint1=Take a look at the token and specifically and the header
|
jwt-jku-hint1=Take a look at the token and specifically and the header
|
||||||
jwt-final-hint2=The 'kid' (key ID) header parameter is a hint indicating which key was used to secure the JWS
|
jwt-jku-hint2=The 'jku' (key ID) header parameter is a hint indicating which key is used to verify the JWS
|
||||||
jwt-final-hint3=The key can be located on the filesystem in memory or even reside in the database
|
jwt-jku-hint3=Could you use WebWolf to host the public key as a JWKS?
|
||||||
jwt-final-hint4=The key is stored in the database and loaded while verifying a token
|
jwt-jku-hint4=Create a key pair and sign the token with the private key
|
||||||
jwt-final-hint5=Using a SQL injection you might be able to manipulate the key to something you know and create a new token.
|
jwt-jku-hint5=Change the JKU header claim and point it to a URL which hosts the public key in JWKS format.
|
||||||
jwt-final-hint6=Use: hacked' UNION select 'deletingTom' from INFORMATION_SCHEMA.SYSTEM_USERS -- as the kid in the header and change the contents of the token to Tom and hit the endpoint with the new token
|
|
||||||
|
jwt-kid-hint1=Take a look at the token and specifically and the header
|
||||||
|
jwt-kid-hint2=The 'kid' (key ID) header parameter is a hint indicating which key was used to secure the JWS
|
||||||
|
jwt-kid-hint3=The key can be located on the filesystem in memory or even reside in the database
|
||||||
|
jwt-kid-hint4=The key is stored in the database and loaded while verifying a token
|
||||||
|
jwt-kid-hint5=Using a SQL injection you might be able to manipulate the key to something you know and create a new token.
|
||||||
|
jwt-kid-hint6=Use: hacked' UNION select 'deletingTom' from INFORMATION_SCHEMA.SYSTEM_USERS -- as the kid in the header and change the contents of the token to Tom and hit the endpoint with the new token
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
$(document).ready(
|
$(document).ready(
|
||||||
function(){
|
function(){
|
||||||
$("#secrettoken").load('/WebGoat/JWT/secret/gettoken');
|
$("#secrettoken").load('JWT/secret/gettoken');
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -87,7 +87,7 @@ green when the user solves the assignment. To make this work we need to add to t
|
|||||||
<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>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/lesson-template/sample-attack">
|
action="lesson-template/sample-attack">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>two random params</td>
|
<td>two random params</td>
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
<!-- modify the action to point to the intended endpoint and set other attributes as desired -->
|
<!-- modify the action to point to the intended endpoint and set other attributes as desired -->
|
||||||
<form class="attack-form" accept-charset="UNKNOWN"
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
action="/WebGoat/lesson-template/sample-attack">
|
action="lesson-template/sample-attack">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>two random params</td>
|
<td>two random params</td>
|
||||||
|
@ -12,7 +12,7 @@ var onViewProfile = function () {
|
|||||||
console.warn("on view profile activated")
|
console.warn("on view profile activated")
|
||||||
webgoat.customjs.jquery.ajax({
|
webgoat.customjs.jquery.ajax({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: "/WebGoat/IDOR/profile",
|
url: "IDOR/profile",
|
||||||
contentType: 'application/json; charset=UTF-8'
|
contentType: 'application/json; charset=UTF-8'
|
||||||
}).then(webgoat.customjs.idorViewProfile);
|
}).then(webgoat.customjs.idorViewProfile);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,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>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
||||||
method="POST"
|
method="POST"
|
||||||
action="/WebGoat/LogSpoofing/log-spoofing">
|
action="LogSpoofing/log-spoofing">
|
||||||
|
|
||||||
<input type="text" value="" name="username" placeholder="username"/>
|
<input type="text" value="" name="username" placeholder="username"/>
|
||||||
<input type="password" value="" name="password" placeholder="password"/>
|
<input type="password" value="" name="password" placeholder="password"/>
|
||||||
@ -38,7 +38,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>
|
||||||
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
||||||
method="POST"
|
method="POST"
|
||||||
action="/WebGoat/LogSpoofing/log-bleeding">
|
action="LogSpoofing/log-bleeding">
|
||||||
|
|
||||||
<input type="text" value="" name="username" placeholder="username"/>
|
<input type="text" value="" name="username" placeholder="username"/>
|
||||||
<input type="password" value="" name="password" placeholder="password"/>
|
<input type="password" value="" name="password" placeholder="password"/>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user