merge of upstream, conflict resolution

This commit is contained in:
Jason White 2017-06-27 08:30:58 -04:00
commit dd18e68660
123 changed files with 5035 additions and 2080 deletions

View File

@ -42,7 +42,7 @@ addons:
project: project:
name: "WebGoat/WebGoat" name: "WebGoat/WebGoat"
description: "Coverity Scan from Travis CI Build Automation" description: "Coverity Scan from Travis CI Build Automation"
notification_email: doug.morato@owasp.org notification_email: webgoat@owasp.org
build_command_prepend: "mvn clean" build_command_prepend: "mvn clean"
build_command: "mvn -DskipTests=true package" build_command: "mvn -DskipTests=true package"
branch_pattern: coverity_scan branch_pattern: coverity_scan

View File

@ -1,7 +1,7 @@
# WebGoat: A deliberately insecure Web Application # WebGoat: A deliberately insecure Web Application
[![Build Status](https://travis-ci.org/WebGoat/WebGoat.svg?branch=develop)](https://travis-ci.org/WebGoat/WebGoat) [![Build Status](https://travis-ci.org/WebGoat/WebGoat.svg?branch=develop)](https://travis-ci.org/WebGoat/WebGoat)
[![Coverage Status](https://coveralls.io/repos/WebGoat/WebGoat/badge.svg?branch=master&service=github)](https://coveralls.io/github/WebGoat/WebGoat?branch=master) [![Coverage Status](https://coveralls.io/repos/WebGoat/WebGoat/badge.svg?branch=develop&service=github)](https://coveralls.io/github/WebGoat/WebGoat?branch=master)
[![Codacy Badge](https://api.codacy.com/project/badge/b69ee3a86e3b4afcaf993f210fccfb1d)](https://www.codacy.com/app/dm/WebGoat) [![Codacy Badge](https://api.codacy.com/project/badge/b69ee3a86e3b4afcaf993f210fccfb1d)](https://www.codacy.com/app/dm/WebGoat)
[![Dependency Status](https://www.versioneye.com/user/projects/562da95ae346d7000e0369aa/badge.svg?style=flat)](https://www.versioneye.com/user/projects/562da95ae346d7000e0369aa) [![Dependency Status](https://www.versioneye.com/user/projects/562da95ae346d7000e0369aa/badge.svg?style=flat)](https://www.versioneye.com/user/projects/562da95ae346d7000e0369aa)
[![OWASP Labs](https://img.shields.io/badge/owasp-labs-orange.svg)](https://www.owasp.org/index.php/OWASP_Project_Inventory#tab=Labs_Projects) [![OWASP Labs](https://img.shields.io/badge/owasp-labs-orange.svg)](https://www.owasp.org/index.php/OWASP_Project_Inventory#tab=Labs_Projects)
@ -44,8 +44,21 @@ docker pull webgoat/webgoat-8.0
docker run -p 8080:8080 webgoat/webgoat-8.0 docker run -p 8080:8080 webgoat/webgoat-8.0
``` ```
Wait for the Docker container to start and go to step 3. Wait for the Docker container to start, and run `docker ps` to verify it's running.
Please note: this version may not be completely in sync with the develop branch.
- If you are using `docker-machine`, verify the machine IP using `docker-machine env`
- If you are using `boot2docker` on OSX, verify the IP by running `docker network inspect bridge`
- Otherwise, the host will be bound to localhost
Once you have the IP and port, you'll want to navigate to the `/WebGoat` path in the URL. For example:
```
http://192.168.99.100:8080/WebGoat
```
Here you'll be able to register a new user and get started.
_Please note: this version may not be completely in sync with the develop branch._
## 2. Run from the sources ## 2. Run from the sources
@ -131,12 +144,3 @@ docker tag webgoat/webgoat-8.0 webgoat/webgoat-8.0:8.0
docker login docker login
docker push webgoat/webgoat-8.0 docker push webgoat/webgoat-8.0
``` ```
With the following command you are able to run the Docker container on your local machine:
```Shell
docker run -p 8080:8080 -t webgoat/webgoat-8.0
docker ps
```
With the last command you are able to determine ip address to connect to.

12
buildspec.yml Normal file
View File

@ -0,0 +1,12 @@
version: 0.1
phases:
build:
commands:
- mvn package
artifacts:
files:
- webgoat-server/target/webgoat-server-8.0-SNAPSHOT.jar
discard-paths: yes

View File

@ -0,0 +1,31 @@
# AWS
- This contains the various platform Quick Starts for Getting WebGoat Deployed into AWS.
- This IaaS quickstart uses AWS CloudFormation to perform most of the provisioning
- This IaaS quickstart is composed of three independent bundles
- Code pipeline and Build
- Deploying to EC2
- Deploying to ECS
It is Assumed:
- You have an AWS Account
- You know what an S3 bucket is
- You have seen the IAM console and have permissions to create IAM Roles
## Code Pipeline and Build
This Quickstart is for those that just want to perform builds with AWS. It Triggers off of Github to perform builds of `webgoat-server`
## EC2
(WIP) This uses AWS CodePipeline, CodeBuild, and CodeDeploy to land WebGoat to Running EC2 instances
## ECS
(WIP) This uses AWS CodePipeline, CodeBuild, ECR, to land a container onto an ECS cluster

View File

@ -0,0 +1,101 @@
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "IAM Roles for Code Build WebGoat IaaS Quickstart",
"Parameters": {
"qsS3BucketName": {
"Description": "Name of the S3 Bucket for artifacts",
"Type": "String",
"MinLength": "1"
},
"qsRoleName": {
"Description": "Name of the IAM role that CodeBuild Will Use",
"Type": "String",
"Default": "SimpleCodeBuildRole",
"MinLength": "1"
}
},
"Resources": {
"qsCodeBuildRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"codebuild.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/webgoat/",
"RoleName": {
"Ref": "qsRoleName"
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/AWSCodeCommitFullAccess",
"arn:aws:iam::aws:policy/AWSCodeBuildDeveloperAccess",
"arn:aws:iam::aws:policy/AWSCodeDeployDeployerAccess"
],
"Policies": [
{
"PolicyName": "CloudWatchLogs",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Resource": [
{"Fn::Join": [ "",["arn:aws:logs:*:", { "Ref": "AWS::AccountId" }, ":log-group:/aws/codebuild*" ] ]}
],
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
}
]
}
},
{
"PolicyName": "S3buckets",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Resource": [
{
"Fn::Join": [
"",
[
"arn:aws:s3:::",
{
"Ref": "qsS3BucketName"
},
"*"
]
]
},
"arn:aws:s3:::codepipeline-*"
],
"Action": [
"s3:Put*",
"s3:Get*",
"s3:List*"
]
}
]
}
}
]
}
}
}
}

View File

@ -0,0 +1,127 @@
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "IAM Role for Code Pipeline WebGoat IaaS Quickstart",
"Parameters": {
"qsS3BucketName": {
"Description": "Name of the S3 Bucket for artifacts",
"Type": "String",
"MinLength": "1"
},
"qsRoleName": {
"Description": "Name of the IAM role that CodePipeline Will Use",
"Type": "String",
"Default": "SimpleCodePipelineRole",
"MinLength": "1"
}
},
"Resources": {
"qsCodePipelineRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "codepipeline.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"Path": "/webgoat/",
"RoleName": {
"Ref": "qsRoleName"
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/AWSCodeCommitFullAccess",
"arn:aws:iam::aws:policy/AWSCodeBuildDeveloperAccess",
"arn:aws:iam::aws:policy/AWSCodeDeployDeployerAccess"
],
"Policies": [
{
"PolicyName": "CloudWatchLogsPipeline",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Resource": [
{"Fn::Join": [ "",["arn:aws:logs:*:", { "Ref": "AWS::AccountId" }, ":log-group:/aws/*" ] ]}
],
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
}
]
}
},
{
"PolicyName": "MiscComputeOpen",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Resource": "*",
"Action": [
"lambda:InvokeFunction",
"lambda:ListFunctions",
"elasticbeanstalk:*",
"ec2:*",
"elasticloadbalancing:*",
"autoscaling:*",
"cloudwatch:*",
"s3:*",
"sns:*",
"cloudformation:*",
"rds:*",
"sqs:*",
"ecs:*",
"iam:PassRole"
]
}
]
}
},
{
"PolicyName": "S3buckets",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Resource": [
{
"Fn::Join": [
"",
[
"arn:aws:s3:::",
{
"Ref": "qsS3BucketName"
},
"*"
]
]
},
"arn:aws:s3:::codepipeline-*",
"arn:aws:s3:::elasticbeanstalk*"
],
"Action": [
"s3:Put*",
"s3:Get*",
"s3:List*"
]
}
]
}
}
]
}
}
}
}

View File

@ -0,0 +1,123 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: >
AWS Cloud Formation for creating an AWS CodePipeline that checks a git repo for changes and then performs a build using code build
Parameters:
qsPipelineName:
Description: The name of the AWS Code Pipeline
Type: String
Default: WG-pipeline
MinLength: 1
qsPipelineRoleARN:
Description: The complete ARN to the IAM role that code pipeline should use
Type: String
MinLength: 1
qsCodeRepo:
Description: The Repository
Type: String
MinLength: 1
qsRepoBranch:
Description: The Branch in the Repository
Type: String
MinLength: 1
qsGitHubUser:
Description: The GitHub User Id
Type: String
MinLength: 1
qsGitHubAPIToken:
Description: The GitHub Personal Access token do not use password
NoEcho: true
Type: String
MinLength: 1
qsS3PipelineArtifacts:
Description: Where Code Pipeline will state artifacts in S3
Type: String
MinLength: 1
qsS3CodeBuildArtifacts:
Description: Where Code Build will upload Artifacts can be same as codepipeline
Type: String
MinLength: 1
qsCodeBuildName:
Description: Name of the AWS Code Build
Type: String
Default: WG-mvnBuilder
MinLength: 1
qsKMSKeyARN:
Description: The KMS ARN that the IAM Role is allowed to use
Type: String
MinLength: 1
qsCodeRoleArn:
Description: The IAM Role ARN for CodePipeline and CodeDeploy
Type: String
MinLength: 1
Resources:
stkcbrCodeBuild:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Description: Builds WebGoat Jar using build file in repo
EncryptionKey: !Ref 'qsKMSKeyARN'
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/java:openjdk-8
Type: LINUX_CONTAINER
Name: !Ref 'qsCodeBuildName'
ServiceRole: !Ref 'qsCodeRoleArn'
TimeoutInMinutes: 10
Source:
Type: CODEPIPELINE
stkcplPipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: !Ref 'qsPipelineName'
RoleArn: !Ref 'qsPipelineRoleARN'
ArtifactStore:
Location: !Ref 'qsS3PipelineArtifacts'
Type: S3
Stages:
- Name: CodeRepo
Actions:
- Name: CodeSource
ActionTypeId:
Category: Source
Owner: ThirdParty
Provider: GitHub
Version: 1
Configuration:
Branch: !Ref 'qsRepoBranch'
Repo: !Ref 'qsCodeRepo'
Owner: !Ref 'qsGitHubUser'
OAuthToken: !Ref 'qsGitHubAPIToken'
OutputArtifacts:
- Name: MySource
RunOrder: '1'
- Name: Build
Actions:
- Name: CodeBuild
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
InputArtifacts:
- Name: MySource
Configuration:
ProjectName: !Ref stkcbrCodeBuild
OutputArtifacts:
- Name: MyBuild
RunOrder: '2'

View File

@ -0,0 +1,64 @@
# Serverless MVN builds Featuring AWS
This Quick Start forms the basis for the other AWS quickstarts. This only BUILDS the `webgoat-server` spring boot jar. If you want to also run it on AWS skip to the other AWS quickstarts
Before you Begin
1. Do you have an AWS Account?
2. Can you create an S3 Bucket?
3. Can you create a KMS Key?
4. Do you know what Cloud Formation is?
5. Do you have enough permissions to do any real work in said AWS Account?
If you said no to any of those...hop over to [docs](https://aws.amazon.com/documentation/) and learn (but don't do) how to create those.
You will also need:
1. A GitHub Account
2. Fork of WebGoat
3. Personal access Token with `Admin:repo_hook` and `repo`
## Create Pre-requisites
First pick an AWS region and stick with it for ALL the quickstarts. This one was mostly executed on US-east-1/2 but any region with KMS, CodePipeline, and CodeBuild will work. eu-Central-1, ap-southeast-1 and sa-east-1 have reported success also.
1. Create an S3 bucket and call it something meaningfull like `webgoat-stash-username` or something or use an existing bucket you have access to.
2. Create a KMS Key. Make sure you are a key administrator so you can add key users later.
## Deploy IAM role Cloud Formation Stacks
In this folder there are two json cloudformation templates:
-`01_IAM_codebuild.json`
-`01_IAM_codepipeline.json`
You will use the CloudFormation templates to create two roles. One for CodePipeline and the Other for CodeBuild. You will use the name of the bucket you just created as a parameter.
## Update KMS Key
Access the KMS key you created earlier...add the two IAM roles you just created and Key Users
## Finally the Pipeline
You will use the yaml cloudformation template `01_codepiplinebuild.yml` to create the code building pipeline.
Some of the parameters you will need to pass:
1. The S3 bucket (twice)
2. The Github Branch name (master? develop? yourbranchname?)
3. The Github user (if you forked it would be your username)
4. You personal access token for GitHub
5. The name or the repo (WebGoat! ...unless you renamed and did a whole bunch of fancy git magic)
6. The ARN of the KMS key
7. The ARN of the role for the codebuild for parameter qsCodeRoleArn
8. The ARN for codepipeline
If this Stack successfully deploys a build will begin based on the latest commit automatically. You will have a funky named zip file (without the .zip ending) in a folder in the S3 bucket in a few minutes.
Congratulations. You just Deployed a two step AWS Codepipeline that looks for codechanges and then performs a build.
... ON to the next AWS Quickstart

View File

@ -0,0 +1,80 @@
# GKE - DockerHub
This Quickstart shows how to create a Kubernettes Cluster using Google Cloud Platform's [GKE](https://cloud.google.com/container-engine/) and WebGoat's Docker [Image](https://hub.docker.com/r/webgoat/webgoat-8.0/).
To be Successfull with this Quickstart
1. You have a Google Cloud Platform account and have enough access rights to create Compute Engine and Container Engine Resources
2. You know how to `git clone`
3. You have the gcloud SDK install and initialized somewhere ( do not use the google cloud shell)
Remeber to perform a 'gcloud auth login' before using the gcloud commands below.
## Create Kubernettes Cluster
You can create a cluster using the Google Cloud Console. The Default settings will suffice. For this QuickStart the cluster name used is `owaspbasiccluster`. The `PROJECTNAME` is whatever your project is. The `REGION` is a region/zone near you.
If you want to use the gcloud sdk from a properly initialized gcloud commandline environment use the following command
```
gcloud container --project "PROJECTNAME" clusters create "owaspbasiccluster" --zone "REGION" --machine-type "n1-standard-1" --image-type "COS" --disk-size "100" --scopes "https://www.googleapis.com/auth/compute","https://www.googleapis.com/auth/devstorage.read_only","https://www.googleapis.com/auth/logging.write","https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/servicecontrol","https://www.googleapis.com/auth/service.management.readonly","https://www.googleapis.com/auth/trace.append","https://www.googleapis.com/auth/source.read_only" --num-nodes "3" --network "default" --enable-cloud-logging --no-enable-cloud-monitoring
```
The command creates a similar cluster with more of the options set explicitly.
## Set up Kubectl
Using the commandline gcloud SDK environment you need to set-up 'kubectl'
If you have not already installed 'Kubectl' you can do so with the following command using `gcloud`
- `gcloud components install kubectl`
Then you just run:
- `gcloud container clusters get-credentials owaspbasiccluster --zone REGION --project PROJECTNAME`
## Deploy WebGoat Deployment
Time to deploy the latest DockerImage for WebGoat!
Let's First Make a namespace for this:
- `kubectl create namespace webgoat`
Now it is time to make the magic happen!
- `kubectl create -f /where_you_git_cloned_webgoat/platformQuickStart/GCP/GKE-Docker/webgoat_noDNSnoTLS.yml`
This should complete with no errors.
Use the following command to see information/status about the deployment
- `kubectl describe deployment webgoat-dpl --namespace=webgoat`
After a few minutes the service endpoint should be ready. You can check the status with
- `kubectl describe service webgoatsvc --namespace=webgoat`
In the output you should see a message like "Created load..." after a "Creating load..." which means that the public facing loadbalancer (even thou there is just one container running!) is ready.
If you want to see the Kubernetes dashboard you can run `kubectl proxy` (in a new terminal window) and then navigate to http://localhost:8001/ui .
## Test Deployment
From the previous `describe service` command the `LoadBalancer Ingress:` line should have the external IP. The line below should give the port.
So.....
[IP]:[PORT]/WebGoat in your browser!
DONE

View File

@ -0,0 +1,39 @@
---
apiVersion: v1
kind: Service
metadata:
labels:
app: webgoatapp
name: webgoatsvc
namespace: webgoat
spec:
ports:
-
port: 8080
protocol: TCP
selector:
app: webgoatapp
type: LoadBalancer
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: webgoat-dpl
namespace: webgoat
spec:
replicas: 1
template:
metadata:
name: webgoatapp
labels:
app: webgoatapp
spec:
containers:
-
image: webgoat/webgoat-8.0
name: webgoat
ports:
-
containerPort: 8080

View File

@ -0,0 +1,17 @@
# WebGoat on GCP!
This folder contains sub folders for the various ways you could deploy WebGoat on Google Cloud Platform
It is assumed:
1. You have a Google Cloud Platform Account
2. You can use Git
3. You can use a Linux/Mac/Google Cloud Shell
## GKE Docker
Uses GKE to run the latest DockerHub version of WebGoat8
## AppEngine
WIP

View File

@ -0,0 +1,22 @@
# OWASP WebGoat Platform Quick Starts
Want to Run WebGoat? Want to run WebGoat in the Cloud? Don't want to be cloud Expert?
Do we have a solution for you!
Additionally, Each IaaS/PaaS will have their deployment steps broken down giving the *app-guy-new-to-cloud* an opportunity to learn how said platform works.
## AWS
Multi-Part Quickstart. Starts with simple pipeline that just builds code to a deploying onto EC2 instances and then containers using ECS/ECR
## GCP
Get WebGoat Running on GKE and AppEngine

View File

@ -20,7 +20,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version> <version>1.5.3.RELEASE</version>
</parent> </parent>
<licenses> <licenses>

View File

@ -242,6 +242,12 @@
<version>${junit.version}</version> <version>${junit.version}</version>
<type>jar</type> <type>jar</type>
</dependency> </dependency>
<dependency>
<groupId>com.github.fakemongo</groupId>
<artifactId>fongo</artifactId>
<version>2.1.0</version>
<scope>test</scope>
</dependency>
<!-- ************* END: Dependencies for Unit and Integration Testing ************** --> <!-- ************* END: Dependencies for Unit and Integration Testing ************** -->
<!-- ************* END: <dependencies> ************** --> <!-- ************* END: <dependencies> ************** -->
</dependencies> </dependencies>

View File

@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.util.FileSystemUtils;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.io.File; import java.io.File;
@ -23,14 +24,10 @@ public class CleanupLocalProgressFiles {
@PostConstruct @PostConstruct
public void clean() { public void clean() {
File dir = new File(webgoatHome); File dir = new File(webgoatHome);
if (dir.exists()) { //do it safe, check whether the subdir mongodb is available as subdirectory
File[] progressFiles = dir.listFiles(f -> f.getName().endsWith(".progress")); File[] mongoDir = dir.listFiles(f -> f.isDirectory() && f.getName().contains("mongodb"));
if (progressFiles != null) { if (mongoDir != null && mongoDir.length == 1) {
log.info("Removing stored user preferences..."); FileSystemUtils.deleteRecursively(dir);
for (File f : progressFiles) {
f.delete();
}
}
} }
} }
} }

View File

@ -124,6 +124,7 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
registry.addResourceHandler("/images/**").addResourceLocations("classpath:/images/"); registry.addResourceHandler("/images/**").addResourceLocations("classpath:/images/");
registry.addResourceHandler("/lesson_js/**").addResourceLocations("classpath:/js/"); registry.addResourceHandler("/lesson_js/**").addResourceLocations("classpath:/js/");
registry.addResourceHandler("/lesson_css/**").addResourceLocations("classpath:/css/"); registry.addResourceHandler("/lesson_css/**").addResourceLocations("classpath:/css/");
registry.addResourceHandler("/video/**").addResourceLocations("classpath:/video/");
super.addResourceHandlers(registry); super.addResourceHandlers(registry);
} }

View File

@ -25,11 +25,10 @@
package org.owasp.webgoat.assignments; package org.owasp.webgoat.assignments;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import org.apache.commons.lang3.StringEscapeUtils;
import org.owasp.webgoat.i18n.PluginMessages; import org.owasp.webgoat.i18n.PluginMessages;
@AllArgsConstructor
public class AttackResult { public class AttackResult {
public static class AttackResultBuilder { public static class AttackResultBuilder {
@ -89,6 +88,11 @@ public class AttackResult {
@Getter @Getter
private String output; private String output;
public AttackResult(boolean lessonCompleted, String feedback, String output) {
this.lessonCompleted = lessonCompleted;
this.feedback = StringEscapeUtils.escapeJson(feedback);
this.output = StringEscapeUtils.escapeJson(output);
}
public static AttackResultBuilder builder(PluginMessages messages) { public static AttackResultBuilder builder(PluginMessages messages) {
return new AttackResultBuilder(messages); return new AttackResultBuilder(messages);

View File

@ -33,7 +33,6 @@ package org.owasp.webgoat.controller;
import org.owasp.webgoat.lessons.AbstractLesson; import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.session.Course; import org.owasp.webgoat.session.Course;
import org.owasp.webgoat.session.WebSession; import org.owasp.webgoat.session.WebSession;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
@ -77,8 +76,8 @@ public class StartLesson {
// I will set here the thymeleaf fragment location based on the resource requested. // I will set here the thymeleaf fragment location based on the resource requested.
ModelAndView model = new ModelAndView(); ModelAndView model = new ModelAndView();
SecurityContext context = SecurityContextHolder.getContext(); //TODO this should work with the security roles of Spring SecurityContext context = SecurityContextHolder.getContext(); //TODO this should work with the security roles of Spring
GrantedAuthority authority = context.getAuthentication().getAuthorities().iterator().next(); //GrantedAuthority authority = context.getAuthentication().getAuthorities().iterator().next();
String path = request.getServletPath(); // we now got /a/b/c/AccessControlMatrix.lesson String path = request.getRequestURL().toString(); // we now got /a/b/c/AccessControlMatrix.lesson
String lessonName = path.substring(path.lastIndexOf('/') + 1, path.indexOf(".lesson")); String lessonName = path.substring(path.lastIndexOf('/') + 1, path.indexOf(".lesson"));
List<AbstractLesson> lessons = course.getLessons(); List<AbstractLesson> lessons = course.getLessons();
Optional<AbstractLesson> lesson = lessons.stream() Optional<AbstractLesson> lesson = lessons.stream()

View File

@ -1,6 +1,6 @@
package org.owasp.webgoat.lessons; package org.owasp.webgoat.lessons;
import lombok.Getter; import com.google.common.collect.Lists;
import lombok.Setter; import lombok.Setter;
import org.owasp.webgoat.session.Screen; import org.owasp.webgoat.session.Screen;
@ -44,10 +44,16 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
private Integer ranking; private Integer ranking;
@Getter
@Setter @Setter
private List<Assignment> assignments; private List<Assignment> assignments;
public List<Assignment> getAssignments() {
if (assignments == null) {
return Lists.newArrayList();
}
return assignments;
}
/** /**
* Constructor for the Lesson object * Constructor for the Lesson object
*/ */

View File

@ -52,7 +52,7 @@ public enum Category {
INSECURE_CONFIGURATION("Insecure Configuration", new Integer(1400)), INSECURE_CONFIGURATION("Insecure Configuration", new Integer(1400)),
INSECURE_STORAGE("Insecure Storage", new Integer(1500)), INSECURE_STORAGE("Insecure Storage", new Integer(1500)),
MALICIOUS_EXECUTION("Malicious Execution", new Integer(1600)), MALICIOUS_EXECUTION("Malicious Execution", new Integer(1600)),
PARAMETER_TAMPERING("Parameter Tampering", new Integer(1700)), CLIENT_SIDE("Client side", new Integer(1700)),
SESSION_MANAGEMENT("Session Management Flaws", new Integer(1800)), SESSION_MANAGEMENT("Session Management Flaws", new Integer(1800)),
WEB_SERVICES("Web Services", new Integer(1900)), WEB_SERVICES("Web Services", new Integer(1900)),
VULNERABLE_COMPONENTS("Vulnerable Components - A9", new Integer(1950)), VULNERABLE_COMPONENTS("Vulnerable Components - A9", new Integer(1950)),

View File

@ -7,69 +7,105 @@ import java.sql.Statement;
/** /**
************************************************************************************************* * ************************************************************************************************
* * <p>
* * <p>
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, * This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/ * please see http://www.owasp.org/
* * <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew * Copyright (c) 2002 - 20014 Bruce Mayhew
* * <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the * This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version. * License, or (at your option) any later version.
* * <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. * General Public License for more details.
* * <p>
* You should have received a copy of the GNU General Public License along with this program; if * You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA. * 02111-1307, USA.
* * <p>
* Getting Source ============== * Getting Source ==============
* * <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects. * projects.
* *
* @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a> * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
* @version $Id: $Id * @version $Id: $Id
*/ */
public class CreateDB public class CreateDB {
{
/** /**
* Description of the Method * Description of the Method
* *
* @param connection * @param connection Description of the Parameter
* Description of the Parameter * @throws SQLException Description of the Exception
*
* @exception SQLException
* Description of the Exception
*/ */
private void createMessageTable(Connection connection) throws SQLException private void createServersTable(Connection connection) throws SQLException {
{ Statement statement = connection.createStatement();
// Drop servers table
try {
String dropTable = "DROP TABLE servers";
statement.executeUpdate(dropTable);
} catch (SQLException e) {
System.out.println("Info - Could not drop servers table");
}
// Create the new table
try {
String createTableStatement = "CREATE TABLE servers"
+ " (" + "id varchar(10),"
+ "hostname varchar(20),"
+ "ip varchar(20),"
+ "mac varchar(20),"
+ "status varchar(20),"
+ "description varchar(40)"
+ ")";
statement.executeUpdate(createTableStatement);
String insertData1 = "INSERT INTO servers VALUES ('1', 'webgoat-dev', '192.168.4.0', 'AA:BB:11:22:CC:DD', 'online', 'Development server')";
String insertData2 = "INSERT INTO servers VALUES ('2', 'webgoat-tst', '192.168.2.1', 'EE:FF:33:44:AB:CD', 'online', 'Test server')";
String insertData3 = "INSERT INTO servers VALUES ('3', 'webgoat-acc', '192.168.3.3', 'EF:12:FE:34:AA:CC', 'offline', 'Acceptance server')";
String insertData4 = "INSERT INTO servers VALUES ('4', 'webgoat-pre-prod', '192.168.6.4', 'EF:12:FE:34:AA:CC', 'offline', 'Pre-production server')";
String insertData5 = "INSERT INTO servers VALUES ('4', 'webgoat-prd', '104.130.219.202', 'FA:91:EB:82:DC:73', 'out of order', 'Production server')";
statement.executeUpdate(insertData1);
statement.executeUpdate(insertData2);
statement.executeUpdate(insertData3);
statement.executeUpdate(insertData4);
statement.executeUpdate(insertData5);
} catch (SQLException e) {
System.out.println("Error creating product table " + e.getLocalizedMessage());
}
}
/**
* Description of the Method
*
* @param connection Description of the Parameter
* @throws SQLException Description of the Exception
*/
private void createMessageTable(Connection connection) throws SQLException {
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
// Drop admin user table // Drop admin user table
try try {
{
String dropTable = "DROP TABLE messages"; String dropTable = "DROP TABLE messages";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop message database"); System.out.println("Info - Could not drop message database");
} }
// Create the new table // Create the new table
try try {
{
String createTableStatement = "CREATE TABLE messages (" + "num int not null," + "title varchar(50)," String createTableStatement = "CREATE TABLE messages (" + "num int not null," + "title varchar(50),"
+ "message varchar(200)," + "user_name varchar(50) not null, " + "lesson_type varchar(50) not null" + "message varchar(200)," + "user_name varchar(50) not null, " + "lesson_type varchar(50) not null"
+ ")"; + ")";
statement.executeUpdate(createTableStatement); statement.executeUpdate(createTableStatement);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error creating message database " + e.getLocalizedMessage()); System.out.println("Error creating message database " + e.getLocalizedMessage());
} }
} }
@ -78,35 +114,27 @@ public class CreateDB
* Description of the Method * Description of the Method
* *
* @param connection Description of the Parameter * @param connection Description of the Parameter
* * @throws SQLException Description of the Exception
* @exception SQLException Description of the Exception
*/ */
private void createMFEImagesTable(Connection connection) throws SQLException private void createMFEImagesTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
// Drop mfe_images table // Drop mfe_images table
try try {
{
String dropTable = "DROP TABLE mfe_images"; String dropTable = "DROP TABLE mfe_images";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} } catch (SQLException e) {
catch (SQLException e)
{
System.out.println("Info - Could not drop mfe_images table from database"); System.out.println("Info - Could not drop mfe_images table from database");
} }
// Create the new mfe_images table // Create the new mfe_images table
try try {
{
String createTableStatement = "CREATE TABLE mfe_images (" String createTableStatement = "CREATE TABLE mfe_images ("
+ "user_name varchar(50) not null, " + "user_name varchar(50) not null, "
+ "image_relative_url varchar(50) not null" + "image_relative_url varchar(50) not null"
+ ")"; + ")";
statement.executeUpdate(createTableStatement); statement.executeUpdate(createTableStatement);
} } catch (SQLException e) {
catch (SQLException e)
{
System.out.println("Error creating mfe_images table in database " + e.getLocalizedMessage()); System.out.println("Error creating mfe_images table in database " + e.getLocalizedMessage());
} }
@ -115,35 +143,27 @@ public class CreateDB
/** /**
* Description of the Method * Description of the Method
* *
* @param connection * @param connection Description of the Parameter
* Description of the Parameter * @throws SQLException Description of the Exception
*
* @exception SQLException
* Description of the Exception
*/ */
private void createProductTable(Connection connection) throws SQLException private void createProductTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
// Drop admin user table // Drop admin user table
try try {
{
String dropTable = "DROP TABLE product_system_data"; String dropTable = "DROP TABLE product_system_data";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop product table"); System.out.println("Info - Could not drop product table");
} }
// Create the new table // Create the new table
try try {
{
String createTableStatement = "CREATE TABLE product_system_data (" String createTableStatement = "CREATE TABLE product_system_data ("
+ "productid varchar(6) not null primary key," + "product_name varchar(20)," + "price varchar(10)" + "productid varchar(6) not null primary key," + "product_name varchar(20)," + "price varchar(10)"
+ ")"; + ")";
statement.executeUpdate(createTableStatement); statement.executeUpdate(createTableStatement);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error creating product table " + e.getLocalizedMessage()); System.out.println("Error creating product table " + e.getLocalizedMessage());
} }
@ -163,34 +183,26 @@ public class CreateDB
/** /**
* Description of the Method * Description of the Method
* *
* @param connection * @param connection Description of the Parameter
* Description of the Parameter * @throws SQLException Description of the Exception
*
* @exception SQLException
* Description of the Exception
*/ */
private void createUserAdminTable(Connection connection) throws SQLException private void createUserAdminTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
// Drop admin user table // Drop admin user table
try try {
{
String dropTable = "DROP TABLE user_system_data"; String dropTable = "DROP TABLE user_system_data";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop user admin table"); System.out.println("Info - Could not drop user admin table");
} }
// Create the new table // Create the new table
try try {
{
String createTableStatement = "CREATE TABLE user_system_data (" + "userid varchar(5) not null primary key," String createTableStatement = "CREATE TABLE user_system_data (" + "userid varchar(5) not null primary key,"
+ "user_name varchar(12)," + "password varchar(10)," + "cookie varchar(30)" + ")"; + "user_name varchar(12)," + "password varchar(10)," + "cookie varchar(30)" + ")";
statement.executeUpdate(createTableStatement); statement.executeUpdate(createTableStatement);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error creating user admin table " + e.getLocalizedMessage()); System.out.println("Error creating user admin table " + e.getLocalizedMessage());
} }
@ -210,35 +222,27 @@ public class CreateDB
/** /**
* Description of the Method * Description of the Method
* *
* @param connection * @param connection Description of the Parameter
* Description of the Parameter * @throws SQLException Description of the Exception
*
* @exception SQLException
* Description of the Exception
*/ */
private void createUserDataTable(Connection connection) throws SQLException private void createUserDataTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
// Delete table if there is one // Delete table if there is one
try try {
{
String dropTable = "DROP TABLE user_data"; String dropTable = "DROP TABLE user_data";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop user table"); System.out.println("Info - Could not drop user table");
} }
// Create the new table // Create the new table
try try {
{
String createTableStatement = "CREATE TABLE user_data (" + "userid int not null," String createTableStatement = "CREATE TABLE user_data (" + "userid int not null,"
+ "first_name varchar(20)," + "last_name varchar(20)," + "cc_number varchar(30)," + "first_name varchar(20)," + "last_name varchar(20)," + "cc_number varchar(30),"
+ "cc_type varchar(10)," + "cookie varchar(20)," + "login_count int" + ")"; + "cc_type varchar(10)," + "cookie varchar(20)," + "login_count int" + ")";
statement.executeUpdate(createTableStatement); statement.executeUpdate(createTableStatement);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error creating user table " + e.getLocalizedMessage()); System.out.println("Error creating user table " + e.getLocalizedMessage());
} }
@ -272,61 +276,49 @@ public class CreateDB
} }
private void createLoginTable(Connection connection) throws SQLException private void createLoginTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
// Delete table if there is one // Delete table if there is one
try try {
{
String dropTable = "DROP TABLE user_login"; String dropTable = "DROP TABLE user_login";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop user_login table"); System.out.println("Info - Could not drop user_login table");
} }
// Create the new table // Create the new table
try try {
{
String createTableStatement = "CREATE TABLE user_login (" + "userid varchar(5)," String createTableStatement = "CREATE TABLE user_login (" + "userid varchar(5),"
+ "webgoat_user varchar(20)" + ")"; + "webgoat_user varchar(20)" + ")";
statement.executeUpdate(createTableStatement); statement.executeUpdate(createTableStatement);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error creating user_login table " + e.getLocalizedMessage()); System.out.println("Error creating user_login table " + e.getLocalizedMessage());
} }
} }
// creates the table pins which is used in the blind sql injection lesson // creates the table pins which is used in the blind sql injection lesson
private void createBlindSQLLessonTable(Connection connection) throws SQLException private void createBlindSQLLessonTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
// Delete table if there is one // Delete table if there is one
try try {
{
String dropTable = "DROP TABLE pins"; String dropTable = "DROP TABLE pins";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} } catch (SQLException e) {
catch (SQLException e)
{
System.out.println("Info - Could not drop pins table"); System.out.println("Info - Could not drop pins table");
} }
// Create the new table // Create the new table
try try {
{
String createTableStatement = "CREATE TABLE pins (" String createTableStatement = "CREATE TABLE pins ("
+ "cc_number varchar(30)," + "cc_number varchar(30),"
+ "pin int," + "pin int,"
+ "name varchar(20)" + "name varchar(20)"
+ ")"; + ")";
statement.executeUpdate(createTableStatement); statement.executeUpdate(createTableStatement);
} } catch (SQLException e) {
catch (SQLException e)
{
System.out.println("Error creating pins table " + e.getLocalizedMessage()); System.out.println("Error creating pins table " + e.getLocalizedMessage());
} }
@ -347,32 +339,25 @@ public class CreateDB
// creates the table salaries which is used in the lessons // creates the table salaries which is used in the lessons
// which add or modify data using sql injection // which add or modify data using sql injection
private void createModifyWithSQLLessonTable(Connection connection) throws SQLException private void createModifyWithSQLLessonTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
// Delete table if there is one // Delete table if there is one
try try {
{
String dropTable = "DROP TABLE salaries"; String dropTable = "DROP TABLE salaries";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} } catch (SQLException e) {
catch (SQLException e)
{
System.out.println("Info - Could not drop salaries table"); System.out.println("Info - Could not drop salaries table");
} }
// Create the new table // Create the new table
try try {
{
String createTableStatement = "CREATE TABLE salaries (" String createTableStatement = "CREATE TABLE salaries ("
+ "userid varchar(50)," + "userid varchar(50),"
+ "salary int" + "salary int"
+ ")"; + ")";
statement.executeUpdate(createTableStatement); statement.executeUpdate(createTableStatement);
} } catch (SQLException e) {
catch (SQLException e)
{
System.out.println("Error creating salaries table " + e.getLocalizedMessage()); System.out.println("Error creating salaries table " + e.getLocalizedMessage());
} }
@ -394,35 +379,27 @@ public class CreateDB
/** /**
* Description of the Method * Description of the Method
* *
* @param connection * @param connection Description of the Parameter
* Description of the Parameter * @throws SQLException Description of the Exception
*
* @exception SQLException
* Description of the Exception
*/ */
private void createWeatherDataTable(Connection connection) throws SQLException private void createWeatherDataTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
// Delete table if there is one // Delete table if there is one
try try {
{
String dropTable = "DROP TABLE weather_data"; String dropTable = "DROP TABLE weather_data";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop weather table"); System.out.println("Info - Could not drop weather table");
} }
// Create the new table // Create the new table
try try {
{
String createTableStatement = "CREATE TABLE weather_data (" + "station int not null," String createTableStatement = "CREATE TABLE weather_data (" + "station int not null,"
+ "name varchar(20) not null," + "state char(2) not null," + "min_temp int not null," + "name varchar(20) not null," + "state char(2) not null," + "min_temp int not null,"
+ "max_temp int not null" + ")"; + "max_temp int not null" + ")";
statement.executeUpdate(createTableStatement); statement.executeUpdate(createTableStatement);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error creating weather table " + e.getLocalizedMessage()); System.out.println("Error creating weather table " + e.getLocalizedMessage());
} }
@ -447,30 +424,25 @@ public class CreateDB
* @param connection * @param connection
* @throws SQLException * @throws SQLException
*/ */
private void createTanUserDataTable(Connection connection) throws SQLException private void createTanUserDataTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
// Delete table if there is one // Delete table if there is one
try try {
{
String dropTable = "DROP TABLE user_data_tan"; String dropTable = "DROP TABLE user_data_tan";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop user_data_tan table"); System.out.println("Info - Could not drop user_data_tan table");
} }
// Create the new table // Create the new table
try try {
{
String createTableStatement = "CREATE TABLE user_data_tan (" + "userid int not null," String createTableStatement = "CREATE TABLE user_data_tan (" + "userid int not null,"
+ "first_name varchar(20)," + "last_name varchar(20)," + "cc_number varchar(30)," + "first_name varchar(20)," + "last_name varchar(20)," + "cc_number varchar(30),"
+ "cc_type varchar(10)," + "cookie varchar(20)," + "login_count int," + "password varchar(20)" + "cc_type varchar(10)," + "cookie varchar(20)," + "login_count int," + "password varchar(20)"
+ ")"; + ")";
statement.executeUpdate(createTableStatement); statement.executeUpdate(createTableStatement);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error creating user_data_tan table " + e.getLocalizedMessage()); System.out.println("Error creating user_data_tan table " + e.getLocalizedMessage());
} }
@ -490,28 +462,23 @@ public class CreateDB
* @param connection * @param connection
* @throws SQLException * @throws SQLException
*/ */
private void createTanTable(Connection connection) throws SQLException private void createTanTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
// Delete table if there is one // Delete table if there is one
try try {
{
String dropTable = "DROP TABLE tan"; String dropTable = "DROP TABLE tan";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop tan table"); System.out.println("Info - Could not drop tan table");
} }
// Create the new table // Create the new table
try try {
{
String createTableStatement = "CREATE TABLE tan (" + "userid int not null," + "tanNr int," + "tanValue int" String createTableStatement = "CREATE TABLE tan (" + "userid int not null," + "tanNr int," + "tanValue int"
+ ")"; + ")";
statement.executeUpdate(createTableStatement); statement.executeUpdate(createTableStatement);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error creating tan table " + e.getLocalizedMessage()); System.out.println("Error creating tan table " + e.getLocalizedMessage());
} }
@ -552,22 +519,18 @@ public class CreateDB
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
private void createEmployeeTable(Connection connection) throws SQLException private void createEmployeeTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
try try {
{
String dropTable = "DROP TABLE employee"; String dropTable = "DROP TABLE employee";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop employee table"); System.out.println("Info - Could not drop employee table");
} }
// Create Table // Create Table
try try {
{
String createTable = "CREATE TABLE employee (" String createTable = "CREATE TABLE employee ("
// + "userid INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY," // + "userid INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,"
+ "userid INT NOT NULL PRIMARY KEY," + "first_name VARCHAR(20)," + "last_name VARCHAR(20)," + "userid INT NOT NULL PRIMARY KEY," + "first_name VARCHAR(20)," + "last_name VARCHAR(20),"
@ -582,8 +545,7 @@ public class CreateDB
+ ")"; + ")";
statement.executeUpdate(createTable); statement.executeUpdate(createTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error: unable to create employee table " + e.getLocalizedMessage()); System.out.println("Error: unable to create employee table " + e.getLocalizedMessage());
} }
@ -649,27 +611,22 @@ public class CreateDB
} }
private void createRolesTable(Connection connection) throws SQLException private void createRolesTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
try try {
{
String dropTable = "DROP TABLE roles"; String dropTable = "DROP TABLE roles";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop roles table"); System.out.println("Info - Could not drop roles table");
} }
try try {
{
String createTable = "CREATE TABLE roles (" + "userid INT NOT NULL," + "role VARCHAR(10) NOT NULL," String createTable = "CREATE TABLE roles (" + "userid INT NOT NULL," + "role VARCHAR(10) NOT NULL,"
+ "PRIMARY KEY (userid, role)" + ")"; + "PRIMARY KEY (userid, role)" + ")";
statement.executeUpdate(createTable); statement.executeUpdate(createTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error: Unable to create role table: " + e.getLocalizedMessage()); System.out.println("Error: Unable to create role table: " + e.getLocalizedMessage());
} }
@ -700,27 +657,22 @@ public class CreateDB
statement.executeUpdate(insertData12); statement.executeUpdate(insertData12);
} }
private void createAuthTable(Connection connection) throws SQLException private void createAuthTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
try try {
{
String dropTable = "DROP TABLE auth"; String dropTable = "DROP TABLE auth";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop auth table"); System.out.println("Info - Could not drop auth table");
} }
try try {
{
String createTable = "CREATE TABLE auth (" + "role VARCHAR(10) NOT NULL," String createTable = "CREATE TABLE auth (" + "role VARCHAR(10) NOT NULL,"
+ "functionid VARCHAR(20) NOT NULL," + "PRIMARY KEY (role, functionid)" + ")"; + "functionid VARCHAR(20) NOT NULL," + "PRIMARY KEY (role, functionid)" + ")";
statement.executeUpdate(createTable); statement.executeUpdate(createTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error: unable to create auth table: " + e.getLocalizedMessage()); System.out.println("Error: unable to create auth table: " + e.getLocalizedMessage());
} }
@ -807,27 +759,22 @@ public class CreateDB
//statement.executeUpdate(insertData28); //statement.executeUpdate(insertData28);
} }
private void createOwnershipTable(Connection connection) throws SQLException private void createOwnershipTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
try try {
{
String dropTable = "DROP TABLE ownership"; String dropTable = "DROP TABLE ownership";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop ownership table"); System.out.println("Info - Could not drop ownership table");
} }
try try {
{
String createTable = "CREATE TABLE ownership (" + "employer_id INT NOT NULL," + "employee_id INT NOT NULL," String createTable = "CREATE TABLE ownership (" + "employer_id INT NOT NULL," + "employee_id INT NOT NULL,"
+ "PRIMARY KEY (employee_id, employer_id)" + ")"; + "PRIMARY KEY (employee_id, employer_id)" + ")";
statement.executeUpdate(createTable); statement.executeUpdate(createTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error: unable to create ownership table: " + e.getLocalizedMessage()); System.out.println("Error: unable to create ownership table: " + e.getLocalizedMessage());
} }
@ -951,34 +898,29 @@ public class CreateDB
* Start creation of data for WebServices labs * Start creation of data for WebServices labs
*/ */
private void createTransactionTable(Connection connection) throws SQLException private void createTransactionTable(Connection connection) throws SQLException {
{
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
try try {
{
String dropTable = "DROP TABLE transactions"; String dropTable = "DROP TABLE transactions";
statement.executeUpdate(dropTable); statement.executeUpdate(dropTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Info - Could not drop transactions table"); System.out.println("Info - Could not drop transactions table");
} }
try try {
{
String createTable = "CREATE TABLE Transactions (" + "userName VARCHAR(16) NOT NULL, " String createTable = "CREATE TABLE Transactions (" + "userName VARCHAR(16) NOT NULL, "
+ "sequence INTEGER NOT NULL, " + "from_account VARCHAR(16) NOT NULL, " + "sequence INTEGER NOT NULL, " + "from_account VARCHAR(16) NOT NULL, "
+ "to_account VARCHAR(16) NOT NULL, " + "transactionDate TIMESTAMP NOT NULL, " + "to_account VARCHAR(16) NOT NULL, " + "transactionDate TIMESTAMP NOT NULL, "
+ "description VARCHAR(255) NOT NULL, " + "amount INTEGER NOT NULL" + ")"; + "description VARCHAR(255) NOT NULL, " + "amount INTEGER NOT NULL" + ")";
statement.executeUpdate(createTable); statement.executeUpdate(createTable);
} catch (SQLException e) } catch (SQLException e) {
{
System.out.println("Error: unable to create transactions table: " + e.getLocalizedMessage()); System.out.println("Error: unable to create transactions table: " + e.getLocalizedMessage());
throw e; throw e;
} }
String[] data = new String[] { String[] data = new String[]{
"'dave', 0, '238-4723-4024', '324-7635-9867', '2008-02-06 21:40:00', 'Mortgage', '150'", "'dave', 0, '238-4723-4024', '324-7635-9867', '2008-02-06 21:40:00', 'Mortgage', '150'",
"'dave', 1, '238-4723-4024', '324-7635-9867', '2008-02-12 21:41:00', 'Car', '150'", "'dave', 1, '238-4723-4024', '324-7635-9867', '2008-02-12 21:41:00', 'Car', '150'",
"'dave', 2, '238-4723-4024', '324-7635-9867', '2008-02-20 21:42:00', 'School fees', '150'", "'dave', 2, '238-4723-4024', '324-7635-9867', '2008-02-20 21:42:00', 'School fees', '150'",
@ -987,35 +929,32 @@ public class CreateDB
"'CEO', 5, '348-6324-9872', '980-2344-5492', '2008-02-27 21:42:00', 'Vacation', '-150000'", "'CEO', 5, '348-6324-9872', '980-2344-5492', '2008-02-27 21:42:00', 'Vacation', '-150000'",
"'jeff', 6, '934-2002-3485', '783-2409-8234', '2008-02-01 21:40:00', 'Vet', '250'", "'jeff', 6, '934-2002-3485', '783-2409-8234', '2008-02-01 21:40:00', 'Vet', '250'",
"'jeff', 7, '934-2002-3485', '634-5879-0345', '2008-02-19 21:41:00', 'Doctor', '800'", "'jeff', 7, '934-2002-3485', '634-5879-0345', '2008-02-19 21:41:00', 'Doctor', '800'",
"'jeff', 8, '934-2002-3485', '435-4325-3358', '2008-02-20 21:42:00', 'X-rays', '200'", }; "'jeff', 8, '934-2002-3485', '435-4325-3358', '2008-02-20 21:42:00', 'X-rays', '200'",};
try try {
{ for (int i = 0; i < data.length; i++) {
for (int i = 0; i < data.length; i++)
{
statement.executeUpdate("INSERT INTO Transactions VALUES (" + data[i] + ");"); statement.executeUpdate("INSERT INTO Transactions VALUES (" + data[i] + ");");
} }
} catch (SQLException sqle) } catch (SQLException sqle) {
{
System.out.println("Error: Unable to insert transactions: " + sqle.getLocalizedMessage()); System.out.println("Error: Unable to insert transactions: " + sqle.getLocalizedMessage());
int errorCode = sqle.getErrorCode(); int errorCode = sqle.getErrorCode();
System.out.println("Error Code: " + errorCode); System.out.println("Error Code: " + errorCode);
// ignore exceptions for Oracle and SQL Server // ignore exceptions for Oracle and SQL Server
if (errorCode != 911 && errorCode != 273) { throw sqle; } if (errorCode != 911 && errorCode != 273) {
throw sqle;
}
} }
} }
/** /**
* Description of the Method * Description of the Method
* *
* @param connection * @param connection Description of the Parameter
* Description of the Parameter * @throws SQLException Description of the Exception
* @exception SQLException
* Description of the Exception
* @throws java.sql.SQLException if any. * @throws java.sql.SQLException if any.
*/ */
public void makeDB(Connection connection) throws SQLException public void makeDB(Connection connection) throws SQLException {
{
System.out.println("Successful connection to database"); System.out.println("Successful connection to database");
createServersTable(connection);
createUserDataTable(connection); createUserDataTable(connection);
createLoginTable(connection); createLoginTable(connection);
createBlindSQLLessonTable(connection); createBlindSQLLessonTable(connection);

View File

@ -16,7 +16,7 @@ security.enable-csrf=false
spring.resources.cache-period=0 spring.resources.cache-period=0
spring.thymeleaf.cache=false spring.thymeleaf.cache=false
webgoat.clean=true webgoat.clean=false
webgoat.server.directory=${user.home}/.webgoat/ webgoat.server.directory=${user.home}/.webgoat/
webgoat.user.directory=${user.home}/.webgoat/ webgoat.user.directory=${user.home}/.webgoat/
webgoat.build.version=@project.version@ webgoat.build.version=@project.version@
@ -29,6 +29,7 @@ webgoat.database.driver=org.hsqldb.jdbcDriver
webgoat.database.connection.string=jdbc:hsqldb:mem:{USER} webgoat.database.connection.string=jdbc:hsqldb:mem:{USER}
webgoat.default.language=en webgoat.default.language=en
spring.data.mongodb.database=webgoat spring.data.mongodb.database=webgoat
spring.mongodb.embedded.storage.databaseDir=${webgoat.user.directory}/mongodb/ spring.mongodb.embedded.storage.databaseDir=${webgoat.user.directory}/mongodb/

View File

@ -80,7 +80,9 @@ define(['jquery',
var self = this; var self = this;
// TODO custom Data prep for submission // TODO custom Data prep for submission
var prepareDataFunctionName = $(curForm).attr('prepareData'); var prepareDataFunctionName = $(curForm).attr('prepareData');
var callbackFunctionName = $(curForm).attr('callback');
var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize(); var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize();
var callbackFunction = (typeof webgoat.customjs[callbackFunctionName] === 'function') ? webgoat.customjs[callbackFunctionName] : function() {};
// var submitData = this.$form.serialize(); // var submitData = this.$form.serialize();
this.curForm = curForm; this.curForm = curForm;
this.$curFeedback = $(curForm).closest('.attack-container').find('.attack-feedback'); this.$curFeedback = $(curForm).closest('.attack-container').find('.attack-feedback');
@ -93,14 +95,16 @@ define(['jquery',
url:formUrl, url:formUrl,
method:formMethod, method:formMethod,
contentType:contentType, contentType:contentType,
data: submitData data: submitData,
complete: function (data) {
callbackFunction();
}
}).then(self.onSuccessResponse.bind(self), self.onErrorResponse.bind(self)); }).then(self.onSuccessResponse.bind(self), self.onErrorResponse.bind(self));
return false; return false;
}, },
onSuccessResponse: function(data) { onSuccessResponse: function(data) {
this.renderFeedback(data.feedback); this.renderFeedback(data.feedback);
this.renderOutput(data.output || ""); this.renderOutput(data.output || "");
//TODO: refactor back assignmentCompleted in Java //TODO: refactor back assignmentCompleted in Java
if (data.lessonCompleted || data.assignmentCompleted) { if (data.lessonCompleted || data.assignmentCompleted) {

View File

@ -0,0 +1,49 @@
package org.owasp.webgoat.plugins;
import org.junit.Before;
import org.owasp.webgoat.i18n.Language;
import org.owasp.webgoat.i18n.PluginMessages;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.session.WebgoatContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.LocalServerPort;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;
import java.util.Locale;
import static org.mockito.Mockito.when;
/**
* @author nbaars
* @since 5/20/17.
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(locations = "classpath:/application-test.properties")
public abstract class LessonTest {
@LocalServerPort
protected int localPort;
protected MockMvc mockMvc;
@Autowired
protected WebApplicationContext wac;
@Autowired
protected PluginMessages messages;
@MockBean
protected WebSession webSession;
@Autowired
private WebgoatContext context;
@MockBean
private Language language;
@Before
public void init() {
when(webSession.getUserName()).thenReturn("unit-test");
when(language.getLocale()).thenReturn(Locale.getDefault());
when(webSession.getWebgoatContext()).thenReturn(context);
}
}

View File

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

View File

@ -0,0 +1 @@
webgoat.user.directory=/tmp/

View File

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

View File

@ -0,0 +1,63 @@
package org.owasp.webgoat.plugin;
import com.beust.jcommander.internal.Lists;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import java.util.List;
/**
* ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>
*
* @author WebGoat
* @version $Id: $Id
* @since October 12, 2016
*/
public class BypassRestrictions extends NewLesson {
@Override
public Category getDefaultCategory() {
return Category.CLIENT_SIDE;
}
@Override
public List<String> getHints() {
return Lists.newArrayList();
}
@Override
public Integer getDefaultRanking() {
return 2;
}
@Override
public String getTitle() {
return "bypass-restrictions.title";
}
@Override
public String getId() {
return "BypassRestrictions";
}
}

View File

@ -0,0 +1,74 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* *************************************************************************************************
*
*
* This file is part of WebGoat, an Open Web Application Security Project
* utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* For details, please see http://webgoat.github.io
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
@AssignmentPath("/BypassRestrictions/FieldRestrictions")
public class BypassRestrictionsFieldRestrictions extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public
@ResponseBody
AttackResult completed(@RequestParam String select, @RequestParam String radio, @RequestParam String checkbox, @RequestParam String shortInput) throws IOException {
if (select.toString().equals("option1") || select.toString().equals("option2")) {
return trackProgress(failed().build());
}
if (radio.toString().equals("option1") || radio.toString().equals("option2")) {
return trackProgress(failed().build());
}
if (checkbox.toString().equals("on") || checkbox.toString().equals("off")) {
return trackProgress(failed().build());
}
if (shortInput.toString().length() <= 5) {
return trackProgress(failed().build());
}
/*if (disabled == null) {
return trackProgress(failed().build());
}
if (submit.toString().equals("submit")) {
return trackProgress(failed().build());
}*/
return trackProgress(success().build());
}
}

View File

@ -0,0 +1,87 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* *************************************************************************************************
*
*
* This file is part of WebGoat, an Open Web Application Security Project
* utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* For details, please see http://webgoat.github.io
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
@AssignmentPath("/BypassRestrictions/frontendValidation")
public class BypassRestrictionsFrontendValidation extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public
@ResponseBody
AttackResult completed(@RequestParam String field1, @RequestParam String field2, @RequestParam String field3, @RequestParam String field4, @RequestParam String field5, @RequestParam String field6, @RequestParam String field7, @RequestParam Integer error) throws IOException {
String regex1="^[a-z]{3}$";
String regex2="^[0-9]{3}$";
String regex3="^[a-zA-Z0-9 ]*$";
String regex4="^(one|two|three|four|five|six|seven|eight|nine)$";
String regex5="^\\d{5}$";
String regex6="^\\d{5}(-\\d{4})?$";
String regex7="^[2-9]\\d{2}-?\\d{3}-?\\d{4}$";
if (error>0) {
return trackProgress(failed().build());
}
if (field1.matches(regex1)) {
return trackProgress(failed().build());
}
if (field2.matches(regex2)) {
return trackProgress(failed().build());
}
if (field3.matches(regex3)) {
return trackProgress(failed().build());
}
if (field4.matches(regex4)) {
return trackProgress(failed().build());
}
if (field5.matches(regex5)) {
return trackProgress(failed().build());
}
if (field6.matches(regex6)) {
return trackProgress(failed().build());
}
if (field7.matches(regex7)) {
return trackProgress(failed().build());
}
return trackProgress(success().build());
}
}

View File

@ -0,0 +1,126 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:BypassRestrictions_Intro.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<!-- stripped down without extra comments -->
<div class="adoc-content" th:replace="doc:BypassRestrictions_FieldRestrictions.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" name="fieldRestrictions"
method="POST"
action="/WebGoat/BypassRestrictions/FieldRestrictions"
enctype="application/json;charset=UTF-8">
<div>Select field with two possible values</div>
<select name="select">
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
</select>
<div>Radio button with two possible values</div>
<input type="radio" name="radio" value="option1" checked="checked"/> Option 1<br />
<input type="radio" name="radio" value="option2" /> Option 2<br />
<div>Checkbox: value either on or off</div>
<input type="checkbox" name="checkbox" checked="checked"/> Checkbox
<div>Input restricted to max 5 characters</div>
<input type="text" value="12345" name="shortInput" maxlength="5"/>
<div>Disabled input field</div>
<input type="submit" value="submit"/>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:BypassRestrictions_FrontendValidation.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" name="frontendValidation"
id="frontendValidation"
method="POST"
action="/WebGoat/BypassRestrictions/frontendValidation/"
enctype="application/json;charset=UTF-8"
onsubmit="return validate()">
<div>
<strong>Field 1:</strong> exactly three lowercase characters(^[a-z]{3}$)
</div>
<div>
<textarea cols="25" name="field1" rows="1">abc</textarea>
</div>
<p></p>
<div><strong>Field 2:</strong> exactly three digits(^[0-9]{3}$)</div>
<div>
<textarea cols="25" name="field2" rows="1">123</textarea>
</div>
<p></p>
<div><strong>Field 3:</strong> letters, numbers, and space only(^[a-zA-Z0-9 ]*$)</div>
<div>
<textarea cols="25" name="field3" rows="1">abc 123 ABC</textarea>
</div>
<p></p>
<div><strong>Field 4:</strong> enumeration of numbers (^(one|two|three|four|five|six|seven|eight|nine)$)</div>
<div>
<textarea cols="25" name="field4" rows="1">seven</textarea>
</div>
<p></p>
<div><strong>Field 5:</strong> simple zip code (^\d{5}$)</div>
<div>
<textarea cols="25" name="field5" rows="1">01101</textarea>
</div>
<p></p>
<div><strong>Field 6:</strong> zip with optional dash four (^\d{5}(-\d{4})?$)</div>
<div>
<textarea cols="25" name="field6" rows="1">90210-1111</textarea>
</div>
<p></p>
<div><strong>Field 7:</strong> US phone number with or without dashes (^[2-9]\d{2}-?\d{3}-?\d{4}$)</div>
<div>
<textarea cols="25" name="field7" rows="1">301-604-4882</textarea>
</div>
<input type="hidden" value="" name="error" />
<p><button type="submit" class="btn btn-primary">Submit</button></p>
</form>
<script>
var regex1=/^[a-z]{3}$/;
var regex2=/^[0-9]{3}$/;
var regex3=/^[a-zA-Z0-9 ]*$/;
var regex4=/^(one|two|three|four|five|six|seven|eight|nine)$/;
var regex5=/^\d{5}$/;
var regex6=/^\d{5}(-\d{4})?$/;
var regex7=/^[2-9]\d{2}-?\d{3}-?\d{4}$/;
var validate = function() {
var msg='JavaScript found form errors';
var err=0;
if (!regex1.test(document.frontendValidation.field1.value)) {err+=1; msg+='\n Value entered for field 1 is not correct';}
if (!regex2.test(document.frontendValidation.field2.value)) {err+=1; msg+='\n Value entered for field 2 is not correct';}
if (!regex3.test(document.frontendValidation.field3.value)) {err+=1; msg+='\n Value entered for field 3 is not correct';}
if (!regex4.test(document.frontendValidation.field4.value)) {err+=1; msg+='\n Value entered for field 4 is not correct';}
if (!regex5.test(document.frontendValidation.field5.value)) {err+=1; msg+='\n Value entered for field 5 is not correct';}
if (!regex6.test(document.frontendValidation.field6.value)) {err+=1; msg+='\n Value entered for field 6 is not correct';}
if (!regex7.test(document.frontendValidation.field7.value)) {err+=1; msg+='\n Value entered for field 7 is not correct';}
document.frontendValidation.error.value = err
if ( err > 0 ) {
alert(msg)
return false;
}
return true;
}
</script>
<br/>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -0,0 +1,4 @@
bypass-restrictions.title=Bypass front-end restrictions
bypass-restrictions.intercept.success=Well done, you intercepted the request as expected
bypass-restrictions.intercept.failure=Please try again. Make sure to make all the changes. And case sensitivity may matter ... or not, you never know!

View File

@ -0,0 +1,6 @@
== Field Restrictions
In most browsers, client has complete or almost complete control over HTML part
of the webpage. They can alter values or restrictions to fit their preference.
=== Task
Send a request that bypasses restrictions of all four of these fields

View File

@ -0,0 +1,9 @@
== Validation
Often, there is some mechanism in place to prevent users from sending altered
field values to server, such as validation before sending. Most of popular browsers
such as Chrome don't allow editing scripts during runtime. We will have to circumvent
the validation some other way.
=== Task
Send a request that does not fit the regular expression above the field in all fields.

View File

@ -0,0 +1,11 @@
== Concept
Users have a great degree of control over the front-end of the web application.
They can alter HTML code, sometimes also scripts. This is why
apps that require certain format of input should also validate on server-side.
== Goals
* The user should have a basic knowledge of HTML
* The user should be able to tamper a request before sending (with proxy or other tool)
* The user will be able to tamper with field restrictions and bypass client-side validation

View File

@ -0,0 +1,76 @@
package org.owasp.webgoat.plugin;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author nbaars
* @since 6/16/17.
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class BypassRestrictionsFrontendValidationTest extends LessonTest {
@Before
public void setup() throws Exception {
when(webSession.getCurrentLesson()).thenReturn(new BypassRestrictions());
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void noChangesShouldNotPassTheLesson() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation")
.param("field1", "abc")
.param("field2", "123")
.param("field3", "abc ABC 123")
.param("field4", "seven")
.param("field5", "01101")
.param("field6", "90201 1111")
.param("field7", "301-604-4882")
.param("error", "2"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false)));
}
@Test
public void bypassAllFieldShouldPass() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation")
.param("field1", "abcd")
.param("field2", "1234")
.param("field3", "abc $ABC 123")
.param("field4", "ten")
.param("field5", "01101AA")
.param("field6", "90201 1111AA")
.param("field7", "301-604-4882$$")
.param("error", "0"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true)));
}
@Test
public void notBypassingAllFieldShouldNotPass() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation")
.param("field1", "abc")
.param("field2", "1234")
.param("field3", "abc $ABC 123")
.param("field4", "ten")
.param("field5", "01101AA")
.param("field6", "90201 1111AA")
.param("field7", "301-604-4882AA")
.param("error", "0"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false)));
}
}

View File

@ -1,5 +1,11 @@
=== Welcome to the WebGoat challenge (CTF) === Welcome to the WebGoat challenge (CTF)
==== Introduction
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
participants can join and hack the challenges. A scoreboard is available at http://localhost:8080/WebGoat/scoreboard
: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
need to post in order to gain points. need to post in order to gain points.

View File

@ -39,7 +39,7 @@ public class ClientSideFiltering extends NewLesson {
@Override @Override
public Category getDefaultCategory() { public Category getDefaultCategory() {
return Category.AJAX_SECURITY; return Category.CLIENT_SIDE;
} }
@Override @Override

View File

@ -0,0 +1,34 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>html-tampering</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId>
<version>8.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>4.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<type>jar</type>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,63 @@
package org.owasp.webgoat.plugin;
import com.beust.jcommander.internal.Lists;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import java.util.List;
/**
* ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>
*
* @author WebGoat
* @version $Id: $Id
* @since October 12, 2016
*/
public class HtmlTampering extends NewLesson {
@Override
public Category getDefaultCategory() {
return Category.CLIENT_SIDE;
}
@Override
public List<String> getHints() {
return Lists.newArrayList();
}
@Override
public Integer getDefaultRanking() {
return 3;
}
@Override
public String getTitle() {
return "html-tampering.title";
}
@Override
public String getId() {
return "HtmlTampering";
}
}

View File

@ -0,0 +1,60 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException;
/**
* *************************************************************************************************
*
*
* This file is part of WebGoat, an Open Web Application Security Project
* utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* For details, please see http://webgoat.github.io
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
@AssignmentPath("/HtmlTampering/task")
@AssignmentHints({ "hint1", "hint2", "hint3"})
public class HtmlTamperingTask extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public
@ResponseBody
AttackResult completed(@RequestParam String QTY, @RequestParam String Total) throws IOException {
if (Float.parseFloat(QTY) * 2999.99 > Float.parseFloat(Total) + 1) {
return trackProgress(success().feedback("html-tampering.tamper.success").build());
}
return trackProgress(failed().feedback("html-tampering.tamper.failure").build());
}
}

View File

@ -0,0 +1,149 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:HtmlTampering_Intro.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<!-- stripped down without extra comments -->
<div class="adoc-content" th:replace="doc:HtmlTampering_Task.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" id="task" name="task"
method="POST"
action="/WebGoat/HtmlTampering/task"
enctype="application/json;charset=UTF-8">
<script>
var regex = /^2999.99$/;
var price = 2999.99;
document.getElementById("total").innerHTML = '$' + price.toString();
var total = price * document.task.QTY.value;
document.getElementById("total").innerHTML = '$' + total;
document.getElementById("subtotal").innerHTML = '$' + total;
document.getElementById("totalAmount").innerHTML = '$' + total;
$('#remove').click(function () {
document.getElementById("QTY").value = 1;
update();
});
$("#QTY").on('change keydown paste input blur', function () {
update();
});
function update() {
price = $('#price').text();
if (!regex.test(price.toString())) {
alert('Data tampering is disallowed');
document.getElementById("price").innerHTML = 2999.99;
update();
}
var total = price * document.task.QTY.value;
$('#total').text('$' + total.toFixed(2));
$('#subtotal').text('$' + total.toFixed(2));
$('#totalAmount').text('$' + total.toFixed(2));
$('#Total').val(total.toFixed(2));
}
</script>
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-10 col-md-offset-1">
<table class="table table-hover">
<thead>
<tr>
<th>Product</th>
<th>Quantity</th>
<th class="text-center">Price</th>
<th class="text-center">Total</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td class="col-sm-8 col-md-6">
<div class="media">
<a class="thumbnail pull-left" href="#"> <img class="media-object"
th:src="@{/images/samsung.jpg}"
style="width: 72px; height: 72px;"></img>
</a>
<div class="media-body">
<h4 class="media-heading"><a href="#">55'' M5510 White Full HD Smart TV</a>
</h4>
<h5 class="media-heading"> by <a href="#">Samsung</a></h5>
<span>Status: </span><span
class="text-success"><strong>In Stock</strong></span>
</div>
</div>
</td>
<td>
<input size="2" value="1" name="QTY" type="TEXT" id="QTY"/>
</td>
<td class="col-sm-1 col-md-1 text-center"><strong><span
id="price">2999.99</span></strong></td>
<td class="col-sm-1 col-md-1 text-center"><strong><span
id="total">$2999.99</span></strong></td>
<td class="col-sm-1 col-md-1">
<button type="submit" id="remove" class="btn btn-danger">
<span class="glyphicon glyphicon-remove" onclick="clear()"></span> Remove
</button>
</td>
</tr>
<tr>
<td>  </td>
<td>  </td>
<td>  </td>
<td><h5>Subtotal</h5></td>
<td class="text-right"><h5><strong><span id="subtotal">$2999.99</span></strong></h5>
</td>
</tr>
<tr>
<td>  </td>
<td>  </td>
<td>  </td>
<td><h5>Shipping costs</h5></td>
<td class="text-right"><h5><strong>$0.00</strong></h5>
</td>
</tr>
<tr>
<td>  </td>
<td>  </td>
<td>  </td>
<td><h3>Total</h3></td>
<td class="text-right"><h3><strong><span id="totalAmount">$2999.99</span></strong></h3>
</td>
</tr>
<tr>
<td>  </td>
<td>  </td>
<td>  </td>
<td>
<button type="button" class="btn btn-default">
<span class="glyphicon glyphicon-shopping-cart"></span> Continue Shopping
</button>
</td>
<td>
<div id="checkout">
<button type="submit" class="btn btn-success">
Checkout <span class="glyphicon glyphicon-play"></span>
</button>
</div>
</td>
<input id="Total" name="Total" type="HIDDEN" value="2999.99"/>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</form>
<br/><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:HtmlTampering_Mitigation.adoc"></div>
</div>
</html>

View File

@ -0,0 +1,9 @@
html-tampering.title=HTML tampering
html-tampering.tamper.success=Well done, you just bought a TV at a discount
html-tampering.tamper.failure=This is too expensive... You need to buy at a cheaper cost!
hint1=Try to change the number of items and see what is happening
hint2=Is the price part of the HTML request?
hint3=Intercept the request and manipulate the price before submitting it.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,8 @@
== Concept
Browsers generally offer many options of editing the displayed content. Developers
therefore must be aware that the values sent by the user may have been tampered with.
== Goals
* The user should have a basic understanding of HTML
* The user will be able to exploit editing front end of website

View File

@ -0,0 +1,14 @@
=== Mitigation
In this simple example you noticed that the price is calculated server side and send to the server. The server
accepted the input as a given and did not calculate the price again. One of the mitigations in this case is to look up
the price of the television in your database and calculate the total price again.
In a real application you should never rely on client side validation it is important to verify all the input
send by the client. Always remember: **NEVER TRUST INPUT SEND BY A CLIENT.**
''''
==== References
https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet

View File

@ -0,0 +1,2 @@
=== Try it yourself
In an online store you ordered a new TV, try to buy one or more TVs for a lower price.

View File

@ -9,28 +9,4 @@
<version>8.0-SNAPSHOT</version> <version>8.0-SNAPSHOT</version>
</parent> </parent>
<build>
<plugins>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.3</version>
<executions>
<execution>
<id>output-html</id>
<phase>generate-resources</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html</backend>
<sourceDirectory>src/main/resources/lessonPlans/en/</sourceDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project> </project>

View File

@ -0,0 +1,34 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>insecure-login</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId>
<version>8.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>4.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<type>jar</type>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,63 @@
package org.owasp.webgoat.plugin;
import com.beust.jcommander.internal.Lists;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import java.util.List;
/**
* ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>
*
* @author WebGoat
* @version $Id: $Id
* @since October 12, 2016
*/
public class InsecureLogin extends NewLesson {
@Override
public Category getDefaultCategory() {
return Category.INSECURE_COMMUNICATION;
}
@Override
public List<String> getHints() {
return Lists.newArrayList();
}
@Override
public Integer getDefaultRanking() {
return 1;
}
@Override
public String getTitle() {
return "insecure-login.title";
}
@Override
public String getId() {
return "InsecureLogin";
}
}

View File

@ -0,0 +1,59 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* *************************************************************************************************
*
*
* This file is part of WebGoat, an Open Web Application Security Project
* utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* For details, please see http://webgoat.github.io
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
@AssignmentPath("/InsecureLogin/task")
public class InsecureLoginTask extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public
@ResponseBody
AttackResult completed(@RequestParam String username, @RequestParam String password) throws IOException {
if (username.toString().equals("CaptainJack") && password.toString().equals("BlackPearl")) {
return trackProgress(success().build());
}
return trackProgress(failed().build());
}
}

View File

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:InsecureLogin_Intro.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<!-- stripped down without extra comments -->
<div class="adoc-content" th:replace="doc:InsecureLogin_Task.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<script th:src="@{/lesson_js/credentials.js}"
language="JavaScript"></script>
<form class="attack-form" accept-charset="UNKNOWN" name="task"
method="POST"
action="#attack/307/100"
enctype="application/json;charset=UTF-8">
<!---
<input type="hidden" value="" name="username" id="SecretUsername"/>
<input type="hidden" value="" name="password" id="SecretPassword"/>
<input type="button" value="Log in" onpress="submit_secret_credentials()"/>-->
<button onclick="submit_secret_credentials()">Log in</button>
</form>
<br></br>
<form class="attack-form" accept-charset="UNKNOWN" name="task"
method="POST"
action="/WebGoat/InsecureLogin/task"
enctype="application/json;charset=UTF-8">
<input type="text" value="" name="username" placeholder="username"/>
<input type="password" value="" name="password" placeholder="password" />
<input type="submit" value="Submit" />
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -0,0 +1,4 @@
insecure-login.title=Insecure Login
insecure-login.intercept.success=Welcome, CaptainJack!
insecure-login.intercept.failure=Wrong username or password

View File

@ -0,0 +1,6 @@
function submit_secret_credentials() {
var xhttp = new XMLHttpRequest();
xhttp['open']('POST', '#attack/307/100', true);
//sending the request is obfuscated, to descourage js reading
var _0xb7f9=["\x43\x61\x70\x74\x61\x69\x6E\x4A\x61\x63\x6B","\x42\x6C\x61\x63\x6B\x50\x65\x61\x72\x6C","\x73\x74\x72\x69\x6E\x67\x69\x66\x79","\x73\x65\x6E\x64"];xhttp[_0xb7f9[3]](JSON[_0xb7f9[2]]({username:_0xb7f9[0],password:_0xb7f9[1]}))
}

View File

@ -0,0 +1,7 @@
== Concept
Encryption is a very inportant tool for secure communication. In this lesson, we will find out, why it should always be employed when sending sensitive data.
== Goals
* The user should have a basic understanding of packet sniffer usage
* The user will be able to intercept and read an unencrypted requests

View File

@ -0,0 +1,4 @@
=== Let's try
Click the "log in" button to send a request containing login credentials of another user.
Then, write these credentials into the appropriate fields and submit to confirm.
Try using a packet sniffer to intercept the request.

View File

@ -14,16 +14,21 @@
</parent> </parent>
<modules> <modules>
<module>bypass-restrictions</module>
<module>challenge</module> <module>challenge</module>
<module>client-side-filtering</module> <module>client-side-filtering</module>
<module>cross-site-scripting</module> <module>cross-site-scripting</module>
<module>html-tampering</module>
<module>http-basics</module> <module>http-basics</module>
<module>http-proxies</module> <module>http-proxies</module>
<module>insecure-login</module>
<module>jwt</module> <module>jwt</module>
<module>sql-injection</module> <module>sql-injection</module>
<module>xxe</module> <module>xxe</module>
<module>idor</module> <module>idor</module>
<module>vulnerable-components</module> <module>vulnerable-components</module>
<!-- uncomment below to include lesson template in build, also uncomment the dependency in webgoat-server/pom.xml to have it run in the project fully -->
<!--<module>webgoat-lesson-template</module>-->
</modules> </modules>
<dependencies> <dependencies>
@ -33,6 +38,14 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>provided</scope>
<type>jar</type> <type>jar</type>
<!-- Exclude Mongo embedded so testcases do not start it automatically, seems to be
the easiest way to stop the autoconfiguration of Spring Boot -->
<exclusions>
<exclusion>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!--<dependency>--> <!--<dependency>-->
<!--<groupId>org.apache.commons</groupId>--> <!--<groupId>org.apache.commons</groupId>-->
@ -45,6 +58,14 @@
<version>${project.version}</version> <version>${project.version}</version>
<classifier>tests</classifier> <classifier>tests</classifier>
<scope>test</scope> <scope>test</scope>
<!-- Exclude Mongo embedded so testcases do not start it automatically, seems to be
the easiest way to stop the autoconfiguration of Spring Boot -->
<exclusions>
<exclusion>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
@ -70,6 +91,12 @@
<version>4.1.3.RELEASE</version> <version>4.1.3.RELEASE</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.github.fakemongo</groupId>
<artifactId>fongo</artifactId>
<version>2.1.0</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.owasp.encoder</groupId> <groupId>org.owasp.encoder</groupId>
<artifactId>encoder</artifactId> <artifactId>encoder</artifactId>

View File

@ -14,7 +14,7 @@ Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from
## XXE ## ## XXE ##
Simple <?xml version="1.0" standalone="yes" ?><!DOCTYPE comment [<!ENTITY root SYSTEM "file:///"> ]><comment> <text>&root;</text><password>test</password></comment> Simple - <?xml version="1.0" standalone="yes" ?><!DOCTYPE user [<!ENTITY root SYSTEM "file:///"> ]><comment><text>&root;</text></comment>
Modern Rest Framework - change content type to: Content-Type: application/xml && Modern Rest Framework - change content type to: Content-Type: application/xml &&
<?xml version="1.0" standalone="yes" ?><!DOCTYPE user [<!ENTITY root SYSTEM "file:///"> ]><user> <username>&root;</username><password>test</password></user> <?xml version="1.0" standalone="yes" ?><!DOCTYPE user [<!ENTITY root SYSTEM "file:///"> ]><user> <username>&root;</username><password>test</password></user>

View File

@ -1,220 +0,0 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.DatabaseUtilities;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.sql.*;
/***************************************************************************************************
*
*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
*
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* For details, please see http://webgoat.github.io
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
@AssignmentPath("/SqlInjection/attack5a")
public class SqlInjectionLesson5a extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody AttackResult completed(@RequestParam String account, HttpServletRequest request) throws IOException {
return injectableQuery(account);
}
protected AttackResult injectableQuery(String accountName)
{
try
{
Connection connection = DatabaseUtilities.getConnection(getWebSession());
String query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'";
try
{
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet results = statement.executeQuery(query);
if ((results != null) && (results.first() == true))
{
ResultSetMetaData resultsMetaData = results.getMetaData();
StringBuffer output = new StringBuffer();
output.append(writeTable(results, resultsMetaData));
results.last();
// If they get back more than one user they succeeded
if (results.getRow() >= 6)
{
return trackProgress(success().feedback("sql-injection.5a.success").feedbackArgs(output.toString()).build());
} else {
return trackProgress(failed().output(output.toString()).build());
}
}
else
{
return trackProgress(failed().feedback("sql-injection.5a.no.results").build());
}
} catch (SQLException sqle)
{
return trackProgress(failed().output(sqle.getMessage()).build());
}
} catch (Exception e)
{
e.printStackTrace();
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
}
}
public String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) throws IOException,
SQLException
{
int numColumns = resultsMetaData.getColumnCount();
results.beforeFirst();
StringBuffer t = new StringBuffer();
t.append("<p>");
if (results.next())
{
for (int i = 1; i < (numColumns + 1); i++)
{
t.append(resultsMetaData.getColumnName(i));
t.append(", ");
}
t.append("<br />");
results.beforeFirst();
while (results.next())
{
for (int i = 1; i < (numColumns + 1); i++)
{
t.append(results.getString(i));
t.append(", ");
}
t.append("<br />");
}
}
else
{
t.append ("Query Successful; however no data was returned from this query.");
}
t.append("</p>");
return (t.toString());
}
//
// protected Element parameterizedQuery(WebSession s)
// {
// ElementContainer ec = new ElementContainer();
//
// ec.addElement(getLabelManager().get("StringSqlInjectionSecondStage"));
// if (s.getParser().getRawParameter(ACCT_NAME, "YOUR_NAME").equals("restart"))
// {
// getLessonTracker(s).getLessonProperties().setProperty(STAGE, "1");
// return (injectableQuery(s));
// }
//
// ec.addElement(new BR());
//
// try
// {
// Connection connection = DatabaseUtilities.getConnection(s);
//
// ec.addElement(makeAccountLine(s));
//
// String query = "SELECT * FROM user_data WHERE last_name = ?";
// ec.addElement(new PRE(query));
//
// try
// {
// PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE,
// ResultSet.CONCUR_READ_ONLY);
// statement.setString(1, accountName);
// ResultSet results = statement.executeQuery();
//
// if ((results != null) && (results.first() == true))
// {
// ResultSetMetaData resultsMetaData = results.getMetaData();
// ec.addElement(DatabaseUtilities.writeTable(results, resultsMetaData));
// results.last();
//
// // If they get back more than one user they succeeded
// if (results.getRow() >= 6)
// {
// makeSuccess(s);
// }
// }
// else
// {
// ec.addElement(getLabelManager().get("NoResultsMatched"));
// }
// } catch (SQLException sqle)
// {
// ec.addElement(new P().addElement(sqle.getMessage()));
// }
// } catch (Exception e)
// {
// s.setMessage(getLabelManager().get("ErrorGenerating") + this.getClass().getName());
// e.printStackTrace();
// }
//
// return (ec);
// }
//
// protected Element makeAccountLine(WebSession s)
// {
// ElementContainer ec = new ElementContainer();
// ec.addElement(new P().addElement(getLabelManager().get("EnterLastName")));
//
// accountName = s.getParser().getRawParameter(ACCT_NAME, "Your Name");
// Input input = new Input(Input.TEXT, ACCT_NAME, accountName.toString());
// ec.addElement(input);
//
// Element b = ECSFactory.makeButton(getLabelManager().get("Go!"));
// ec.addElement(b);
//
// return ec;
//
// }
}

View File

@ -1,224 +0,0 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.DatabaseUtilities;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.sql.*;
/***************************************************************************************************
*
*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
*
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* For details, please see http://webgoat.github.io
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
@AssignmentPath("/SqlInjection/attack5b")
public class SqlInjectionLesson5b extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody AttackResult completed(@RequestParam String userid, HttpServletRequest request) throws IOException {
return injectableQuery(userid);
}
protected AttackResult injectableQuery(String accountName)
{
try
{
Connection connection = DatabaseUtilities.getConnection(getWebSession());
String query = "SELECT * FROM user_data WHERE userid = " + accountName;
try
{
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet results = statement.executeQuery(query);
if ((results != null) && (results.first() == true))
{
ResultSetMetaData resultsMetaData = results.getMetaData();
StringBuffer output = new StringBuffer();
output.append(writeTable(results, resultsMetaData));
results.last();
// If they get back more than one user they succeeded
if (results.getRow() >= 6)
{
return trackProgress(success().feedback("sql-injection.5b.success").feedbackArgs(output.toString()).build());
} else {
return trackProgress(failed().output(output.toString()).build());
}
}
else
{
return trackProgress(failed().feedback("sql-injection.5b.no.results").build());
// output.append(getLabelManager().get("NoResultsMatched"));
}
} catch (SQLException sqle)
{
return trackProgress(failed().output(sqle.getMessage()).build());
}
} catch (Exception e)
{
e.printStackTrace();
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
}
}
public String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) throws IOException,
SQLException
{
int numColumns = resultsMetaData.getColumnCount();
results.beforeFirst();
StringBuffer t = new StringBuffer();
t.append("<p>");
if (results.next())
{
for (int i = 1; i < (numColumns + 1); i++)
{
t.append(resultsMetaData.getColumnName(i));
t.append(", ");
}
t.append("<br />");
results.beforeFirst();
while (results.next())
{
for (int i = 1; i < (numColumns + 1); i++)
{
t.append(results.getString(i));
t.append(", ");
}
t.append("<br />");
}
}
else
{
t.append ("Query Successful; however no data was returned from this query.");
}
t.append("</p>");
return (t.toString());
}
//
// protected Element parameterizedQuery(WebSession s)
// {
// ElementContainer ec = new ElementContainer();
//
// ec.addElement(getLabelManager().get("StringSqlInjectionSecondStage"));
// if (s.getParser().getRawParameter(ACCT_NAME, "YOUR_NAME").equals("restart"))
// {
// getLessonTracker(s).getLessonProperties().setProperty(STAGE, "1");
// return (injectableQuery(s));
// }
//
// ec.addElement(new BR());
//
// try
// {
// Connection connection = DatabaseUtilities.getConnection(s);
//
// ec.addElement(makeAccountLine(s));
//
// String query = "SELECT * FROM user_data WHERE last_name = ?";
// ec.addElement(new PRE(query));
//
// try
// {
// PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE,
// ResultSet.CONCUR_READ_ONLY);
// statement.setString(1, accountName);
// ResultSet results = statement.executeQuery();
//
// if ((results != null) && (results.first() == true))
// {
// ResultSetMetaData resultsMetaData = results.getMetaData();
// ec.addElement(DatabaseUtilities.writeTable(results, resultsMetaData));
// results.last();
//
// // If they get back more than one user they succeeded
// if (results.getRow() >= 6)
// {
// makeSuccess(s);
// }
// }
// else
// {
// ec.addElement(getLabelManager().get("NoResultsMatched"));
// }
// } catch (SQLException sqle)
// {
// ec.addElement(new P().addElement(sqle.getMessage()));
// }
// } catch (Exception e)
// {
// s.setMessage(getLabelManager().get("ErrorGenerating") + this.getClass().getName());
// e.printStackTrace();
// }
//
// return (ec);
// }
//
// protected Element makeAccountLine(WebSession s)
// {
// ElementContainer ec = new ElementContainer();
// ec.addElement(new P().addElement(getLabelManager().get("EnterLastName")));
//
// accountName = s.getParser().getRawParameter(ACCT_NAME, "Your Name");
// Input input = new Input(Input.TEXT, ACCT_NAME, accountName.toString());
// ec.addElement(input);
//
// Element b = ECSFactory.makeButton(getLabelManager().get("Go!"));
// ec.addElement(b);
//
// return ec;
//
// }
}

View File

@ -1,223 +0,0 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.DatabaseUtilities;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.sql.*;
/***************************************************************************************************
*
*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
*
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* For details, please see http://webgoat.github.io
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
@AssignmentPath("/SqlInjection/attack6a")
public class SqlInjectionLesson6a extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody AttackResult completed(@RequestParam String userid_6a, HttpServletRequest request) throws IOException {
return injectableQuery(userid_6a);
// The answer: Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data --
}
protected AttackResult injectableQuery(String accountName)
{
try
{
Connection connection = DatabaseUtilities.getConnection(getWebSession());
String query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'";
try
{
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet results = statement.executeQuery(query);
if ((results != null) && (results.first() == true))
{
ResultSetMetaData resultsMetaData = results.getMetaData();
StringBuffer output = new StringBuffer();
output.append(writeTable(results, resultsMetaData));
results.last();
// If they get back more than one user they succeeded
if (results.getRow() >= 5)
{
return trackProgress(success().feedback("sql-injection.6a.success").feedbackArgs(output.toString()).build());
} else {
return trackProgress(failed().output(output.toString()).build());
}
}
else
{
return trackProgress(failed().feedback("sql-injection.6a.no.results").build());
}
} catch (SQLException sqle)
{
return trackProgress(failed().output(sqle.getMessage()).build());
}
} catch (Exception e)
{
e.printStackTrace();
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
}
}
public String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) throws IOException,
SQLException
{
int numColumns = resultsMetaData.getColumnCount();
results.beforeFirst();
StringBuffer t = new StringBuffer();
t.append("<p>");
if (results.next())
{
for (int i = 1; i < (numColumns + 1); i++)
{
t.append(resultsMetaData.getColumnName(i));
t.append(", ");
}
t.append("<br />");
results.beforeFirst();
while (results.next())
{
for (int i = 1; i < (numColumns + 1); i++)
{
t.append(results.getString(i));
t.append(", ");
}
t.append("<br />");
}
}
else
{
t.append ("Query Successful; however no data was returned from this query.");
}
t.append("</p>");
return (t.toString());
}
//
// protected Element parameterizedQuery(WebSession s)
// {
// ElementContainer ec = new ElementContainer();
//
// ec.addElement(getLabelManager().get("StringSqlInjectionSecondStage"));
// if (s.getParser().getRawParameter(ACCT_NAME, "YOUR_NAME").equals("restart"))
// {
// getLessonTracker(s).getLessonProperties().setProperty(STAGE, "1");
// return (injectableQuery(s));
// }
//
// ec.addElement(new BR());
//
// try
// {
// Connection connection = DatabaseUtilities.getConnection(s);
//
// ec.addElement(makeAccountLine(s));
//
// String query = "SELECT * FROM user_data WHERE last_name = ?";
// ec.addElement(new PRE(query));
//
// try
// {
// PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE,
// ResultSet.CONCUR_READ_ONLY);
// statement.setString(1, accountName);
// ResultSet results = statement.executeQuery();
//
// if ((results != null) && (results.first() == true))
// {
// ResultSetMetaData resultsMetaData = results.getMetaData();
// ec.addElement(DatabaseUtilities.writeTable(results, resultsMetaData));
// results.last();
//
// // If they get back more than one user they succeeded
// if (results.getRow() >= 6)
// {
// makeSuccess(s);
// }
// }
// else
// {
// ec.addElement(getLabelManager().get("NoResultsMatched"));
// }
// } catch (SQLException sqle)
// {
// ec.addElement(new P().addElement(sqle.getMessage()));
// }
// } catch (Exception e)
// {
// s.setMessage(getLabelManager().get("ErrorGenerating") + this.getClass().getName());
// e.printStackTrace();
// }
//
// return (ec);
// }
//
// protected Element makeAccountLine(WebSession s)
// {
// ElementContainer ec = new ElementContainer();
// ec.addElement(new P().addElement(getLabelManager().get("EnterLastName")));
//
// accountName = s.getParser().getRawParameter(ACCT_NAME, "Your Name");
// Input input = new Input(Input.TEXT, ACCT_NAME, accountName.toString());
// ec.addElement(input);
//
// Element b = ECSFactory.makeButton(getLabelManager().get("Go!"));
// ec.addElement(b);
//
// return ec;
//
// }
}

View File

@ -0,0 +1,63 @@
package org.owasp.webgoat.plugin.advanced;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import java.util.ArrayList;
import java.util.List;
/**
* ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>
*
* @author WebGoat
* @version $Id: $Id
* @since October 12, 2016
*/
public class SqlInjectionAdvanced extends NewLesson {
@Override
public Category getDefaultCategory() {
return Category.INJECTION;
}
@Override
public List<String> getHints() {
return new ArrayList<>();
}
@Override
public Integer getDefaultRanking() {
return 1;
}
@Override
public String getTitle() {
return "SQL Injection (advanced)";
}
@Override
public String getId() {
return "SqlInjectionAdvanced";
}
}

View File

@ -0,0 +1,136 @@
package org.owasp.webgoat.plugin.advanced;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.DatabaseUtilities;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.sql.*;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
/**
* @author nbaars
* @since 4/8/17.
*/
@AssignmentPath("SqlInjection/challenge")
@Slf4j
public class SqlInjectionChallenge extends AssignmentEndpoint {
private static final String PASSWORD_TOM = "thisisasecretfortomonly";
//Make it more random at runtime (good luck guessing)
private static final String USERS_TABLE_NAME = "challenge_users_6" + RandomStringUtils.randomAlphabetic(16);
@Autowired
private WebSession webSession;
public SqlInjectionChallenge() {
log.info("Challenge 6 tablename is: {}", USERS_TABLE_NAME);
}
@PutMapping //assignment path is bounded to class so we use different http method :-)
@ResponseBody
public AttackResult registerNewUser(@RequestParam String username_reg, @RequestParam String email_reg, @RequestParam String password_reg) throws Exception {
AttackResult attackResult = checkArguments(username_reg, email_reg, password_reg);
if (attackResult == null) {
Connection connection = DatabaseUtilities.getConnection(webSession);
checkDatabase(connection);
String checkUserQuery = "select userid from " + USERS_TABLE_NAME + " where userid = '" + username_reg + "'";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(checkUserQuery);
if (resultSet.next()) {
attackResult = failed().feedback("user.exists").feedbackArgs(username_reg).build();
} else {
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO " + USERS_TABLE_NAME + " VALUES (?, ?, ?)");
preparedStatement.setString(1, username_reg);
preparedStatement.setString(2, email_reg);
preparedStatement.setString(3, password_reg);
preparedStatement.execute();
attackResult = success().feedback("user.created").feedbackArgs(username_reg).build();
}
}
return attackResult;
}
private AttackResult checkArguments(String username_reg, String email_reg, String password_reg) {
if (StringUtils.isEmpty(username_reg) || StringUtils.isEmpty(email_reg) || StringUtils.isEmpty(password_reg)) {
return failed().feedback("input.invalid").build();
}
if (username_reg.length() > 250 || email_reg.length() > 30 || password_reg.length() > 30) {
return failed().feedback("input.invalid").build();
}
return null;
}
@RequestMapping(method = POST)
@ResponseBody
public AttackResult login(@RequestParam String username_login, @RequestParam String password_login) throws Exception {
Connection connection = DatabaseUtilities.getConnection(webSession);
checkDatabase(connection);
PreparedStatement statement = connection.prepareStatement("select password from " + USERS_TABLE_NAME + " where userid = ? and password = ?");
statement.setString(1, username_login);
statement.setString(2, password_login);
ResultSet resultSet = statement.executeQuery();
if (resultSet.next() && "tom".equals(username_login)) {
return success().build();
} else {
return failed().feedback("NoResultsMatched").build();
}
}
private void checkDatabase(Connection connection) throws SQLException {
try {
Statement statement = connection.createStatement();
statement.execute("select 1 from " + USERS_TABLE_NAME);
} catch (SQLException e) {
createChallengeTable(connection);
}
}
private void createChallengeTable(Connection connection) {
Statement statement = null;
try {
statement = connection.createStatement();
String dropTable = "DROP TABLE " + USERS_TABLE_NAME;
statement.executeUpdate(dropTable);
} catch (SQLException e) {
log.info("Delete failed, this does not point to an error table might not have been present...");
}
log.debug("Challenge 6 - Creating tables for users {}", USERS_TABLE_NAME);
try {
String createTableStatement = "CREATE TABLE " + USERS_TABLE_NAME
+ " (" + "userid varchar(250),"
+ "email varchar(30),"
+ "password varchar(30)"
+ ")";
statement.executeUpdate(createTableStatement);
String insertData1 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('larry', 'larry@webgoat.org', 'larryknows')";
String insertData2 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('tom', 'tom@webgoat.org', '" + PASSWORD_TOM + "')";
String insertData3 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('alice', 'alice@webgoat.org', 'rt*(KJ()LP())$#**')";
String insertData4 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('eve', 'eve@webgoat.org', '**********')";
statement.executeUpdate(insertData1);
statement.executeUpdate(insertData2);
statement.executeUpdate(insertData3);
statement.executeUpdate(insertData4);
} catch (SQLException e) {
log.error("Unable create table", e);
}
}
}

View File

@ -1,4 +1,4 @@
package org.owasp.webgoat.plugin; package org.owasp.webgoat.plugin.introduction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -0,0 +1,128 @@
package org.owasp.webgoat.plugin.introduction;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.DatabaseUtilities;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException;
import java.sql.*;
/***************************************************************************************************
*
*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
*
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* For details, please see http://webgoat.github.io
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
@AssignmentPath("/SqlInjection/attack5a")
@AssignmentHints(value = {"SqlStringInjectionHint1", "SqlStringInjectionHint2", "SqlStringInjectionHint3", "SqlStringInjectionHint4"})
public class SqlInjectionLesson5a extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public
@ResponseBody
AttackResult completed(@RequestParam String account) {
return injectableQuery(account);
}
protected AttackResult injectableQuery(String accountName) {
try {
Connection connection = DatabaseUtilities.getConnection(getWebSession());
String query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'";
try {
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet results = statement.executeQuery(query);
if ((results != null) && (results.first())) {
ResultSetMetaData resultsMetaData = results.getMetaData();
StringBuffer output = new StringBuffer();
output.append(writeTable(results, resultsMetaData));
results.last();
// If they get back more than one user they succeeded
if (results.getRow() >= 6) {
return trackProgress(success().feedback("sql-injection.5a.success").feedbackArgs(output.toString()).build());
} else {
return trackProgress(failed().output(output.toString()).build());
}
} else {
return trackProgress(failed().feedback("sql-injection.5a.no.results").build());
}
} catch (SQLException sqle) {
return trackProgress(failed().output(sqle.getMessage()).build());
}
} catch (Exception e) {
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
}
}
public static String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) throws IOException,
SQLException {
int numColumns = resultsMetaData.getColumnCount();
results.beforeFirst();
StringBuffer t = new StringBuffer();
t.append("<p>");
if (results.next()) {
for (int i = 1; i < (numColumns + 1); i++) {
t.append(resultsMetaData.getColumnName(i));
t.append(", ");
}
t.append("<br />");
results.beforeFirst();
while (results.next()) {
for (int i = 1; i < (numColumns + 1); i++) {
t.append(results.getString(i));
t.append(", ");
}
t.append("<br />");
}
} else {
t.append("Query Successful; however no data was returned from this query.");
}
t.append("</p>");
return (t.toString());
}
}

View File

@ -0,0 +1,99 @@
package org.owasp.webgoat.plugin.introduction;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.DatabaseUtilities;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.sql.*;
/***************************************************************************************************
*
*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
*
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* For details, please see http://webgoat.github.io
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
@AssignmentPath("/SqlInjection/attack5b")
@AssignmentHints(value = {"SqlStringInjectionHint1", "SqlStringInjectionHint2", "SqlStringInjectionHint3", "SqlStringInjectionHint4"})
public class SqlInjectionLesson5b extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public
@ResponseBody
AttackResult completed(@RequestParam String userid, HttpServletRequest request) throws IOException {
return injectableQuery(userid);
}
protected AttackResult injectableQuery(String accountName) {
try {
Connection connection = DatabaseUtilities.getConnection(getWebSession());
String query = "SELECT * FROM user_data WHERE userid = " + accountName;
try {
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet results = statement.executeQuery(query);
if ((results != null) && (results.first() == true)) {
ResultSetMetaData resultsMetaData = results.getMetaData();
StringBuffer output = new StringBuffer();
output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData));
results.last();
// If they get back more than one user they succeeded
if (results.getRow() >= 6) {
return trackProgress(success().feedback("sql-injection.5b.success").feedbackArgs(output.toString()).build());
} else {
return trackProgress(failed().output(output.toString()).build());
}
} else {
return trackProgress(failed().feedback("sql-injection.5b.no.results").build());
// output.append(getLabelManager().get("NoResultsMatched"));
}
} catch (SQLException sqle) {
return trackProgress(failed().output(sqle.getMessage()).build());
}
} catch (Exception e) {
e.printStackTrace();
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
}
}
}

View File

@ -0,0 +1,97 @@
package org.owasp.webgoat.plugin.introduction;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.DatabaseUtilities;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException;
import java.sql.*;
/***************************************************************************************************
*
*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
*
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* For details, please see http://webgoat.github.io
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
@AssignmentPath("/SqlInjection/attack6a")
@AssignmentHints(value = {"SqlStringInjectionHint5", "SqlStringInjectionHint6", "SqlStringInjectionHint7"})
public class SqlInjectionLesson6a extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public
@ResponseBody
AttackResult completed(@RequestParam String userid_6a) throws IOException {
return injectableQuery(userid_6a);
// The answer: Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data --
}
protected AttackResult injectableQuery(String accountName) {
try {
Connection connection = DatabaseUtilities.getConnection(getWebSession());
String query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'";
try {
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet results = statement.executeQuery(query);
if ((results != null) && (results.first())) {
ResultSetMetaData resultsMetaData = results.getMetaData();
StringBuffer output = new StringBuffer();
output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData));
results.last();
// If they get back more than one user they succeeded
if (results.getRow() >= 5) {
return trackProgress(success().feedback("sql-injection.6a.success").feedbackArgs(output.toString()).build());
} else {
return trackProgress(failed().output(output.toString()).build());
}
} else {
return trackProgress(failed().feedback("sql-injection.6a.no.results").build());
}
} catch (SQLException sqle) {
return trackProgress(failed().output(sqle.getMessage()).build());
}
} catch (Exception e) {
e.printStackTrace();
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
}
}
}

View File

@ -1,5 +1,5 @@
package org.owasp.webgoat.plugin; package org.owasp.webgoat.plugin.introduction;
import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath; import org.owasp.webgoat.assignments.AssignmentPath;
@ -10,7 +10,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
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 javax.servlet.http.HttpServletRequest;
import java.io.IOException; import java.io.IOException;
import java.sql.Connection; import java.sql.Connection;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -18,7 +17,6 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
/*************************************************************************************************** /***************************************************************************************************
* *
* *
@ -53,7 +51,8 @@ import java.sql.Statement;
public class SqlInjectionLesson6b extends AssignmentEndpoint { public class SqlInjectionLesson6b extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST) @RequestMapping(method = RequestMethod.POST)
public @ResponseBody AttackResult completed(@RequestParam String userid_6b, HttpServletRequest request) throws IOException { @ResponseBody
public AttackResult completed(@RequestParam String userid_6b) throws IOException {
if (userid_6b.toString().equals(getPassword())) { if (userid_6b.toString().equals(getPassword())) {
return trackProgress(success().build()); return trackProgress(success().build());
} else { } else {
@ -61,32 +60,26 @@ public class SqlInjectionLesson6b extends AssignmentEndpoint {
} }
} }
protected String getPassword() protected String getPassword() {
{
String password="dave"; String password = "dave";
try try {
{
Connection connection = DatabaseUtilities.getConnection(getWebSession()); Connection connection = DatabaseUtilities.getConnection(getWebSession());
String query = "SELECT password FROM user_system_data WHERE user_name = 'dave'"; String query = "SELECT password FROM user_system_data WHERE user_name = 'dave'";
try try {
{
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY); ResultSet.CONCUR_READ_ONLY);
ResultSet results = statement.executeQuery(query); ResultSet results = statement.executeQuery(query);
if ((results != null) && (results.first() == true)) if ((results != null) && (results.first() == true)) {
{
password = results.getString("password"); password = results.getString("password");
} }
} catch (SQLException sqle) } catch (SQLException sqle) {
{
sqle.printStackTrace(); sqle.printStackTrace();
// do nothing // do nothing
} }
} catch (Exception e) } catch (Exception e) {
{
e.printStackTrace(); e.printStackTrace();
// do nothing // do nothing
} }

View File

@ -0,0 +1,56 @@
package org.owasp.webgoat.plugin.mitigation;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.SneakyThrows;
import org.owasp.webgoat.session.DatabaseUtilities;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
/**
* @author nbaars
* @since 6/13/17.
*/
@RestController
@RequestMapping("SqlInjection/servers")
public class Servers {
@AllArgsConstructor
@Getter
private class Server {
private String id;
private String hostname;
private String ip;
private String mac;
private String status;
private String description;
}
@Autowired
private WebSession webSession;
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
@SneakyThrows
@ResponseBody
public List<Server> sort(@RequestParam String column) {
Connection connection = DatabaseUtilities.getConnection(webSession);
PreparedStatement preparedStatement = connection.prepareStatement("select id, hostname, ip, mac, status, description from servers where status <> 'out of order' order by " + column);
ResultSet rs = preparedStatement.executeQuery();
List<Server> servers = Lists.newArrayList();
while (rs.next()) {
Server server = new Server(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5), rs.getString(6));
servers.add(server);
}
return servers;
}
}

View File

@ -0,0 +1,46 @@
package org.owasp.webgoat.plugin.mitigation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.DatabaseUtilities;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.sql.*;
/**
* @author nbaars
* @since 6/13/17.
*/
@AssignmentPath("SqlInjection/attack12a")
@AssignmentHints(value = {"SqlStringInjectionHint8", "SqlStringInjectionHint9", "SqlStringInjectionHint10", "SqlStringInjectionHint11"})
@Slf4j
public class SqlInjectionLesson12a extends AssignmentEndpoint {
@Autowired
private WebSession webSession;
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
@SneakyThrows
public AttackResult completed(@RequestParam String ip) {
Connection connection = DatabaseUtilities.getConnection(webSession);
PreparedStatement preparedStatement = connection.prepareStatement("select ip from servers where ip = ?");
preparedStatement.setString(1, ip);
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
return trackProgress(success().build());
}
return trackProgress(failed().build());
}
}

View File

@ -0,0 +1,63 @@
package org.owasp.webgoat.plugin.mitigation;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import java.util.ArrayList;
import java.util.List;
/**
* ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>
*
* @author WebGoat
* @version $Id: $Id
* @since October 12, 2016
*/
public class SqlInjectionMitigations extends NewLesson {
@Override
public Category getDefaultCategory() {
return Category.INJECTION;
}
@Override
public List<String> getHints() {
return new ArrayList<>();
}
@Override
public Integer getDefaultRanking() {
return 1;
}
@Override
public String getTitle() {
return "SQL Injection (mitigations)";
}
@Override
public String getId() {
return "SqlInjectionMitigations";
}
}

View File

@ -0,0 +1,96 @@
.panel-login {
border-color: #ccc;
-webkit-box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2);
-moz-box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2);
box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2);
}
.panel-login>.panel-heading {
color: #00415d;
background-color: #fff;
border-color: #fff;
text-align:center;
}
.panel-login>.panel-heading a{
text-decoration: none;
color: #666;
font-weight: bold;
font-size: 15px;
-webkit-transition: all 0.1s linear;
-moz-transition: all 0.1s linear;
transition: all 0.1s linear;
}
.panel-login>.panel-heading a.active{
color: #029f5b;
font-size: 18px;
}
.panel-login>.panel-heading hr{
margin-top: 10px;
margin-bottom: 0px;
clear: both;
border: 0;
height: 1px;
background-image: -webkit-linear-gradient(left,rgba(0, 0, 0, 0),rgba(0, 0, 0, 0.15),rgba(0, 0, 0, 0));
background-image: -moz-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
background-image: -ms-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
background-image: -o-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
}
.panel-login input[type="text"],.panel-login input[type="email"],.panel-login input[type="password"] {
height: 45px;
border: 1px solid #ddd;
font-size: 16px;
-webkit-transition: all 0.1s linear;
-moz-transition: all 0.1s linear;
transition: all 0.1s linear;
}
.panel-login input:hover,
.panel-login input:focus {
outline:none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
border-color: #ccc;
}
.btn-login {
background-color: #59B2E0;
outline: none;
color: #fff;
font-size: 14px;
height: auto;
font-weight: normal;
padding: 14px 0;
text-transform: uppercase;
border-color: #59B2E6;
}
.btn-login:hover,
.btn-login:focus {
color: #fff;
background-color: #53A3CD;
border-color: #53A3CD;
}
.forgot-password {
text-decoration: underline;
color: #888;
}
.forgot-password:hover,
.forgot-password:focus {
text-decoration: underline;
color: #666;
}
.btn-register {
background-color: #1CB94E;
outline: none;
color: #fff;
font-size: 14px;
height: auto;
font-weight: normal;
padding: 14px 0;
text-transform: uppercase;
border-color: #1CB94A;
}
.btn-register:hover,
.btn-register:focus {
color: #fff;
background-color: #1CA347;
border-color: #1CA347;
}

View File

@ -3,54 +3,33 @@
<html xmlns:th="http://www.thymeleaf.org"> <html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_plan.adoc"></div> <div class="adoc-content" th:replace="doc:SqlInjection_plan.adoc"></div>
</div> </div>
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content1.adoc"></div> <div class="adoc-content" th:replace="doc:SqlInjection_content1.adoc"></div>
</div> </div>
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content2.adoc"></div> <div class="adoc-content" th:replace="doc:SqlInjection_content2.adoc"></div>
</div> </div>
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content3.adoc"></div> <div class="adoc-content" th:replace="doc:SqlInjection_content3.adoc"></div>
</div> </div>
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content4.adoc"></div> <div class="adoc-content" th:replace="doc:SqlInjection_content4.adoc"></div>
</div> </div>
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content5.adoc"></div> <div class="adoc-content" th:replace="doc:SqlInjection_content5.adoc"></div>
</div> </div>
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content5a.adoc"></div> <div class="adoc-content" th:replace="doc:SqlInjection_content5a.adoc"></div>
<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>
<!-- 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 -->
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjection/attack5a" action="/WebGoat/SqlInjection/attack5a"
@ -64,23 +43,15 @@
</tr> </tr>
</table> </table>
</form> </form>
<!-- do not remove the two following div's, this is where your feedback/output will land -->
<div class="attack-feedback"></div> <div class="attack-feedback"></div>
<div class="attack-output"></div> <div class="attack-output"></div>
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
</div> </div>
</div> </div>
<div class="lesson-page-wrapper"> <div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content5b.adoc"></div> <div class="adoc-content" th:replace="doc:SqlInjection_content5b.adoc"></div>
<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>
<!-- 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 -->
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
action="/WebGoat/SqlInjection/attack5b" action="/WebGoat/SqlInjection/attack5b"
@ -95,119 +66,9 @@
</tr> </tr>
</table> </table>
</form> </form>
<!-- do not remove the two following div's, this is where your feedback/output will land -->
<div class="attack-feedback"></div> <div class="attack-feedback"></div>
<div class="attack-output"></div> <div class="attack-output"></div>
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
</div> </div>
</div> </div>
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content6.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content6a.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/SqlInjection/attack6a"
enctype="application/json;charset=UTF-8">
<table>
<tr>
<td>Name:</td>
<td><input name="userid_6a" value="" type="TEXT"/></td>
<td><input
name="Get Account Info" value="Get Account Info" type="SUBMIT"/></td>
<td></td>
</tr>
</table>
</form>
<!-- do not remove the two following div's, this is where your feedback/output will land -->
<div class="attack-feedback"></div>
<div class="attack-output"></div>
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
</div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/SqlInjection/attack6b"
enctype="application/json;charset=UTF-8">
<table>
<tr>
<td>Password:</td>
<td><input name="userid_6b" value="" type="TEXT"/></td>
<td><input
name="Check Dave's Password:" value="Check Password" type="SUBMIT"/></td>
<td></td>
</tr>
</table>
</form>
<!-- do not remove the two following div's, this is where your feedback/output will land -->
<div class="attack-feedback"></div>
<div class="attack-output"></div>
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
</div>
</div>
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content7.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content8.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content9.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content10.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content11.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content12.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
<div class="adoc-content" th:replace="doc:SqlInjection_content13.adoc"></div>
</div>
</html> </html>

View File

@ -0,0 +1,166 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjectionAdvanced_plan.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_content6.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_content6a.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/SqlInjection/attack6a"
enctype="application/json;charset=UTF-8">
<table>
<tr>
<td>Name:</td>
<td><input name="userid_6a" value="" type="TEXT"/></td>
<td><input
name="Get Account Info" value="Get Account Info" type="SUBMIT"/></td>
<td></td>
</tr>
</table>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/SqlInjection/attack6b"
enctype="application/json;charset=UTF-8">
<table>
<tr>
<td>Password:</td>
<td><input name="userid_6b" value="" type="TEXT"/></td>
<td><input
name="Check Dave's Password:" value="Check Password" type="SUBMIT"/></td>
<td></td>
</tr>
</table>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_content6c.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_challenge.adoc"></div>
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/challenge.css}"/>
<script th:src="@{/lesson_js/challenge.js}" language="JavaScript"></script>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="container-fluid">
<div class="row">
<div class="col-md-6">
<div class="panel panel-login">
<div class="panel-heading">
<div class="row">
<div class="col-xs-6">
<a href="#" class="active" id="login-form-link">Login</a>
</div>
<div class="col-xs-6">
<a href="#" id="register-form-link">Register</a>
</div>
</div>
<hr/>
</div>
<div class="panel-body">
<div class="row">
<div class="col-lg-12">
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="SqlInjection/attack7"
enctype="application/json;charset=UTF-8" role="form">
<div class="form-group">
<input type="text" name="username_login" id="username4" tabindex="1"
class="form-control" placeholder="Username" value=""/>
</div>
<div class="form-group">
<input type="password" name="password_login" id="password4" tabindex="2"
class="form-control" placeholder="Password"/>
</div>
<div class="form-group text-center">
<input type="checkbox" tabindex="3" class="" name="remember" id="remember"/>
<label for="remember"> Remember me</label>
</div>
<div class="form-group">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<input type="submit" name="login-submit" id="login-submit"
tabindex="4" class="form-control btn-primary"
value="Log In"/>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-lg-12">
<div class="text-center">
<a href="#" tabindex="5" class="forgot-password">Forgot
Password?</a>
</div>
</div>
</div>
</div>
</form>
<form id="register-form" class="attack-form" accept-charset="UNKNOWN"
method="PUT" name="form"
action="SqlInjection/attack7"
enctype="application/json;charset=UTF-8" style="display: none;" role="form">
<div class="form-group">
<input type="text" name="username_reg" id="username" tabindex="1"
class="form-control" placeholder="Username" value=""/>
</div>
<div class="form-group">
<input type="email" name="email_reg" id="email" tabindex="1"
class="form-control" placeholder="Email Address" value=""/>
</div>
<div class="form-group">
<input type="password" name="password_reg" id="password" tabindex="2"
class="form-control" placeholder="Password"/>
</div>
<div class="form-group">
<input type="password" name="confirm_password_reg" id="confirm-password"
tabindex="2" class="form-control" placeholder="Confirm Password"/>
</div>
<div class="form-group">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<input type="submit" name="register-submit" id="register-submit"
tabindex="4" class="form-control btn btn-primary"
value="Register Now"/>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<br/>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -0,0 +1,112 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_content7.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_content8.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_content9.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_content10.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_content11.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_content12.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_content12a.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_order_by.adoc"></div>
<script th:src="@{/lesson_js/assignment12.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" name="form"
action="/WebGoat/SqlInjection/attack12a"
enctype="application/json;charset=UTF-8">
<div class="container-fluid">
<div class="row">
<div class="panel panel-primary">
<div class="panel-heading">
<h3>List of servers
<div class="pull-right">
<button id="btn-admin" class="btn btn-default"><span
class="glyphicon glyphicon-pencil"></span> Edit
</button>
</div>
</h3>
</div>
<div id="toolbar-admin" class="panel-body">
<div class="btn-toolbar" role="toolbar" aria-label="admin">
<div class="btn-group pull-right" role="group">
<button id="btn-online" type="button" class="btn btn-success">Online</button>
<button id="btn-offline" type="button" class="btn btn-warning">Offline</button>
<button id="btn-out-of-order" type="button" class="btn btn-danger">Out Of Order
</button>
</div>
</div>
</div>
<table class="table table-striped table-hover">
<thead>
<tr>
<th class="col-check"></th>
<th></th>
<th>Hostname <span onclick="getServers('hostname')"><i
class="fa fa-fw fa-sort"></i></span>
</th>
<th>IP <span onclick="getServers('ip')"><i class="fa fa-fw fa-sort"></i></span></th>
<th>MAC <span onclick="getServers('mac')"><i class="fa fa-fw fa-sort"></i></span></th>
<th>Status <span onclick="getServers('status')"><i class="fa fa-fw fa-sort"></i></span>
</th>
<th>Description <span onclick="getServers('description')"><i
class="fa fa-fw fa-sort"></i></span>
</th>
</tr>
</thead>
<tbody id="servers">
</tbody>
</table>
</div>
</div>
<br/>
<br/>
</div>
</form>
<form class="attack-form" method="POST" name="form" action="SqlInjection/attack12a">
<div class="form-group">
<div class="input-group">
<div class="input-group-addon">IP address webgoat-prd server:</div>
<input type="text" class="form-control" id="ip" name="ip"
placeholder="192.1.0.12"/>
</div>
<div class="input-group" style="margin-top: 10px">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:SqlInjection_content13.adoc"></div>
</div>
</html>

View File

@ -6,7 +6,13 @@ SqlStringInjectionHint1=The application is taking your input and inserting it at
SqlStringInjectionHint2=This is the code for the query being built and issued by WebGoat:<br><br> "SELECT * FROM user_data WHERE last_name = "accountName" SqlStringInjectionHint2=This is the code for the query being built and issued by WebGoat:<br><br> "SELECT * FROM user_data WHERE last_name = "accountName"
SqlStringInjectionHint3=Compound SQL statements can be made by joining multiple tests with keywords like AND and OR. Try appending a SQL statement that always resolves to true SqlStringInjectionHint3=Compound SQL statements can be made by joining multiple tests with keywords like AND and OR. Try appending a SQL statement that always resolves to true
SqlStringInjectionHint4=Try entering [ smith' OR '1' = '1 ]. SqlStringInjectionHint4=Try entering [ smith' OR '1' = '1 ].
SqlStringInjectionHint5=First try to find out the number of columns by adding a group by 1,2,3 etc to the query.
SqlStringInjectionHint6=Try adding a union to the query, the number of columns should match.
SqlStringInjectionHint7=Try entering [ Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data -- ].
SqlStringInjectionHint8=Try sorting and look at the request
SqlStringInjectionHint9=Intercept the request and try to specify a different order by
SqlStringInjectionHint10=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
SqlStringInjectionHint11=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
sql-injection.5a.success=You have succeed: {0} sql-injection.5a.success=You have succeed: {0}
sql-injection.5a.no.results=No results matched. Try Again. sql-injection.5a.no.results=No results matched. Try Again.

View File

@ -0,0 +1,61 @@
$(function () {
$('.col-check').hide();
$('#btn-admin').on('click', function () {
if ($("#toolbar-admin").is(":visible")) {
$("#toolbar-admin").hide();
$(".col-check").hide();
}
else {
$("#toolbar-admin").show();
$(".col-check").show();
}
});
$('#btn-online').on('click', function () {
$('table tr').filter(':has(:checkbox:checked)').find('td').parent().removeClass().addClass('success');
$('table tr').filter(':has(:checkbox:checked)').find('td.status').text('online');
});
$('#btn-offline').on('click', function () {
$('table tr').filter(':has(:checkbox:checked)').find('td').parent().removeClass().addClass('warning');
$('table tr').filter(':has(:checkbox:checked)').find('td.status').text('offline');
});
$('#btn-out-of-order').on('click', function () {
$('table tr').filter(':has(:checkbox:checked)').find('td').parent().removeClass().addClass('danger');
$('table tr').filter(':has(:checkbox:checked)').find('td.status').text('out of order');
});
});
$(document).ready(function () {
getServers('id');
});
var html = '<tr class="STATUS">' +
'<td class="col-check"><input type="checkbox" class="form-check-input"/></td>' +
'<td>HOSTNAME</td>' +
'<td>IP</td>' +
'<td>MAC</td>' +
'<td class="status">ONLINE</td>' +
'<td>DESCRIPTION</td>' +
'</tr>';
function getServers(column) {
$.get("SqlInjection/servers?column=" + column, function (result, status) {
$("#servers").empty();
for (var i = 0; i < result.length; i++) {
var server = html.replace('ID', result[i].id);
var status = "success";
if (result[i].status === 'offline') {
status = "danger";
}
server = server.replace('ONLINE', status);
server = server.replace('STATUS', status);
server = server.replace('HOSTNAME', result[i].hostname);
server = server.replace('IP', result[i].ip);
server = server.replace('MAC', result[i].mac);
server = server.replace('DESCRIPTION', result[i].description);
$("#servers").append(server);
}
});
}

View File

@ -0,0 +1,18 @@
$(function() {
$('#login-form-link').click(function(e) {
$("#login-form").delay(100).fadeIn(100);
$("#register-form").fadeOut(100);
$('#register-form-link').removeClass('active');
$(this).addClass('active');
e.preventDefault();
});
$('#register-form-link').click(function(e) {
$("#register-form").delay(100).fadeIn(100);
$("#login-form").fadeOut(100);
$('#login-form-link').removeClass('active');
$(this).addClass('active');
e.preventDefault();
});
});

View File

@ -0,0 +1,8 @@
== Concept
This lesson describes the more advanced topics for an SQL injection.
== Goals
** Combining SQL Injection Techniques
** Blind SQL injection

View File

@ -0,0 +1,4 @@
We now explained the basic steps involved in an SQL injection. In this assignment you will need to combine all
the things we explained in the SQL lessons.
Have fun!

View File

@ -1,35 +1,28 @@
== Parameterized Queries Java Example == Parameterized Queries Java Example
[source,java]
------------------------------------------------------- -------------------------------------------------------
// Parser returns only valid string data public static String loadAccount() {
String accountID = getParser().getStringParameter(ACCT_ID, ""); // Parser returns only valid string data
String data = null; String accountID = getParser().getStringParameter(ACCT_ID, "");
try String data = null;
{ String query = "SELECT first_name, last_name, acct_id, balance FROM user_data WHERE acct_id = ?";
// Read only database connection try (Connection connection = null;
Statement connection = DatabaseUtilities.getConnection(READ_ONLY); PreparedStatement statement = connection.prepareStatement(query)) {
// Build a fully qualified query
String query = "SELECT first_name, last_name, acct_id, balance
FROM user_data WHERE acct_id = ?";
PreparedStatement statement = connection.prepareStatement(query);
statement.setString(1, accountID); statement.setString(1, accountID);
ResultSet results = statement.executeQuery(); ResultSet results = statement.executeQuery();
if ((results != null) && (results.first() == true)) if (results != null && results.first()) {
{ results.last(); // Only one record should be returned for this query
// Only one record should be returned for this query if (results.getRow() <= 2) {
Results.last();
if (results.getRow() <= 2)
{
data = processAccount(results); data = processAccount(results);
} else {
// Handle the error Database integrity issue
} }
else { // Handle the error Database integrity issue } } else {
// Handle the error no records found }
} }
else { // Handle the error no records found } } catch (SQLException sqle) {
// Log and handle the SQL Exception }
}
return data;
} }
catch (SQLException sqle) { // Log and handle the SQL Exception }
catch (Exception e) { // Log and handle the Exception }
finally { // Always close connection in finally block
DatabaseUtilities.closeConnection();
}
return data;
------------------------------------------------------- -------------------------------------------------------

View File

@ -0,0 +1,48 @@
== Order by clause
Question: Does a preparared statement always prevent against an SQL injection?
Answer: No it does not
Let's take a look at the following statement:
----
select * from users order by lastname;
----
If we look at the specification of the SQL grammar the definition is as follows:
----
SELECT ...
FROM tableList
[WHERE Expression]
[ORDER BY orderExpression [, ...]]
orderExpression:
{ columnNr | columnAlias | selectExpression }
[ASC | DESC]
selectExpression:
{ Expression | COUNT(*) | {
COUNT | MIN | MAX | SUM | AVG | SOME | EVERY |
VAR_POP | VAR_SAMP | STDDEV_POP | STDDEV_SAMP
} ([ALL | DISTINCT][2]] Expression) } [[AS] label]
Based on HSQLDB
----
This means an `orderExpression` van be a `selectExpression` which can be a function as well, so for example with
a `case` statement we might be able to ask the database some questions, like:
----
select * from users order by
(select case when (true) then lastname else firstname)
----
So we can substitute any kind of boolean operation in the `when(....)` part. The statement will just work because
it is a valid query whether you use a prepared statement or not an order by clause can by definition contain a
expression.
=== Mitigation
If you need to provide a sorting column in your web application you should implement a whitelist to validate the value
of the `order by` statement it should always be limited to something like 'firstname' or 'lastname'.

View File

@ -0,0 +1,59 @@
== Blind SQL Injection
Blind SQL injection is a type of SQL injection attack that asks the database true or false
questions and determines the answer based on the applications response. This attack is often used when the web
application is configured to show generic error messages, but has not mitigated the code that is vulnerable to SQL
injection.
=== Difference
Let's first start with the difference between a normal SQL injection and a blind SQL injection. In a normal
SQL injection the error messages from the database are displayed and gives enough information to find out how
the query is working. Or in the case of an union based SQL injection the application does not reflect the information
directly on the webpage. So in the case where nothing is displayed you will need to start asking the database questions
based on a true or false statement. That's why a blind SQL injection is much more difficult to exploit.
There are several different types of blind SQL injections: content based and time based SQL injections.
=== Example
In this case we are trying to ask the database a boolean question based on for example a unique id, for example
suppose we have the following url: `https://my-shop.com?article=4`
On the server side this query will be translated as follows:
----
SELECT * from articles where article_id = 4
----
When we want to exploit this we change the url into: `https://my-shop.com?article=4 AND 1=1`
This will be translated to:
----
SELECT * from articles where article_id = 4 AND 1 = 1
----
If the browser will return the same page as it used to when using `https://my-shop.com?article=4` you know the
website is vulnerable for a blind SQL injection.
If the browser responds with a page not found or something else you know a blind SQL injection might not work.
You can now change the SQL query and test for example: `https://my-shop.com?article=4 AND 1=2` which will not return
anything because the query returns false.
So but how do we actually take advantage of this? Above we only asked the database for trivial question but you can
for example also use the following url: `https://my-shop.com?article=4 AND substring(database_version(),1,1) = 2`
Most of the time you start by finding which type of database is used, based on the type of database you can find
the system tables of the database you can enumerate all the tables present in the database. With this information
you can start getting information from all the tables and you are able to dump the database.
Be aware that this approach might not work if the privileges of the database are setup correctly (meaning the
system tables cannot be queried with the user used to connect from the web application to the database).
Another way is called a time based SQL injection, in this case you will ask the database to wait before returning
the result. You might need to use this if you are totally blind so there is no difference between the response you
can use for example:
----
article = 4; sleep(10) --
----

View File

@ -0,0 +1,4 @@
In this assignment try to perform an SQL injection through the ORDER BY field.
Try to find the ip address of the `webgoat-prd` server.
Note: The submit field of this assignment is *NOT* vulnerable for an SQL injection.

View File

@ -9,5 +9,4 @@ This lesson describes what is Structured Query Language (SQL) and how it can be
* The user will demonstrate knowledge on: * The user will demonstrate knowledge on:
** String SQL Injection ** String SQL Injection
** Numeric SQL Injection ** Numeric SQL Injection
** Combining SQL Injection Techniques

View File

@ -0,0 +1,81 @@
package org.owasp.webgoat.plugin.introduction;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.plugins.LessonTest;
import org.owasp.webgoat.session.WebgoatContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author nbaars
* @since 5/21/17.
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class SqlInjectionLesson5aTest extends LessonTest {
@Autowired
private WebgoatContext context;
@Before
public void setup() throws Exception {
SqlInjection sql = new SqlInjection();
when(webSession.getCurrentLesson()).thenReturn(sql);
when(webSession.getWebgoatContext()).thenReturn(context);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void knownAccountShouldDisplayData() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5a")
.param("account", "Smith"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(jsonPath("lessonCompleted", is(false)))
.andExpect(jsonPath("$.feedback", is(messages.getMessage("assignment.not.solved"))))
.andExpect(jsonPath("$.output", containsString("<p>USERID, FIRST_NAME")));
}
@Test
public void unknownAccount() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5a")
.param("account", "Smithh"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(jsonPath("lessonCompleted", is(false)))
.andExpect(jsonPath("$.feedback", is(messages.getMessage("NoResultsMatched"))))
.andExpect(jsonPath("$.output").doesNotExist());
}
@Test
public void sqlInjection() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5a")
.param("account", "smith' OR '1' = '1"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(jsonPath("lessonCompleted", is(true)))
.andExpect(jsonPath("$.feedback", containsString("You have succeed")))
.andExpect(jsonPath("$.output").doesNotExist());
}
@Test
public void sqlInjectionWrongShouldDisplayError() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5a")
.param("account", "smith' OR '1' = '1'"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(jsonPath("lessonCompleted", is(false)))
.andExpect(jsonPath("$.feedback", containsString(messages.getMessage("assignment.not.solved"))))
.andExpect(jsonPath("$.output", is("malformed string: '1''")));
}
}

View File

@ -0,0 +1,81 @@
package org.owasp.webgoat.plugin.introduction;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author nbaars
* @since 6/15/17.
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class SqlInjectionLesson6aTest extends LessonTest {
@Before
public void setup() throws Exception {
when(webSession.getCurrentLesson()).thenReturn(new SqlInjection());
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void wrongSolution() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6a")
.param("userid_6a", "John"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.lessonCompleted", is(false)));
}
@Test
public void wrongNumberOfColumns() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6a")
.param("userid_6a", "Smith' union select userid,user_name, password,cookie from user_system_data --"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.lessonCompleted", is(false)))
.andExpect(jsonPath("$.output", is("column number mismatch detected in rows of UNION, INTERSECT, EXCEPT, or VALUES operation")));
}
@Test
public void wrongDataTypeOfColumns() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6a")
.param("userid_6a", "Smith' union select 1,password, 1,'2','3', '4',1 from user_system_data --"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.lessonCompleted", is(false)))
.andExpect(jsonPath("$.output", containsString("incompatible data types in combination")));
}
@Test
public void correctSolution() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6a")
.param("userid_6a", "Smith' union select 1,password, '1','2','3', '4',1 from user_system_data --"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.lessonCompleted", is(true)))
.andExpect(jsonPath("$.feedback", containsString("dave")));
}
@Test
public void noResultsReturned() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6a")
.param("userid_6a", "Smith' and 1 = 2 --"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.lessonCompleted", is(false)))
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.6a.no.results"))));
}
}

View File

@ -0,0 +1,46 @@
package org.owasp.webgoat.plugin.introduction;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**a
* @author nbaars
* @since 6/16/17.
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class SqlInjectionLesson6bTest extends LessonTest {
@Before
public void setup() throws Exception {
when(webSession.getCurrentLesson()).thenReturn(new SqlInjection());
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void submitCorrectPassword() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6b")
.param("userid_6b", "dave"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true)));
}
@Test
public void submitWrongPassword() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6b")
.param("userid_6b", "John"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false)));
}
}

View File

@ -0,0 +1,96 @@
package org.owasp.webgoat.plugin.mitigation;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.plugin.introduction.SqlInjection;
import org.owasp.webgoat.plugins.LessonTest;
import org.owasp.webgoat.session.WebgoatContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author nbaars
* @since 5/21/17.
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class SqlInjectionLesson12aTest extends LessonTest {
@Autowired
private WebgoatContext context;
@Before
public void setup() throws Exception {
SqlInjection sql = new SqlInjection();
when(webSession.getCurrentLesson()).thenReturn(sql);
when(webSession.getWebgoatContext()).thenReturn(context);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void knownAccountShouldDisplayData() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
.param("column", "id"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk());
}
@Test
public void trueShouldSortByHostname() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
.param("column", "(case when (true) then hostname else id end)"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc")));
}
@Test
public void falseShouldSortById() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
.param("column", "(case when (true) then hostname else id end)"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc")));
}
@Test
public void passwordIncorrectShouldOrderByHostname() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
.param("column", "CASE WHEN (SELECT ip FROM servers WHERE hostname='webgoat-prd') LIKE '192.%' THEN hostname ELSE id END"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-dev")));
}
@Test
public void passwordCorrectShouldOrderByHostname() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
.param("column", "CASE WHEN (SELECT ip FROM servers WHERE hostname='webgoat-prd') LIKE '104.%' THEN hostname ELSE id END"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc")));
}
@Test
public void postingCorrectAnswerShouldPassTheLesson() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack12a")
.param("ip", "104.130.219.202"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true)));
}
@Test
public void postingWrongAnswerShouldNotPassTheLesson() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack12a")
.param("ip", "192.168.219.202"))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false)));
}
}

Binary file not shown.

View File

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

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,65 @@
package org.owasp.webgoat.plugin;
import com.beust.jcommander.internal.Lists;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import java.util.List;
/**
* ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>
*
* @author misfir3
* @version $Id: $Id
* @since January 3, 2017
*/
public class LessonTemplate extends NewLesson {
@Override
public Category getDefaultCategory() {
return Category.GENERAL;
}
@Override
public List<String> getHints() {
return Lists.newArrayList();
}
@Override
public Integer getDefaultRanking() {
return 30;
}
@Override
public String getTitle() {
return "lesson-template.title";
}
@Override
public String getId() {
return "LessonTemplate";
}
}

View File

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

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