Compare commits

..

65 Commits

Author SHA1 Message Date
985148ede3 Merge branch 'release/v8.0.0' 2018-05-29 14:59:07 +02:00
9587550bc5 Fixed column name on sql injection lesson 7 2018-05-29 14:42:22 +02:00
9a0995dae5 Fixed column name on sql injection lesson 6 2018-05-29 14:42:02 +02:00
4e07e0ebfa Fix links to open new browser tab 2018-05-29 14:04:33 +02:00
6e95fdfe56 Adjusted documentation 2018-05-29 13:33:52 +02:00
e045bc692d Buying page also calculates the prices
Product image added
2018-05-29 12:47:27 +02:00
589872ad47 Fix for JWT assignment 1 log in now works again.
Reset button only triggers reset when admin is set to true in the token
2018-05-29 11:20:40 +02:00
5f4889cefe Clicking link in first password reset link only switched back and forward 2018-05-29 09:29:50 +02:00
55793dd153 New release v8.0.0.M15 2018-05-27 20:54:50 +02:00
1edceb0aa8 Extended and fixed some lessons 2018-05-27 20:37:44 +02:00
d2b6725f3b Moved challenge2 to client-side-filtering as final assignment 2018-05-27 12:41:52 +02:00
6e003bc088 Working last password assignment 2018-05-26 18:48:48 +02:00
f8a7a61e85 New lesson working 2018-05-26 15:09:18 +02:00
eaf68d38c5 Initial commit for password reset lesson 2018-05-25 14:27:45 +02:00
8d7ecb19d7 Added testcases for all JWT endpoints 2018-05-23 14:28:19 +02:00
e0cf5b4a84 Removed under construction from JWT lesson 2018-05-23 14:28:19 +02:00
5b524d3a94 Added more unit tests 2018-05-23 14:28:19 +02:00
dda6f674a3 Last assignment for JWT tokens finished 2018-05-23 14:28:19 +02:00
e06d4642eb Fix error in testcase 2018-05-23 14:28:19 +02:00
4a8fdcf887 Fix content-type for login (gives error in console of browser) 2018-05-23 14:28:19 +02:00
fd96ba18f1 Added test cases for solving the lesson 2018-05-23 14:28:19 +02:00
60ef35e241 Working lesson 2018-05-23 14:28:19 +02:00
9d7886d572 More JWT work 2018-05-23 14:28:19 +02:00
7a0820bf89 WIP 2018-05-23 14:28:19 +02:00
ea9c1a453d Initial version for JWT 2018-05-23 14:28:19 +02:00
63ca11a1bb Change WebWolf to WebGoat
The links for the WebGoat download were mislabeled as WebWolf
2018-05-23 14:07:32 +02:00
5378d72600 Change version in pom.xml 2018-05-23 14:04:21 +02:00
93d6d0e6b7 Added lesson texts 2018-05-23 13:58:37 +02:00
84860e65f6 Insecure Deserialization exercise 2018-05-23 13:58:03 +02:00
a73bf58d36 more hintview patching 2018-05-23 13:35:51 +02:00
0ff6000511 wiring jqueryui to vuln jquery #368 2018-05-23 13:35:51 +02:00
91d9db5f80 work-arounds, fixes for page initialization and some clean-up 2018-05-23 13:35:51 +02:00
ac1b9e8311 cleanup that was missed in prev. commit 2018-05-23 13:35:51 +02:00
9d49373486 fix for periodic fail on StoredXssCommentsTest 2018-05-23 13:35:51 +02:00
ead78d40e6 Chore - fix spelling issues 2018-05-23 13:35:51 +02:00
7b5bb6d6f1 Fixed typos 2018-05-23 13:35:51 +02:00
408a637649 Update HttpBasics_ProxyIntro0.adoc
Fixed typo, Actual : "wihtin" , Expected :  "within"
2018-05-23 13:35:51 +02:00
6cf96f971d Fix typo 2018-05-11 15:14:11 +02:00
0b9a027c19 Fix some minor grammatical issues. 2018-05-11 15:13:30 +02:00
6a5ca43e7e Strip out slash-escaped JSON sequence received in client.
The server will slash-escape some JSON related characters before sending. Need to strip them out before using, on the client side.
2018-05-02 22:21:22 +02:00
5d28ef9fbe small fix for CSRF content type lesson descrption 2018-05-02 22:10:06 +02:00
9aa674e326 stringfy object so it's visible in the console 2018-05-02 22:04:25 +02:00
84e3fcde07 Added .sonatype (author: @maurycupitt) 2018-05-02 21:34:17 +02:00
6209b3fe8d Updated lesson for starting WebWolf as a Docker container 2018-05-02 21:25:44 +02:00
a1db8e8bd9 Added documentation how to mount the data directory of WebGoat running in Docker to your host system. 2018-05-02 09:29:52 +02:00
6b4a488c8c Users shared now between WebGoat and WebWolf by starting HSQLDB
as standalone database
2018-05-01 22:00:07 +02:00
0e160c19f5 Docker-compose for postgres and hsqldb 2018-05-01 21:58:43 +02:00
8050a2b56d XXE lesson not showing correct link for WebWolf 2018-05-01 21:54:28 +02:00
11ffa5702c Added "WebWolf" enabled to the lessons which support the usage of WebWolf 2018-04-29 15:02:19 +02:00
32927c8109 Bumped Spring Boot version 2018-04-28 16:02:09 +02:00
8b8a89a8ab Add extra informational message when a failure occurs while sending an email from WebGoat to WebWolf. 2018-04-28 16:01:57 +02:00
e4ca0c4836 Make report working again 2018-04-27 19:26:01 +02:00
e422da4c64 Polling for lesson updates (updates the menu and page navigation) 2018-04-27 18:50:13 +02:00
76daac0db5 Label was missing for HTTP basic lesson 2018-04-27 11:29:52 +02:00
245ba2c3d1 Fix XXE lesson, the exact .webgoat directory including version number will be put in the lesson. 2018-04-24 20:44:05 +02:00
672d78eebc Resource bundle in UTF-8 2018-04-23 16:12:50 +02:00
f4eb96fc6a Add additional remark WebWolf should be running if interaction is necessary 2018-04-23 11:32:07 +02:00
46fedf3764 Fix for Docker command to start WebWolf 2018-04-23 11:20:25 +02:00
f30db3abfc New version number 2018-04-11 20:45:12 +02:00
58d4b81df2 Wrong image name mentioned in lesson for WebWolf 2018-04-11 20:22:19 +02:00
2ae1b4955f By default binds to ALL network interfaces #431
Fix for Docker not binding to any address by default
2018-01-30 07:18:05 +01:00
13a4b69cbe All lesson flags are displayed while running webgoat 8.0 standalone java file #430 2018-01-29 15:43:19 +01:00
98efc1235f By default binds to ALL network interfaces #431 2018-01-29 15:32:02 +01:00
b99b554522 Version: docker 8.0.0.M9 Multiple users can't finalize the same lesson #432 2018-01-29 15:29:48 +01:00
e3e7ed004f Not making a Docker release is we build develop (putting a tag will create a release which is more a controlled/intuitive way to make a release to Docker) 2018-01-02 22:19:49 +01:00
218 changed files with 3834 additions and 889 deletions

4
.gitignore vendored
View File

@ -42,3 +42,7 @@ webgoat-lessons/**/target
**/.DS_Store
webgoat-server/mongo-data/*
webgoat-lessons/vulnerable-components/dependency-reduced-pom.xml
**/.sts4-cache/*
**/.vscode/*
/.sonatype

View File

@ -20,8 +20,8 @@ git flow release publish
Now we can make a new release, be sure you committed all your changes.
```
git tag v8.0.0.M3
git push origin v8.0.0.M3
git tag v8.0.0.M15
git push origin v8.0.0.M15
```
Now Travis takes over and will create the release in Github and on Docker Hub.

View File

@ -40,6 +40,15 @@ docker pull webgoat/webgoat-8.0
docker run -p 8080:8080 -it webgoat/webgoat-8.0 /home/webgoat/start.sh
```
If you want to keep the database between Docker sessions you need to map the WebGoat data directory to a
folder on the host system as follows:
```Shell
docker run -p 8080:8080 -it -v /tmp/webgoat-data:/home/webgoat/.webgoat-${VERSION} webgoat/webgoat-8.0 /home/webgoat/start.sh
```
where `${VERSION}` is for example `v8.0.0.M14`. The data will now be stored in `/tmp/webgoat-data` on your host system.
Wait for the Docker container to start, and run `docker ps` to verify it's running.
- If you are using `docker-machine`, verify the machine IP using `docker-machine env`
@ -58,7 +67,7 @@ _Please note: this version may not be completely in sync with the develop branch
## 2. Standalone
Download the latest WebWolf release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases)
Download the latest WebGoat release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases)
```Shell
java -jar webgoat-server-<<version>>.jar

View File

@ -0,0 +1,35 @@
version: '2.0'
services:
webgoat:
image: webgoat/webgoat-8.0
user: webgoat
environment:
- WEBWOLF_HOST=webwolf
- spring.datasource.url=jdbc:postgresql://webgoat_db:5432/webgoat
- spring.datasource.username=webgoat
- spring.datasource.password=webgoat
- spring.datasource.driver-class-name=org.postgresql.Driver
- spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL94Dialect
ports:
- "8080:8080"
webwolf:
image: webgoat/webwolf
environment:
- spring.datasource.url=jdbc:postgresql://webgoat_db:5432/webgoat
- spring.datasource.username=webgoat
- spring.datasource.password=webgoat
- spring.datasource.driver-class-name=org.postgresql.Driver
- spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL94Dialect
ports:
- "8081:8081"
db:
container_name: webgoat_db
image: postgres:latest
environment:
- POSTGRES_PASSWORD=webgoat
- POSTGRES_USER=webgoat
- POSTGRES_DB=webgoat
ports:
- "5432:5432"

View File

@ -1,15 +1,28 @@
version: '2.0'
version: '2.1'
services:
webgoat:
build: webgoat-server/
command: "sh /home/webgoat/start.sh"
image: webgoat/webgoat-8.0
environment:
- WEBWOLF_HOST=webwolf
- spring.datasource.url=jdbc:hsqldb:hsql://webgoat_db:9001/webgoat
ports:
- "8080:8080"
webwolf:
build: webwolf/
command: "sh /home/webwolf/start.sh"
depends_on:
- webgoat
- db
webwolf:
image: webgoat/webwolf
environment:
- spring.datasource.url=jdbc:hsqldb:hsql://webgoat_db:9001/webgoat
ports:
- "8081:8081"
- "8081:8081"
depends_on:
- db
db:
image: blacklabelops/hsqldb
container_name: webgoat_db
environment:
- HSQLDB_TRACE=false
- HSQLDB_SILENT=true
- HSQLDB_DATABASE_NAME=webgoat
- HSQLDB_DATABASE_ALIAS=webgoat

View File

@ -5,7 +5,7 @@
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-parent</artifactId>
<packaging>pom</packaging>
<version>8.0.0.M3</version>
<version>v8.0.0.M15</version>
<name>WebGoat Parent Pom</name>
<description>Parent Pom for the WebGoat Project. A deliberately insecure Web Application</description>
@ -20,7 +20,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<version>1.5.12.RELEASE</version>
</parent>
<licenses>
@ -135,7 +135,7 @@
<gatling-plugin.version>2.2.4</gatling-plugin.version>
<guava.version>18.0</guava.version>
<h2.version>1.4.190</h2.version>
<hsqldb.version>2.3.2</hsqldb.version>
<hsqldb.version>2.3.4</hsqldb.version>
<j2h.version>1.3.1</j2h.version>
<jackson-core.version>2.6.3</jackson-core.version>
<jackson-databind.version>2.6.3</jackson-databind.version>

View File

@ -17,6 +17,24 @@ elif [ ! -z "${TRAVIS_TAG}" ]; then
#elif [ "${BRANCH}" == "develop" ]; then
# docker build -f Dockerfile -t $REPO:snapshot .
# docker push $REPO
else
echo "Skipping releasing to DockerHub because it is a build of branch ${BRANCH}"
fi
export REPO=webgoat/webwolf
cd ..
cd webwolf
ls target/
if [ "${BRANCH}" == "master" ] && [ ! -z "${TRAVIS_TAG}" ]; then
# If we push a tag to master this will update the LATEST Docker image and tag with the version number
docker build --build-arg webwolf_version=${TRAVIS_TAG:1} -f Dockerfile -t $REPO:latest -t $REPO:${TRAVIS_TAG} .
docker push $REPO
elif [ ! -z "${TRAVIS_TAG}" ]; then
# Creating a tag build we push it to Docker with that tag
docker build --build-arg webwolf_version=${TRAVIS_TAG:1} -f Dockerfile -t $REPO:${TRAVIS_TAG} -t $REPO:latest .
docker push $REPO
else
echo "Skipping releasing to DockerHub because it is a build of branch ${BRANCH}"
fi

View File

@ -10,7 +10,7 @@
<parent>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-parent</artifactId>
<version>8.0.0.M3</version>
<version>v8.0.0.M15</version>
</parent>
<profiles>

View File

@ -35,6 +35,7 @@ import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.extension.JavaExtensionRegistry;
import org.owasp.webgoat.asciidoc.WebGoatVersionMacro;
import org.owasp.webgoat.asciidoc.WebWolfMacro;
import org.owasp.webgoat.i18n.Language;
import org.thymeleaf.TemplateProcessingParameters;
@ -86,6 +87,7 @@ public class AsciiDoctorTemplateResolver extends TemplateResolver {
StringWriter writer = new StringWriter();
JavaExtensionRegistry extensionRegistry = asciidoctor.javaExtensionRegistry();
extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class);
extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class);
asciidoctor.convert(new InputStreamReader(is), writer, createAttributes());
return new ByteArrayInputStream(writer.getBuffer().toString().getBytes(UTF_8));

View File

@ -130,6 +130,7 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
@Bean
public PluginMessages pluginMessages(Messages messages, Language language) {
PluginMessages pluginMessages = new PluginMessages(messages, language);
pluginMessages.setDefaultEncoding("UTF-8");
pluginMessages.setBasenames("i18n/WebGoatLabels");
return pluginMessages;
}
@ -142,6 +143,7 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
@Bean
public Messages messageSource(Language language) {
Messages messages = new Messages(language);
messages.setDefaultEncoding("UTF-8");
messages.setBasename("classpath:i18n/messages");
return messages;
}

View File

@ -0,0 +1,23 @@
package org.owasp.webgoat.asciidoc;
import org.asciidoctor.ast.AbstractBlock;
import org.asciidoctor.extension.InlineMacroProcessor;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
public class WebGoatVersionMacro extends InlineMacroProcessor {
public WebGoatVersionMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
@Override
protected String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
return EnvironmentExposure.getEnv().getProperty("webgoat.build.version");
}
}

View File

@ -10,6 +10,12 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* Usage in asciidoc:
* <p>
* webWolfLink:here[] will display a href with here as text
* webWolfLink:landing[noLink] will display the complete url, for example: http://WW_HOST:WW_PORT/landing
*/
public class WebWolfMacro extends InlineMacroProcessor {
public WebWolfMacro(String macroName, Map<String, Object> config) {
@ -20,9 +26,17 @@ public class WebWolfMacro extends InlineMacroProcessor {
protected String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
Environment env = EnvironmentExposure.getEnv();
String hostname = determineHost(env.getProperty("webwolf.host"), env.getProperty("webwolf.port"));
if (displayCompleteLinkNoFormatting(attributes)) {
return hostname + (hostname.endsWith("/") ? "" : "/") + target;
}
return "<a href=\"" + hostname + "\" target=\"_blank\">" + target + "</a>";
}
private boolean displayCompleteLinkNoFormatting(Map<String, Object> attributes) {
return attributes.values().stream().filter(a -> a.equals("noLink")).findFirst().isPresent();
}
/**
* Look at the remote address from received from the browser first. This way it will also work if you run
* the browser in a Docker container and WebGoat on your local machine.

View File

@ -55,7 +55,7 @@ public abstract class AssignmentEndpoint extends Endpoint {
//// TODO: 11/13/2016 events better fit?
protected AttackResult trackProgress(AttackResult attackResult) {
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
if (userTracker == null) {
userTracker = new UserTracker(webSession.getUserName());
}

View File

@ -1,11 +1,9 @@
package org.owasp.webgoat.lessons;
import com.google.common.collect.Lists;
import lombok.*;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import javax.persistence.*;
import java.util.List;
/**
@ -37,19 +35,30 @@ import java.util.List;
* @version $Id: $Id
* @since November 25, 2016
*/
@AllArgsConstructor
@RequiredArgsConstructor
@NoArgsConstructor
@Getter
@EqualsAndHashCode
@Entity
public class Assignment {
@NonNull
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@NonNull
private String path;
@Transient
private List<String> hints;
private Assignment() {
//Hibernate
}
public Assignment(String name, String path) {
this(name, path, Lists.newArrayList());
}
public Assignment(String name, String path, List<String> hints) {
this.name = name;
this.path = path;
this.hints = hints;
}
}

View File

@ -46,6 +46,7 @@ public enum Category {
INSECURE_CONFIGURATION("Insecure Configuration", new Integer(600)),
INSECURE_COMMUNICATION("Insecure Communication", new Integer(700)),
INSECURE_STORAGE("Insecure Storage", new Integer(800)),
INSECURE_DESERIALIZATION("Insecure Deserialization", new Integer(850)),
REQUEST_FORGERIES("Request Forgeries", new Integer(900)),
VULNERABLE_COMPONENTS("Vulnerable Components - A9", new Integer(950)),
AJAX_SECURITY("AJAX Security", new Integer(1000)),

View File

@ -2,7 +2,6 @@ package org.owasp.webgoat.lessons;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.owasp.webgoat.session.WebSession;
/**
* <p>LessonInfoModel class.</p>

View File

@ -73,7 +73,7 @@ public class LessonMenuService {
List<LessonMenuItem> showLeftNav() {
List<LessonMenuItem> menu = new ArrayList<>();
List<Category> categories = course.getCategories();
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
for (Category category : categories) {
LessonMenuItem categoryItem = new LessonMenuItem();

View File

@ -40,17 +40,19 @@ public class LessonProgressService {
@RequestMapping(value = "/service/lessonprogress.mvc", produces = "application/json")
@ResponseBody
public Map getLessonInfo() {
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
LessonTracker lessonTracker = userTracker.getLessonTracker(webSession.getCurrentLesson());
Map json = Maps.newHashMap();
String successMessage = "";
boolean lessonCompleted = false;
if (lessonTracker != null) {
lessonCompleted = lessonTracker.isLessonSolved();
successMessage = "LessonCompleted"; //@todo we still use this??
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
if (webSession.getCurrentLesson() != null) {
LessonTracker lessonTracker = userTracker.getLessonTracker(webSession.getCurrentLesson());
String successMessage = "";
boolean lessonCompleted = false;
if (lessonTracker != null) {
lessonCompleted = lessonTracker.isLessonSolved();
successMessage = "LessonCompleted"; //@todo we still use this??
}
json.put("lessonCompleted", lessonCompleted);
json.put("successMessage", successMessage);
}
json.put("lessonCompleted", lessonCompleted);
json.put("successMessage", successMessage);
return json;
}
@ -63,7 +65,7 @@ public class LessonProgressService {
@RequestMapping(value = "/service/lessonoverview.mvc", produces = "application/json")
@ResponseBody
public List<LessonOverview> lessonOverview() {
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
AbstractLesson currentLesson = webSession.getCurrentLesson();
List<LessonOverview> result = Lists.newArrayList();
if ( currentLesson != null ) {

View File

@ -32,6 +32,7 @@ import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.owasp.webgoat.i18n.PluginMessages;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.session.Course;
import org.owasp.webgoat.session.WebSession;
@ -57,6 +58,7 @@ public class ReportCardService {
private final WebSession webSession;
private final UserTrackerRepository userTrackerRepository;
private final Course course;
private final PluginMessages pluginMessages;
/**
* Endpoint which generates the report card for the current use to show the stats on the solved lessons
@ -64,7 +66,7 @@ public class ReportCardService {
@GetMapping(path = "/service/reportcard.mvc", produces = "application/json")
@ResponseBody
public ReportCard reportCard() {
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
List<AbstractLesson> lessons = course.getLessons();
ReportCard reportCard = new ReportCard();
reportCard.setTotalNumberOfLessons(course.getTotalOfLessons());
@ -74,7 +76,7 @@ public class ReportCardService {
for (AbstractLesson lesson : lessons) {
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
LessonStatistics lessonStatistics = new LessonStatistics();
lessonStatistics.setName(lesson.getTitle());
lessonStatistics.setName(pluginMessages.getMessage(lesson.getTitle()));
lessonStatistics.setNumberOfAttempts(lessonTracker.getNumberOfAttempts());
lessonStatistics.setSolved(lessonTracker.isLessonSolved());
reportCard.lessonStatistics.add(lessonStatistics);

View File

@ -59,7 +59,7 @@ public class RestartLessonService {
AbstractLesson al = webSession.getCurrentLesson();
log.debug("Restarting lesson: " + al);
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
userTracker.reset(al);
userTrackerRepository.save(userTracker);
}

View File

@ -81,6 +81,39 @@ public class CreateDB {
}
}
/**
* Description of the Method
*
* @param connection Description of the Parameter
* @throws SQLException Description of the Exception
*/
private void createJWTKeys(Connection connection) throws SQLException {
Statement statement = connection.createStatement();
// Drop servers table
try {
String dropTable = "DROP TABLE jwt_keys";
statement.executeUpdate(dropTable);
} catch (SQLException e) {
System.out.println("Info - Could not drop jwtkeys table");
}
// Create the new table
try {
String createTableStatement = "CREATE TABLE jwt_keys"
+ " (" + "id varchar(20),"
+ "key varchar(20))";
statement.executeUpdate(createTableStatement);
String insertData1 = "INSERT INTO jwt_keys VALUES ('webgoat_key', 'qwertyqwerty1234')";
String insertData2 = "INSERT INTO jwt_keys VALUES ('webwolf_key', 'doesnotreallymatter')";
statement.executeUpdate(insertData1);
statement.executeUpdate(insertData2);
} catch (SQLException e) {
System.out.println("Error creating product table " + e.getLocalizedMessage());
}
}
/**
* Description of the Method
@ -975,6 +1008,7 @@ public class CreateDB {
createTanTable(connection);
createMFEImagesTable(connection);
createModifyWithSQLLessonTable(connection);
createJWTKeys(connection);
System.out.println("Success: creating tables.");
}
}

View File

@ -47,8 +47,11 @@ import java.util.stream.Collectors;
*/
@Entity
public class LessonTracker {
@Getter
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Getter
private String lessonName;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private final Set<Assignment> solvedAssignments = Sets.newHashSet();

View File

@ -38,7 +38,7 @@ public class Scoreboard {
List<WebGoatUser> allUsers = userRepository.findAll();
List<Ranking> rankings = Lists.newArrayList();
for (WebGoatUser user : allUsers) {
UserTracker userTracker = userTrackerRepository.findOne(user.getUsername());
UserTracker userTracker = userTrackerRepository.findByUser(user.getUsername());
rankings.add(new Ranking(user.getUsername(), challengesSolved(userTracker)));
}
return rankings;

View File

@ -50,6 +50,9 @@ import java.util.stream.Collectors;
public class UserTracker {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "username")
private String user;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<LessonTracker> lessonTrackers = Sets.newHashSet();

View File

@ -8,5 +8,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
*/
public interface UserTrackerRepository extends JpaRepository<UserTracker, String> {
UserTracker findByUser(String user);
}

View File

@ -3,13 +3,16 @@ server.error.path=/error.html
server.session.timeout=600
server.contextPath=/WebGoat
server.port=8080
server.address=127.0.0.1
spring.datasource.url=jdbc:hsqldb:file:${webgoat.server.directory}/data/webgoat
spring.datasource.url=jdbc:hsqldb:hsql://localhost:9001/webgoat
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
logging.level.org.springframework=WARN
logging.level.org.springframework.boot.devtools=WARN
logging.level.org.springframework=INFO
logging.level.org.springframework.boot.devtools=INFO
logging.level.org.owasp=DEBUG
logging.level.org.owasp.webgoat=TRACE
@ -19,6 +22,7 @@ security.enable-csrf=false
spring.resources.cache-period=0
spring.thymeleaf.cache=false
webgoat.start.hsqldb=true
webgoat.clean=false
webgoat.server.directory=${user.home}/.webgoat-${webgoat.build.version}/
webgoat.user.directory=${user.home}/.webgoat-${webgoat.build.version}/
@ -35,7 +39,7 @@ webgoat.default.language=en
webwolf.host=${WEBWOLF_HOST:localhost}
webwolf.port=${WEBWOLF_PORT:8081}
webwolf.url=http://${webwolf.host}:${webwolf.port}/WebWolf
webworf.url.landingpage=http://${webwolf.host}:${webwolf.port}/landing
webwolf.url.landingpage=http://${webwolf.host}:${webwolf.port}/landing
webwolf.url.mail=http://${webwolf.host}:${webwolf.port}/mail
spring.jackson.serialization.indent_output=true

View File

@ -1066,6 +1066,7 @@ span.show-next-page, span.show-prev-page {
/* ATTACK DISPLAY */
.attack-container {
position: relative;
background-color: #f1f1f1;
border: 2px solid #a66;
border-radius: 12px;
@ -1150,4 +1151,16 @@ div.captured-flag {
height: 117px;
width: 1268px;
margin-bottom: 20px;
}
#content {
position:relative;
}
.webwolf-enabled {
position:absolute;
top: 10px;
right: 25px;
width: 42px;
height: 47px;
}

View File

@ -73,6 +73,7 @@ define(['jquery',
}
this.loadLesson = function(name,pageNum) {
if (this.name === name) {
this.listenToOnce(this.lessonHintView, 'hints:showButton', this.onShowHintsButton);
this.listenTo(this.lessonHintView, 'hints:hideButton', this.onHideHintsButton);
@ -83,15 +84,15 @@ define(['jquery',
return;
}
if (pageNum && !this.name) {
//placeholder
}
this.helpsLoaded = {};
if (typeof(name) === 'undefined' || name === null) {
//TODO: implement lesson not found or return to welcome page?
}
this.lessonContent.loadData({'name':name});
// this.planView = {};
// this.solutionView = {};
// this.sourceView = {};
// this.lessonHintView = {};
this.name = name;
};
@ -124,15 +125,8 @@ define(['jquery',
this.helpControlsView = null;
this.lessonContentView.model = this.lessonContent;
this.lessonContentView.render();
//this.planView = new PlanView();
//this.solutionView = new SolutionView();
//this.sourceView = new SourceView();
if (this.lessonHintView) {
this.lessonHintView.stopListening();
this.lessonHintView = null;
}
this.lessonHintView = new HintView();
//TODO: consider moving hintView as child of lessonContentView ...
this.createLessonHintView();
//TODO: instantiate model with values (not sure why was not working before)
var paramModel = new ParamModel({});
@ -148,40 +142,23 @@ define(['jquery',
this.lessonProgressModel.completed();
};
this.createLessonHintView = function () {
if (this.lessonHintView) {
this.lessonHintView.stopListening();
this.lessonHintView = null;
}
this.lessonHintView = new HintView();
}
this.addCurHelpState = function (curHelp) {
this.helpsLoaded[curHelp.helpElement] = curHelp.value;
};
// this.hideShowHelps = function(showHelp) {
// var showId = '#lesson-' + showHelp + '-row';
// var contentId = '#lesson-' + showHelp + '-content';
// $('.lesson-help').not(showId).hide();
// if (!showId) {
// return;
// }
//
// if ($(showId).is(':visible')) {
// $(showId).hide();
// return;
// } else {
// //TODO: move individual .html operations into individual help views
// switch(showHelp) {
// case 'plan':
// $(contentId).html(this.planView.model.get('content'));
// break;
// case 'solution':
// $(showId).html(this.solutionView.model.get('content'));
// break;
// case 'source':
// $(contentId).html('<pre>' + this.sourceView.model.get('content') + '</pre>');
// break;
// }
// $(showId).show();
// GoatUtils.scrollToHelp()
// }
// };
this.showHintsView = function() {
if (!this.lessonHintView) {
this.createLessonHintView();
}
//
this.lessonHintView.render();
if (this.lessonHintView.getHintsCount > 0) {
this.helpControlsView.showHintsButton();

View File

@ -1,29 +1,33 @@
define(['jquery',
'underscore',
'backbone',
'goatApp/model/MenuModel'],
function($,_,Backbone,MenuModel) {
'underscore',
'backbone',
'goatApp/model/MenuModel'],
function ($, _, Backbone, MenuModel) {
return Backbone.Collection.extend({
model: MenuModel,
url:'service/lessonmenu.mvc',
initialize: function () {
var self = this;
this.fetch();
},
return Backbone.Collection.extend({
model: MenuModel,
url: 'service/lessonmenu.mvc',
onDataLoaded: function() {
this.trigger('menuData:loaded');
},
initialize: function () {
var self = this;
this.fetch();
setInterval(function () {
this.fetch()
}.bind(this), 5000);
},
fetch: function() {
var self=this;
Backbone.Collection.prototype.fetch.apply(this,arguments).then(
function(data) {
this.models = data;
self.onDataLoaded();
}
);
}
});
});
onDataLoaded: function () {
this.trigger('menuData:loaded');
},
fetch: function () {
var self = this;
Backbone.Collection.prototype.fetch.apply(this, arguments).then(
function (data) {
this.models = data;
self.onDataLoaded();
}
);
}
});
});

View File

@ -67,7 +67,7 @@ define(['jquery',
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
success: function (data) {
//devs leave stuff like this in all the time
console.log('phone home said ' + data);
console.log('phone home said ' + JSON.stringify(data));
}
});
}

View File

@ -25,6 +25,9 @@ define(['jquery',
self.navToPage(page);
}
});
setInterval(function () {
this.updatePagination();
}.bind(this), 5000);
},
findPage: function(assignment) {
@ -56,11 +59,13 @@ define(['jquery',
var currentPage = (!isNaN(startPageNum) && startPageNum && startPageNum < this.$contentPages) ? startPageNum : 0;
//init views & pagination
this.showCurContentPage(currentPage);
this.paginationControlView = new PaginationControlView(this.$contentPages,this.model.get('lessonUrl'));
this.paginationControlView = new PaginationControlView(this.$contentPages,this.model.get('lessonUrl'),startPageNum);
},
updatePagination: function() {
this.paginationControlView.updateCollection();
if ( this.paginationControlView != undefined ) {
this.paginationControlView.updateCollection();
}
},
getCurrentPage: function () {
@ -85,6 +90,8 @@ define(['jquery',
var prepareDataFunctionName = $(curForm).attr('prepareData');
var callbackFunctionName = $(curForm).attr('callback');
var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize();
var additionalHeadersFunctionName = $(curForm).attr('additionalHeaders');
var additionalHeaders = (typeof webgoat.customjs[additionalHeadersFunctionName] === 'function') ? webgoat.customjs[additionalHeadersFunctionName]() : function() {};
var successCallBackFunctionName = $(curForm).attr('successCallback');
var failureCallbackFunctionName = $(curForm).attr('failureCallback');
var callbackFunction = (typeof webgoat.customjs[callbackFunctionName] === 'function') ? webgoat.customjs[callbackFunctionName] : function() {};
@ -99,6 +106,7 @@ define(['jquery',
$.ajax({
//data:submitData,
url:formUrl,
headers: additionalHeaders,
method:formMethod,
contentType:contentType,
data: submitData,
@ -146,14 +154,23 @@ define(['jquery',
return false;
},
removeSlashesFromJSON: function(str) {
// slashes are leftover escapes from JSON serialization by server
// for every two char sequence starting with backslash,
// replace them in the text with second char only
return str.replace(/\\(.)/g, "$1");
},
renderFeedback: function(feedback) {
this.$curFeedback.html(polyglot.t(feedback) || "");
var s = this.removeSlashesFromJSON(feedback);
this.$curFeedback.html(polyglot.t(s) || "");
this.$curFeedback.show(400)
},
renderOutput: function(output) {
this.$curOutput.html(polyglot.t(output) || "");
var s = this.removeSlashesFromJSON(output);
this.$curOutput.html(polyglot.t(s) || "");
this.$curOutput.show(400)
},
@ -173,13 +190,19 @@ define(['jquery',
return endpoints;
},
onNavToPage: function(pageNum) {
var assignmentPaths = this.findAssigmentEndpointsOnPage(pageNum);
this.trigger('endpoints:filtered',assignmentPaths);
},
navToPage: function (pageNum) {
this.paginationControlView.setCurrentPage(pageNum);//provides validation
this.showCurContentPage(this.paginationControlView.currentPage);
this.paginationControlView.render();
this.paginationControlView.hideShowNavButtons();
var assignmentPaths = this.findAssigmentEndpointsOnPage(pageNum);
this.trigger('endpoints:filtered',assignmentPaths);
this.onNavToPage(pageNum);
//var assignmentPaths = this.findAssigmentEndpointsOnPage(pageNum);
//this.trigger('endpoints:filtered',assignmentPaths);
},
/* for testing */

View File

@ -12,14 +12,14 @@ define(['jquery',
template: PaginationTemplate,
el: '#lesson-page-controls',
initialize: function ($contentPages,baseLessonUrl) {
initialize: function ($contentPages,baseLessonUrl,initPageNum) {
this.$contentPages = $contentPages;
this.collection = new LessonOverviewCollection();
this.listenTo(this.collection, 'reset', this.render);
this.numPages = this.$contentPages.length;
this.baseUrl = baseLessonUrl;
this.collection.fetch({reset:true});
this.initPagination();
this.initPagination(initPageNum);
//this.render();
},
@ -117,9 +117,9 @@ define(['jquery',
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').hide();
},
initPagination: function() {
//track pagination state in this view ... start at 0
this.currentPage = 0;
initPagination: function(initPageNum) {
//track pagination state in this view ... start at 0 .. unless a pageNum was provided
this.currentPage = !initPageNum ? 0 : initPageNum;
},
setCurrentPage: function (pageNum) {

View File

@ -30,7 +30,7 @@ require.config({
shim: {
"jqueryui": {
exports:"$",
deps: ['jquery']
deps: ['libs/jquery-2.1.4.min']
},
underscore: {
exports: "_"

View File

@ -76,24 +76,25 @@
</a>
</li>
<li role="presentation" class="divider"></li>
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#"
th:text="#{version}">Version: <span
th:text="${@environment.getProperty('webgoat.build.version')}"></span></a>
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">
<span th:text="#{version}">Version:</span><span>: </span>
<span th:text="${@environment.getProperty('webgoat.build.version')}"></span></a>
</li>
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#"
th:text="#{build}">Build:
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">
<span th:text="#{build}">Build:</span><span>: </span>
<span th:text="${@environment.getProperty('webgoat.build.number')}"></span></a></li>
</ul>
</div>
<div style="display:inline" id="settings">
<!--<button type="button" id="admin-button" class="btn btn-default right_nav_button" title="Administrator">-->
<!--<i class="fa fa-cog"></i>-->
<!--</button>-->
<button type="button" id="report-card-button" class="btn btn-default right_nav_button button-up"
th:title="#{report.card}">
<a href="#reportCard"><i class="fa fa-bar-chart-o"></i></a>
</button>
<a href="#reportCard">
<button type="button" id="report-card-button" class="btn btn-default right_nav_button button-up"
th:title="#{report.card}">
<i class="fa fa-bar-chart-o"></i>
</button>
</a>
<!--<button type="button" id="user-management" class="btn btn-default right_nav_button"-->
<!--title="User management">-->
<!--<i class="fa fa-users"></i>-->

View File

@ -62,7 +62,7 @@ public class AssignmentEndpointTest {
public void init(AssignmentEndpoint a) {
messages.setBasenames("classpath:/i18n/messages", "classpath:/i18n/WebGoatLabels");
when(userTrackerRepository.findOne(anyString())).thenReturn(userTracker);
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
ReflectionTestUtils.setField(a, "userTrackerRepository", userTrackerRepository);
ReflectionTestUtils.setField(a, "userSessionData", userSessionData);
ReflectionTestUtils.setField(a, "webSession", webSession);

View File

@ -63,7 +63,7 @@ public class LessonMenuServiceTest {
when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1, l2));
when(course.getCategories()).thenReturn(Lists.newArrayList(Category.ACCESS_CONTROL));
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
when(userTrackerRepository.findOne(anyString())).thenReturn(userTracker);
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
mockMvc.perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC))
.andExpect(status().isOk())
@ -81,7 +81,7 @@ public class LessonMenuServiceTest {
when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1));
when(course.getCategories()).thenReturn(Lists.newArrayList(Category.ACCESS_CONTROL));
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
when(userTrackerRepository.findOne(anyString())).thenReturn(userTracker);
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
mockMvc.perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC))

View File

@ -72,7 +72,7 @@ public class LessonProgressServiceTest {
@Before
public void setup() {
Assignment assignment = new Assignment("test", "test");
when(userTrackerRepository.findOne(anyString())).thenReturn(userTracker);
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
when(websession.getCurrentLesson()).thenReturn(lesson);
when(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true));

View File

@ -6,6 +6,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.owasp.webgoat.i18n.PluginMessages;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.session.Course;
import org.owasp.webgoat.session.WebSession;
@ -40,10 +41,13 @@ public class ReportCardServiceTest {
private UserTrackerRepository userTrackerRepository;
@Mock
private WebSession websession;
@Mock
private PluginMessages pluginMessages;
@Before
public void setup() {
this.mockMvc = standaloneSetup(new ReportCardService(websession, userTrackerRepository, course)).build();
this.mockMvc = standaloneSetup(new ReportCardService(websession, userTrackerRepository, course, pluginMessages)).build();
when(pluginMessages.getMessage(anyString())).thenReturn("Test");
}
@Test
@ -53,7 +57,7 @@ public class ReportCardServiceTest {
when(course.getTotalOfLessons()).thenReturn(1);
when(course.getTotalOfAssignments()).thenReturn(10);
when(course.getLessons()).thenReturn(Lists.newArrayList(lesson));
when(userTrackerRepository.findOne(anyString())).thenReturn(userTracker);
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
mockMvc.perform(MockMvcRequestBuilders.get("/service/reportcard.mvc"))
.andExpect(status().isOk())

View File

@ -62,7 +62,7 @@ public class UserTrackerRepositoryTest {
userTrackerRepository.save(userTracker);
userTracker = userTrackerRepository.findOne("test");
userTracker = userTrackerRepository.findByUser("test");
Assertions.assertThat(userTracker.getLessonTracker("test")).isNotNull();
}
@ -77,7 +77,7 @@ public class UserTrackerRepositoryTest {
userTrackerRepository.saveAndFlush(userTracker);
userTracker = userTrackerRepository.findOne("test");
userTracker = userTrackerRepository.findByUser("test");
Assertions.assertThat(userTracker.numberOfAssignmentsSolved()).isEqualTo(1);
}
@ -90,7 +90,7 @@ public class UserTrackerRepositoryTest {
userTracker.assignmentFailed(lesson);
userTrackerRepository.saveAndFlush(userTracker);
userTracker = userTrackerRepository.findOne("test");
userTracker = userTrackerRepository.findByUser("test");
userTracker.assignmentFailed(lesson);
userTracker.assignmentFailed(lesson);
userTrackerRepository.saveAndFlush(userTracker);

View File

@ -1 +1,15 @@
<configuration />
<configuration />
<!--
Enable below if you want to debug a unit test and see why the controller fails the configuration above is there
to keep the Travis build going otherwise it fails with too much logging.
//TODO we should use a different Spring profile for Travis
-->
<!--
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
-->

View File

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

View File

@ -1,4 +1,4 @@
== Authentication Bpasses
== Authentication Bypasses
Authentication Bypasses happen in many ways, but usually take advantage of some flaw in the configuration or logic. Tampering to achieve the right conditions.
@ -12,4 +12,4 @@ Sometimes, if an attacker doesn't know the correct value of a parameter, they ma
=== Forced Browsing
If an area of a site is not protected properly by configuation, that area of the site may be accessed by guessing/brute-forcing.
If an area of a site is not protected properly by configuration, that area of the site may be accessed by guessing/brute-forcing.

View File

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

View File

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

View File

@ -46,7 +46,6 @@ public class Flag extends Endpoint {
@PostConstruct
public void initFlags() {
IntStream.range(1, 10).forEach(i -> FLAGS.put(i, UUID.randomUUID().toString()));
FLAGS.entrySet().stream().forEach(e -> log.debug("Flag {} {}", e.getKey(), e.getValue()));
}
@Override

View File

@ -10,11 +10,8 @@ public interface SolutionConstants {
//TODO should be random generated when starting the server
String PASSWORD = "!!webgoat_admin_1234!!";
String SUPER_COUPON_CODE = "get_it_for_free";
String PASSWORD_TOM = "thisisasecretfortomonly";
String PASSWORD_LARRY = "larryknows";
String JWT_PASSWORD = "victory";
String ADMIN_PASSWORD_LINK = "375afe1104f4a487a73823c50a9292a2";
String PASSWORD_TOM_9 = "somethingVeryRandomWhichNoOneWillEverTypeInAsPasswordForTom";
String TOM_EMAIL = "tom@webgoat-cloud.org";
}

View File

@ -1,39 +0,0 @@
package org.owasp.webgoat.plugin.challenge9;
import com.google.common.collect.Lists;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import java.util.List;
/**
* @author nbaars
* @since 3/21/17.
*/
public class Challenge9 extends NewLesson {
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public List<String> getHints() {
return Lists.newArrayList();
}
@Override
public Integer getDefaultRanking() {
return 10;
}
@Override
public String getTitle() {
return "challenge9.title";
}
@Override
public String getId() {
return "Challenge9";
}
}

View File

@ -1,112 +0,0 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Challenge_2.adoc"></div>
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/challenge2.css}"/>
<script th:src="@{/lesson_js/challenge2.js}" language="JavaScript"></script>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="container-fluid">
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/challenge/2"
enctype="application/json;charset=UTF-8">
<input id="discount" type="hidden" value="0"/>
<div class="row">
<div class="col-xs-3 item-photo">
<img style="max-width:100%;" th:src="@{/images/samsung-black.jpg}"/>
</div>
<div class="col-xs-5" style="border:0px solid gray">
<h3>Samsung Galaxy S8</h3>
<h5 style="color:#337ab7"><a href="http://www.samsung.com">Samsung</a> ·
<small style="color:#337ab7">(124421 reviews)</small>
</h5>
<h6 class="title-price">
<small>PRICE</small>
</h6>
<h3 style="margin-top:0px;"><span>US $</span><span id="price">899</span></h3>
<div class="section">
<h6 class="title-attr" style="margin-top:15px;">
<small>COLOR</small>
</h6>
<div>
<div class="attr" style="width:25px;background:lightgrey;"></div>
<div class="attr" style="width:25px;background:black;"></div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>CAPACITY</small>
</h6>
<div>
<div class="attr2">64 GB</div>
<div class="attr2">128 GB</div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>QUANTITY</small>
</h6>
<div>
<div class="btn-minus"><span class="glyphicon glyphicon-minus"></span></div>
<input class="quantity" value="1"/>
<div class="btn-plus"><span class="glyphicon glyphicon-plus"></span></div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>CHECKOUT CODE</small>
</h6>
<!--
Checkout code: webgoat, owasp, owasp-webgoat
-->
<input name="checkoutCode" class="checkoutCode" value=""/>
</div>
<div class="section" style="padding-bottom:20px;">
<button type="submit" class="btn btn-success"><span style="margin-right:20px"
class="glyphicon glyphicon-shopping-cart"
aria-hidden="true"></span>Buy
</button>
<h6><a href="#"><span class="glyphicon glyphicon-heart-empty"
style="cursor:pointer;"></span>
Like</a></h6>
</div>
</div>
</div>
</form>
</div>
<br/>
<form class="attack-form" method="POST" name="form" action="/WebGoat/challenge/flag">
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
style="font-size:20px"></i></div>
<input type="text" class="form-control" id="flag" name="flag"
placeholder="a7179f89-906b-4fec-9d99-f15b796e7208"/>
</div>
<div class="input-group" style="margin-top: 10px">
<button type="submit" class="btn btn-primary">Submit flag</button>
</div>
</div>
</form>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -1,109 +0,0 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Challenge_9.adoc"></div>
<script th:src="@{/lesson_js/challenge9.js}" language="JavaScript"></script>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="container-fluid">
<div class="row">
<div class="col-md-6">
<h4 style="border-bottom: 1px solid #c5c5c5;">
<i class="glyphicon glyphicon-user"></i>
Account Access
</h4>
<div style="padding: 20px;" id="form-login">
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/challenge/9/login"
enctype="application/json;charset=UTF-8" role="form">
<fieldset>
<div class="form-group input-group">
<span class="input-group-addon"> @ </span>
<input class="form-control" placeholder="Email" name="email" type="email"
required="" autofocus=""/>
</div>
<div class="form-group input-group">
<span class="input-group-addon">
<i class="glyphicon glyphicon-lock">
</i>
</span>
<input class="form-control" placeholder="Password" name="password" type="password"
value="" required=""/>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">
Access
</button>
<p class="help-block">
<a class="pull-right text-muted" href="#" id="login">
<small>Forgot your password?</small>
</a>
</p>
</div>
</fieldset>
</form>
</div>
<div style="display: none;" id="form-login">
<h4 class="">
Forgot your password?
</h4>
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/challenge/9/create-password-reset-link"
enctype="application/json;charset=UTF-8" role="form">
<fieldset>
<span class="help-block">
Email address you use to log in to your account
<br/>
We'll send you an email with instructions to choose a new password.
</span>
<div class="form-group input-group">
<span class="input-group-addon">
@
</span>
<input class="form-control" placeholder="Email" name="email" type="email"
required=""/>
</div>
<button type="submit" class="btn btn-primary btn-block" id="btn-login">
Continue
</button>
<p class="help-block">
<a class="text-muted" href="#" id="forgot">
<small>Account Access</small>
</a>
</p>
</fieldset>
</form>
</div>
</div>
</div>
</div>
<br/>
<form class="attack-form" method="POST" name="form" action="/WebGoat/challenge/flag">
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
style="font-size:20px"></i></div>
<input type="text" class="form-control" id="flag" name="flag"
placeholder="a7179f89-906b-4fec-9d99-f15b796e7208"/>
</div>
<div class="input-group" style="margin-top: 10px">
<button type="submit" class="btn btn-primary">Submit flag</button>
</div>
</div>
</form>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -22,8 +22,7 @@ challenge.flag.incorrect=Sorry this is not the correct flag, please try again.
ip.address.unknown=IP address unknown, e-mail has been sent.
login_failed=Login failed
login_failed.tom=Sorry only Tom can login at the moment
required4=Missing username or password, please specify both.
user.not.larry=Please try to log in as Larry not {0}.

View File

@ -1,10 +0,0 @@
$(document).ready(function() {
$('#login').click(function(e) {
e.preventDefault();
$('div#form-login').toggle('500');
});
$('#forgot').click(function(e) {
e.preventDefault();
$('div#form-login').toggle('500');
});
});

View File

@ -1,3 +0,0 @@
Tom always resets his password immediately after receiving the email with the link.
Try to reset the password of Tom (tom@webgoat-cloud.org) to your own choice and login as Tom with
that password.

View File

@ -1,49 +0,0 @@
package org.owasp.webgoat.plugin.challenge2;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import org.owasp.webgoat.assignments.AssignmentEndpointTest;
import org.owasp.webgoat.plugin.Flag;
import org.owasp.webgoat.plugin.SolutionConstants;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
/**
* @author nbaars
* @since 5/2/17.
*/
@RunWith(MockitoJUnitRunner.class)
public class Assignment2Test extends AssignmentEndpointTest {
private MockMvc mockMvc;
@Before
public void setup() {
Assignment2 assignment2 = new Assignment2();
init(assignment2);
new Flag().initFlags();
this.mockMvc = standaloneSetup(assignment2).build();
}
@Test
public void success() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/challenge/2")
.param("checkoutCode", SolutionConstants.SUPER_COUPON_CODE))
.andExpect(jsonPath("$.feedback", CoreMatchers.containsString("flag: " + Flag.FLAGS.get(2))))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
}
@Test
public void wrongCouponCode() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/challenge/2")
.param("checkoutCode", "test"))
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved"))))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
}
}

View File

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

View File

@ -56,7 +56,7 @@ public class ClientSideFiltering extends NewLesson {
@Override
public String getTitle() {
return "Client side filtering";
return "client.side.filtering.title";
}
@Override

View File

@ -1,9 +1,9 @@
package org.owasp.webgoat.plugin.challenge2;
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.plugin.Flag;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@ -11,22 +11,23 @@ import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException;
import static org.owasp.webgoat.plugin.SolutionConstants.SUPER_COUPON_CODE;
/**
* @author nbaars
* @since 4/6/17.
*/
@AssignmentPath("/challenge/2")
public class Assignment2 extends AssignmentEndpoint {
@AssignmentPath("/clientSideFiltering/getItForFree")
@AssignmentHints({"client.side.filtering.free.hint1", "client.side.filtering.free.hint2", "client.side.filtering.free.hint3"})
public class ClientSideFilteringFreeAssignment extends AssignmentEndpoint {
public static final String SUPER_COUPON_CODE = "get_it_for_free";
@RequestMapping(method = RequestMethod.POST)
public
@ResponseBody
AttackResult completed(@RequestParam String checkoutCode) throws IOException {
AttackResult completed(@RequestParam String checkoutCode) {
if (SUPER_COUPON_CODE.equals(checkoutCode)) {
return success().feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(2)).build();
return trackProgress(success().build());
}
return failed().build();
return trackProgress(failed().build());
}
}

View File

@ -1,4 +1,4 @@
package org.owasp.webgoat.plugin.challenge2;
package org.owasp.webgoat.plugin;
import com.beust.jcommander.internal.Lists;
import lombok.AllArgsConstructor;
@ -12,21 +12,21 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Optional;
import static org.owasp.webgoat.plugin.SolutionConstants.SUPER_COUPON_CODE;
import static org.owasp.webgoat.plugin.ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE;
/**
* @author nbaars
* @since 4/6/17.
*/
@RestController
@RequestMapping("challenge-store")
@RequestMapping("/clientSideFiltering/challenge-store")
public class ShopEndpoint {
@AllArgsConstructor
private class CheckoutCodes {
@Getter
private List<CheckoutCode> codes = Lists.newArrayList();
private List<CheckoutCode> codes;
public Optional<CheckoutCode> get(String code) {
return codes.stream().filter(c -> c.getCode().equals(code)).findFirst();

View File

@ -73,7 +73,96 @@
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:ClientSideFiltering_final.adoc"></div>
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/clientSideFilteringFree.css}"/>
<script th:src="@{/lesson_js/clientSideFilteringFree.js}" language="JavaScript"></script>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="container-fluid">
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/clientSideFiltering/getItForFree"
enctype="application/json;charset=UTF-8">
<input id="discount" type="hidden" value="0"/>
<div class="row">
<div class="col-xs-3 item-photo">
<img style="max-width:100%;" th:src="@{/images/samsung-black.jpg}"/>
</div>
<div class="col-xs-5" style="border:0px solid gray">
<h3>Samsung Galaxy S8</h3>
<h5 style="color:#337ab7"><a href="http://www.samsung.com">Samsung</a> ·
<small style="color:#337ab7">(124421 reviews)</small>
</h5>
<h6 class="title-price">
<small>PRICE</small>
</h6>
<h3 style="margin-top:0px;"><span>US $</span><span id="price">899</span></h3>
<div class="section">
<h6 class="title-attr" style="margin-top:15px;">
<small>COLOR</small>
</h6>
<div>
<div class="attr" style="width:25px;background:lightgrey;"></div>
<div class="attr" style="width:25px;background:black;"></div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>CAPACITY</small>
</h6>
<div>
<div class="attr2">64 GB</div>
<div class="attr2">128 GB</div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>QUANTITY</small>
</h6>
<div>
<div class="btn-minus"><span class="glyphicon glyphicon-minus"></span></div>
<input class="quantity" value="1"/>
<div class="btn-plus"><span class="glyphicon glyphicon-plus"></span></div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>CHECKOUT CODE</small>
</h6>
<!--
Checkout code: webgoat, owasp, owasp-webgoat
-->
<input name="checkoutCode" class="checkoutCode" value=""/>
</div>
<div class="section" style="padding-bottom:20px;">
<button type="submit" class="btn btn-success"><span style="margin-right:20px"
class="glyphicon glyphicon-shopping-cart"
aria-hidden="true"></span>Buy
</button>
<h6><a href="#"><span class="glyphicon glyphicon-heart-empty"
style="cursor:pointer;"></span>
Like</a></h6>
</div>
</div>
</div>
</form>
</div>
<br/>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -1,3 +1,4 @@
client.side.filtering.title=Client side filtering
ClientSideFilteringSelectUser=Select user:
ClientSideFilteringUserID=User ID
ClientSideFilteringFirstName=First Name
@ -25,3 +26,7 @@ ClientSideFilteringHint10=Stage 2: Your filter operator should look something li
ClientSideFilteringInstructions1=STAGE 1: You are logged in as Moe Stooge, CSO of Goat Hills Financial. You have access to everyone in the company's information, except the CEO, . Or at least you shouldn't have access to the CEO's information. For this exercise, examine the contents of the page to see what extra information you can find.
ClientSideFilteringInstructions2=STAGE 2: Now, fix the problem. Modify the server to only return results that Moe Stooge is allowed to see.
ClientSideFiltering.incorrect=This is not the salary from Neville Bartholomew...
client.side.filtering.free.hint1=Look through the webpage inspect the sources etc
client.side.filtering.free.hint2=Try to see the flow of request from the page to the backend
client.side.fiterling.free.hint3=One of the responses contains the answer

View File

@ -38,7 +38,7 @@ $(document).ready(function () {
})
$(".checkoutCode").on("blur", function () {
var checkoutCode = $(".checkoutCode").val();
$.get("challenge-store/coupons/" + checkoutCode, function (result, status) {
$.get("clientSideFiltering/challenge-store/coupons/" + checkoutCode, function (result, status) {
var discount = result.discount;
if (discount > 0) {
$('#discount').text(discount);

View File

@ -0,0 +1,49 @@
package org.owasp.webgoat.plugin;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.mockito.Mockito.when;
import static org.owasp.webgoat.plugin.ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
/**
* @author nbaars
* @since 5/2/17.
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class ClientSideFilteringFreeAssignmentTest extends LessonTest {
private MockMvc mockMvc;
@Before
public void setup() {
ClientSideFiltering clientSideFiltering = new ClientSideFiltering();
when(webSession.getCurrentLesson()).thenReturn(clientSideFiltering);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
when(webSession.getUserName()).thenReturn("unit-test");
}
@Test
public void success() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/clientSideFiltering/getItForFree")
.param("checkoutCode", SUPER_COUPON_CODE))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
}
@Test
public void wrongCouponCode() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/clientSideFiltering/getItForFree")
.param("checkoutCode", "test"))
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved"))))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
}
}

View File

@ -1,4 +1,4 @@
package org.owasp.webgoat.plugin.challenge2;
package org.owasp.webgoat.plugin;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
@ -9,7 +9,7 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.hamcrest.Matchers.is;
import static org.owasp.webgoat.plugin.SolutionConstants.SUPER_COUPON_CODE;
import static org.owasp.webgoat.plugin.ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
@ -30,28 +30,28 @@ public class ShopEndpointTest {
@Test
public void getSuperCoupon() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/" + SUPER_COUPON_CODE))
mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/" + SUPER_COUPON_CODE))
.andExpect(jsonPath("$.code", CoreMatchers.is(SUPER_COUPON_CODE)))
.andExpect(jsonPath("$.discount", CoreMatchers.is(100)));
}
@Test
public void getCoupon() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/webgoat"))
mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/webgoat"))
.andExpect(jsonPath("$.code", CoreMatchers.is("webgoat")))
.andExpect(jsonPath("$.discount", CoreMatchers.is(25)));
}
@Test
public void askForUnknownCouponCode() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/does-not-exists"))
mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/does-not-exists"))
.andExpect(jsonPath("$.code", CoreMatchers.is("no")))
.andExpect(jsonPath("$.discount", CoreMatchers.is(0)));
}
@Test
public void fetchAllTheCouponsShouldContainGetItForFree() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/"))
mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/"))
.andExpect(jsonPath("$.codes[3].code", is("get_it_for_free")));
}

View File

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

View File

@ -60,7 +60,7 @@ public class CrossSiteScripting extends NewLesson {
@Override
public String getTitle() {
return "Cross Site Scripting";
return "xss.title";
}
@Override

View File

@ -1,4 +1,5 @@
# XSS success, failure messages and hints
xss.title=Cross Site Scripting
xss-reflected-5a-success=well done, but alerts aren't very impressive are they? Please continue.
xss-reflected-5a-failure=Try again. We do want to see this specific javascript (in case you are trying to do something more fancy)
xss-reflected-5b-success=Correct ... because <ul><li>The script was not triggered by the URL/QueryString</li><li>Even if you use the attack URL in a new tab, it won't execute (becuase of response type). Try it if you like.</li></ul>

View File

@ -2,10 +2,10 @@
=== Why?
Hopefully we've covered that by now. Bottom line, you don't want someone else's code running in the context of your users and their logged-in seession
Hopefully we've covered that by now. Bottom line, you don't want someone else's code running in the context of your users and their logged-in session
=== What to encode?
The basic premise of defending against XSS is *output endoding* any untrusted input that goes to the screen.
The basic premise of defending against XSS is *output encoding* any untrusted input that goes to the screen.
That may be changing with more sophisticated attacks, but is still the best defense we currently have. *AND* ... *context matters*
Another word on 'untrusted input'. If in doubt, treat everything (even data you populated in your DB as untrusted).

View File

@ -33,8 +33,10 @@ import org.mockito.runners.MockitoJUnitRunner;
import org.owasp.webgoat.assignments.AssignmentEndpointTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.util.Assert;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
@ -80,13 +82,13 @@ public class StoredXssCommentsTest extends AssignmentEndpointTest {
*/
//Ensures it is vulnerable
// @Test
// public void isNotEncoded() throws Exception {
// //do get to get comments after posting xss payload
// ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScripting/stored-xss"));
// taintedResults.andExpect(jsonPath("$[0].text",CoreMatchers.is(CoreMatchers.containsString("<script>console.warn('unit test me')</script>"))));
// }
@Test
public void isNotEncoded() throws Exception {
//do get to get comments after posting xss payload
ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScripting/stored-xss"));
MvcResult mvcResult = taintedResults.andReturn();
assert(mvcResult.getResponse().getContentAsString().contains("<script>console.warn"));
}
//Could be used to test an encoding solution ... commented out so build will pass. Uncommenting will fail build, but leaving in as positive Security Unit Test
// @Test
@ -95,4 +97,4 @@ public class StoredXssCommentsTest extends AssignmentEndpointTest {
// ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScripting/stored-xss"));
// taintedResults.andExpect(jsonPath("$[0].text",CoreMatchers.is(CoreMatchers.containsString("&lt;scriptgt;"))));
// }
}
}

View File

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

View File

@ -6,30 +6,31 @@ import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.UserSessionData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
/**
* Created by jason on 9/29/17.
*/
@AssignmentPath("/csrf/confirm-flag-1")
@AssignmentHints({"csrf-get.hint1","csrf-get.hint2","csrf-get.hint3","csrf-get.hint4"})
@AssignmentHints({"csrf-get.hint1", "csrf-get.hint2", "csrf-get.hint3", "csrf-get.hint4"})
public class CSRFConfirmFlag1 extends AssignmentEndpoint {
@Autowired
UserSessionData userSessionData;
@PostMapping(produces = {"application/json"})
public @ResponseBody AttackResult completed(String confirmFlagVal) {
public @ResponseBody
AttackResult completed(String confirmFlagVal) {
if (confirmFlagVal.equals(userSessionData.getValue("csrf-get-success").toString())) {
return success().feedback("csrf-get-null-referer.success").output("Correct, the flag was " + userSessionData.getValue("csrf-get-success")).build();
Object userSessionDataStr = userSessionData.getValue("csrf-get-success");
if (userSessionDataStr != null && confirmFlagVal.equals(userSessionDataStr.toString())) {
return trackProgress(
success().feedback("csrf-get-null-referer.success").output("Correct, the flag was " + userSessionData.getValue("csrf-get-success")).build()
);
}
return failed().feedback("").build();
return trackProgress(failed().build());
}
}

View File

@ -40,7 +40,7 @@ public class CSRFFeedback extends AssignmentEndpoint {
try {
objectMapper.readValue(feedback.getBytes(), Map.class);
} catch (IOException e) {
return failed().feedback(ExceptionUtils.getStackTrace(e)).build();
return failed().feedback(ExceptionUtils.getStackTrace(e)).build();
}
boolean correctCSRF = requestContainsWebGoatCookie(request.getCookies()) && request.getContentType().equals(MediaType.TEXT_PLAIN_VALUE);
correctCSRF &= hostOrRefererDifferentHost(request);
@ -64,8 +64,12 @@ public class CSRFFeedback extends AssignmentEndpoint {
private boolean hostOrRefererDifferentHost(HttpServletRequest request) {
String referer = request.getHeader("referer");
String host = request.getHeader("host");
return !StringUtils.contains(referer, host);
String origin = request.getHeader("origin");
if (referer != null) {
return !referer.contains(origin);
} else {
return true; //this case referer is null or origin does not matter we cannot compare so we return true which should of course be false
}
}
private boolean requestContainsWebGoatCookie(Cookie[] cookies) {

View File

@ -31,7 +31,7 @@ public class CSRFGetFlag extends Endpoint {
@ResponseBody
public Map<String, Object> invoke(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Map<String,Object> response = new HashMap<>();
Map<String, Object> response = new HashMap<>();
String host = (req.getHeader("host") == null) ? "NULL" : req.getHeader("host");
// String origin = (req.getHeader("origin") == null) ? "NULL" : req.getHeader("origin");
@ -40,22 +40,32 @@ public class CSRFGetFlag extends Endpoint {
String referer = (req.getHeader("referer") == null) ? "NULL" : req.getHeader("referer");
String[] refererArr = referer.split("/");
if (referer.equals("NULL") && req.getParameter("csrf").equals("true")) {
Random random = new Random();
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
response.put("success",true);
response.put("message",pluginMessages.getMessage("csrf-get-null-referer.success"));
response.put("flag",userSessionData.getValue("csrf-get-success"));
} else if (refererArr[2].equals(host)) {
if (referer.equals("NULL")) {
if (req.getParameter("csrf").equals("true")) {
Random random = new Random();
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
response.put("success", true);
response.put("message", pluginMessages.getMessage("csrf-get-null-referer.success"));
response.put("flag", userSessionData.getValue("csrf-get-success"));
} else {
Random random = new Random();
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
response.put("success", true);
response.put("message", pluginMessages.getMessage("csrf-get-other-referer.success"));
response.put("flag", userSessionData.getValue("csrf-get-success"));
}
} else if (refererArr[2].equals(host)) {
response.put("success", false);
response.put("message", "Appears the request came from the original host");
response.put("flag", null);
} else {
Random random = new Random();
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
response.put("success",true);
response.put("message",pluginMessages.getMessage("csrf-get-other-referer.success"));
response.put("flag",userSessionData.getValue("csrf-get-success"));
response.put("success", true);
response.put("message", pluginMessages.getMessage("csrf-get-other-referer.success"));
response.put("flag", userSessionData.getValue("csrf-get-success"));
}
return response;

View File

@ -1,69 +0,0 @@
package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.Endpoint;
import org.owasp.webgoat.i18n.PluginMessages;
import org.owasp.webgoat.session.UserSessionData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* Created by jason on 9/30/17.
*/
public class CSRFGetXhrFlag extends Endpoint {
@Autowired
UserSessionData userSessionData;
@Autowired
private PluginMessages pluginMessages;
@RequestMapping(produces = {"application/json"}, method = RequestMethod.GET)
@ResponseBody
public Map<String, Object> invoke(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Map<String,Object> response = new HashMap<>();
String host = (req.getHeader("host") == null) ? "NULL" : req.getHeader("host");
// String origin = (req.getHeader("origin") == null) ? "NULL" : req.getHeader("origin");
// Integer serverPort = (req.getServerPort() < 1) ? 0 : req.getServerPort();
// String serverName = (req.getServerName() == null) ? "NULL" : req.getServerName();
String referer = (req.getHeader("referer") == null) ? "NULL" : req.getHeader("referer");
String[] refererArr = referer.split("/");
if (referer.equals("NULL") && req.getParameter("csrf").equals("true")) {
Random random = new Random();
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
response.put("success",true);
response.put("message",pluginMessages.getMessage("csrf-get-null-referer.success"));
response.put("flag",userSessionData.getValue("csrf-get-success"));
} else if (refererArr[2].equals(host)) {
response.put("success", false);
response.put("message", "Appears the request came from the original host");
response.put("flag", null);
} else {
Random random = new Random();
userSessionData.setValue("csrf-get-success", random.nextInt(65536));
response.put("success",true);
response.put("message",pluginMessages.getMessage("csrf-get-other-referer.success"));
response.put("flag",userSessionData.getValue("csrf-get-success"));
}
return response;
}
@Override
public String getPath() {
return "/csrf/get-xhr-flag";
}
}

View File

@ -33,7 +33,7 @@ public class CSRFLogin extends AssignmentEndpoint {
}
private void markAssignmentSolvedWithRealUser(String username) {
UserTracker userTracker = userTrackerRepository.findOne(username);
UserTracker userTracker = userTrackerRepository.findByUser(username);
userTracker.assignmentSolved(getWebSession().getCurrentLesson(), this.getClass().getSimpleName());
userTrackerRepository.save(userTracker);
}

View File

@ -115,22 +115,13 @@ public class ForgedReviews extends AssignmentEndpoint {
userReviews.put(webSession.getUserName(), reviews);
//short-circuit
if (validateReq == null || !validateReq.equals(weakAntiCSRF)) {
return failed().feedback("csrf-you-forgot-something").build();
return trackProgress(failed().feedback("csrf-you-forgot-something").build());
}
//we have the spoofed files
if (referer != "NULL" && refererArr[2].equals(host) ) {
return (failed().feedback("csrf-same-host").build());
return trackProgress(failed().feedback("csrf-same-host").build());
} else {
return (success().feedback("csrf-review.success").build()); //feedback("xss-stored-comment-failure")
}
}
private Review parseJson(String comment) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(comment, Review.class);
} catch (IOException e) {
return new Review();
return trackProgress(success().feedback("csrf-review.success").build()); //feedback("xss-stored-comment-failure")
}
}
}

View File

@ -15,6 +15,7 @@
<form accept-charset="UNKNOWN" id="basic-csrf-get"
method="GET" name="form1"
target="_blank"
successCallback=""
action="/WebGoat/csrf/basic-get-flag"
enctype="application/json;charset=UTF-8">
@ -26,10 +27,12 @@
<div class="adoc-content" th:replace="doc:CSRF_Basic_Get-1.adoc"></div>
<div class="attack-container">
<img th:src="@{/images/wolf-enabled.png}" class="webwolf-enabled"/>
<div class="assignment-success">
<i class="fa fa-2 fa-check hidden" aria-hidden="true">
</i>
</div>
<br/>
<form class="attack-form" accept-charset="UNKNOWN" id="confirm-flag-1"
method="POST" name="form2"
successCallback=""
@ -40,7 +43,10 @@
<input type="text" length="6" name="confirmFlagVal" value=""/>
<input name="submit" value="Submit" type="submit"/>
<br/>
<br/>
<br/>
<br/>
</form>
<div class="attack-feedback"></div>
@ -56,9 +62,9 @@
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/reviews.css}"/>
<script th:src="@{/lesson_js/csrf-review.js}" language="JavaScript"></script>
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="attack-container">
<img th:src="@{/images/wolf-enabled.png}" class="webwolf-enabled"/>
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="container-fluid">
<div class="panel post">
<div class="post-heading">
@ -133,65 +139,71 @@
padding: 7px;
margin-top:7px;
padding:5px;">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="container-fluid">
<div class="row">
<div class="col-md-8">
<div class="well well-sm">
<form class="attack-form" accept-charset="UNKNOWN" id="csrf-feedback"
method="POST"
prepareData="feedback"
action="/WebGoat/csrf/feedback/message"
contentType="application/json">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">
Name</label>
<input type="text" class="form-control" name="name" id="name"
placeholder="Enter name"
required="required"/>
</div>
<div class="form-group">
<label for="email">
Email Address</label>
<div class="input-group">
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="container-fluid">
<div class="row">
<div class="col-md-8">
<div class="well well-sm">
<form class="attack-form" accept-charset="UNKNOWN" id="csrf-feedback"
method="POST"
prepareData="feedback"
action="/WebGoat/csrf/feedback/message"
contentType="application/json">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name">
Name</label>
<input type="text" class="form-control" name="name" id="name"
placeholder="Enter name"
required="required"/>
</div>
<div class="form-group">
<label for="email">
Email Address</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-envelope"></span>
</span>
<input type="email" name="email" class="form-control" id="email"
placeholder="Enter email"
required="required"/></div>
<input type="email" name="email" class="form-control" id="email"
placeholder="Enter email"
required="required"/></div>
</div>
<div class="form-group">
<label for="subject">
Subject</label>
<select id="subject" name="subject" class="form-control"
required="required">
<option value="na" selected="">Choose One:</option>
<option value="service">General Customer Service</option>
<option value="suggestions">Suggestions</option>
<option value="product">Product Support</option>
</select>
</div>
</div>
<div class="form-group">
<label for="subject">
Subject</label>
<select id="subject" name="subject" class="form-control" required="required">
<option value="na" selected="">Choose One:</option>
<option value="service">General Customer Service</option>
<option value="suggestions">Suggestions</option>
<option value="product">Product Support</option>
</select>
<div class="col-md-6">
<div class="form-group">
<label for="name">
Message</label>
<textarea name="message" id="message" class="form-control" rows="9"
cols="25"
required="required"
placeholder="Message"></textarea>
</div>
</div>
<div class="col-md-12">
<button class="btn btn-primary pull-right" id="btnContactUs">
Send Message
</button>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="name">
Message</label>
<textarea name="message" id="message" class="form-control" rows="9" cols="25"
required="required"
placeholder="Message"></textarea>
</div>
</div>
<div class="col-md-12">
<button class="btn btn-primary pull-right" id="btnContactUs">
Send Message
</button>
</div>
</div>
</form>
</form>
</div>
</div>
</div>
</div>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
@ -211,7 +223,6 @@
<input name="submit" value="Submit" type="submit"/>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>

View File

@ -20,7 +20,7 @@ csrf-review-hint3=This one has a weak anti-CSRF protection, but you do need to o
csrf-feedback-hint1=Look at the content-type.
csrf-feedback-hint2=Try to post the same message with content-type text/plain
csrf-feedback-hint3=The json can be put into a hidden field inside
csrf-feedback-hint3=The json can be put into a hidden field inside
csrf-feedback-invalid-json=Invalid JSON received.
csrf-feedback-success=Congratulations you have found the correct solution, the flag is: {0}

View File

@ -8,11 +8,11 @@ In this assignment you need to achieve to POST the following JSON message to our
[source]
----
POST /csrf/feedback HTTP/1.1
POST /csrf/feedback/message HTTP/1.1
{
"name" : "WebGoat",
"email" : "webgoat@webgoat.org"
"email" : "webgoat@webgoat.org",
"content" : "WebGoat is the best!!"
}
----

View File

@ -13,9 +13,14 @@ match and this will ensure the server the request is running on the same domain.
Remember the session cookie should always be defined with http-only flag.
Another effective defense can be to add a custom request header to each call. This will work if all the interactions
== Custom headers not safe
Another defense can be to add a custom request header to each call. This will work if all the interactions
with the server are performed with JavaScript. On the server side you only need to check the presence of this header
if this header is not present deny the request.
Some frameworks offer this implementation by default however researcer Alex Infuhr found out that this can be bypassed
as well. You can read about: http://insert-blogspot.nl/2018/05/adobe-reader-pdf-client-side-request.html?m=1[Adobe Reader PDF - Client Side Request Injection]

View File

@ -4,7 +4,20 @@ The impact is limited only by what the logged in user can do (if the site/functi
The areas that are really prone to CSRF attacks are IoT devices and 'smart' appliances. Sadly, many consumer-grade routers
have also proven vulnerable to CSRF.
== CSRF Solution
== CSRF solutions
=== Same site cookie attribute
This is a new extension which modern browsers support which limits the scope of the cookie such that it will only be
attached to requests if those requests are 'same-site'
For example requests for `http://webgoat.org/something` will attach same-site cookies if the request is initiated from
`webgoat.org`.
There are two modes, strict and lax. The first one does not allow cross site request, this means when you are on
github.com and you want to like it through Facebook (and Facebook specifies same-site as strict) you will be
redirected to the login page, because the browser does not attach the cookie for Facebook.
More information can be found here: www.sjoerdlangkemper.nl/2016/04/14/preventin-csrf-with-samesite-cookie-attribute/
=== Other protections
Fortunately, many (web) application frameworks now come with built in support to handle CSRF attacks. For example, Spring and
Tomcat have this on by default. As long as you don't turn it off (like it is in WebGoat), you should be safe from CSRF attacks.

View File

@ -3,7 +3,7 @@
A lot of web applications implement no protection against CSRF they are somehow protected by the fact that
they only work with `application/json` as content type. The only way to make a request with this content-type from the
browser is with a XHR request. Before the browser can make such a request a preflight request will be made towards
the server (remember the CSRF request will be cross origin). If the preflight response does not allow the cross origin
the server (remember the CSRF request will be cross origin). If the pre-flight response does not allow the cross origin
request the browser will not make the call.
To make a long answer short: this is *not* a valid protection against CSRF.

View File

@ -46,13 +46,10 @@ public class CSRFFeedbackTest extends LessonTest {
mockMvc.perform(post("/csrf/feedback/message")
.contentType(MediaType.TEXT_PLAIN)
.cookie(new Cookie("JSESSIONID", "test"))
.header("host", "localhost:8080")
.header("origin", "localhost:8080")
.header("referer", "webgoat.org")
.content("{\"name\": \"Test\", \"email\": \"test1233@dfssdf.de\", \"subject\": \"service\", \"message\":\"dsaffd\"}"))
.andExpect(jsonPath("lessonCompleted", is(true)))
.andExpect(jsonPath("feedback", StringContains.containsString("the flag is: ")));
}
}

View File

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

View File

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

View File

@ -8,6 +8,7 @@ http-basics.hints.http_basic_quiz.1=Turn on Show Parameters or other features
http-basics.hints.http_basic_quiz.2=Try to intercept the request with <a href='https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project' title='Link to ZAP'>OWASP ZAP</a>
http-basics.empty=Try again, name cannot be empty.
http-basics.reversed=The server has reversed your name: {0}
http-basics.close=Try again: but this time enter a value before hitting go.

View File

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

View File

@ -48,7 +48,7 @@ public class HttpBasicsInterceptRequest extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.GET)
public @ResponseBody
AttackResult completed(HttpServletRequest request) throws IOException {
AttackResult completed(HttpServletRequest request) {
String header = null;
String param = null;
if (request != null && (header = request.getHeader("x-request-intercepted")) != null

View File

@ -2,7 +2,7 @@
== HTTP Proxy Overview
Many times proxies are used as a way of accessing otherwise blocked content. A user might connect to server A, which relays content from server B
... Because Server B is blocked wihtin the user's network. That's not the use case we will be dealing with here, but the concept is the same.
... Because Server B is blocked within the user's network. That's not the use case we will be dealing with here, but the concept is the same.
HTTP Proxies receive requests from a client and relay them. They also typically record them. They act as a man-in-the-middle (keep that in mind if you decide to
use a proxy server to connect to some other system that is otherwise blocked). We won't get into HTTP vs HTTPS just yet, but that's an important topic in
relationship to proxies.

View File

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

View File

@ -4,5 +4,5 @@ Older apps may follow different patterns, but RESTful apps (which is what's goin
to perform different functions.
Use that knowledge to take the same base request, change its method, path and body (payload) to modify another user's (Buffalo Bill's) profile.
Change the role to something lower (since higher privilege roles and users are ususally lower numbers). Also change modify the
Change the role to something lower (since higher privilege roles and users are ususally lower numbers). Also change the
user's color to 'red'.

View File

@ -1 +1 @@
Please input the alternate path to the Url to view your own profile. Please start witih 'WebGoat' (i.e. disregard 'http://localhost:8080/')
Please input the alternate path to the Url to view your own profile. Please start with 'WebGoat' (i.e. disregard 'http://localhost:8080/')

View File

@ -15,12 +15,12 @@ Examples of Direct Object References using the GET method may look something lik
=== Other Methods
POST, PUT, DELETE or other methods are also potentially succeptible and mainly only differ in the method and the potential payload.
POST, PUT, DELETE or other methods are also potentially susceptible and mainly only differ in the method and the potential payload.
== *Insecure* Direct Object References
These are considered insecure when the reference is not properly handled and allows for authorization bypasses or disclose private data that could be used to
perform opreations or access data that the user should not be able to perform or access.
perform operations or access data that the user should not be able to perform or access.
Let's say that as a user, you go to view your profile and the URL looks something like:
`https://some.company.tld/app/user/23398`

View File

@ -1,6 +1,6 @@
=== Authenticate First, Abuse Authorization Later
Many access control issues are succeptible to attack from an authenticated-but-unauthorized user. So, let's start by legitimately authenticating. Then, we will look for ways to bypass or abuse Authorization.
Many access control issues are susceptible to attack from an authenticated-but-unauthorized user. So, let's start by legitimately authenticating. Then, we will look for ways to bypass or abuse Authorization.
The id and password for the account in this case are 'tom' and 'cat' (It is an insecure app, right?).

View File

@ -38,7 +38,7 @@ For example, if a super-user or admin can edit other's profiles ... That is some
examples would include detected violations or attempts to violate access control mechanisms.
=== Using Indrect References
Not many applications employ it, but you can use *indirect* refrences. In this case you can run your references across a hahsing,
Not many applications employ it, but you can use *indirect* references. In this case you can run your references across a hashing,
encoding or other function on the server so that the id that the client sees is not the actual reference
which the server handles. This will reduce efficiency some (a common trade-off for security) and is still subject to being
guessed, brute-forced or reverse engineered.

View File

@ -0,0 +1,27 @@
<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-deserialization</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>org.owasp.webgoat.lesson</groupId>
<artifactId>webgoat-lessons-parent</artifactId>
<version>v8.0.0.M15</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>
</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 InsecureDeserialization extends NewLesson {
@Override
public Category getDefaultCategory() {
return Category.INSECURE_DESERIALIZATION;
}
@Override
public List<String> getHints() {
return Lists.newArrayList();
}
@Override
public Integer getDefaultRanking() {
return 1;
}
@Override
public String getTitle() {
return "insecure-deserialization.title";
}
@Override
public String getId() {
return "InsecureDeserialization";
}
}

View File

@ -0,0 +1,90 @@
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;
import java.io.ObjectInputStream;
import java.io.ByteArrayInputStream;
import java.util.Base64;
/**
* *************************************************************************************************
*
*
* 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("/InsecureDeserialization/task")
public class InsecureDeserializationTask extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public
@ResponseBody
AttackResult completed(@RequestParam String token) throws IOException {
String b64token;
byte [] data;
ObjectInputStream ois;
Object o;
long before, after;
int delay;
b64token = token.replace('-', '+').replace('_', '/');
try {
data = Base64.getDecoder().decode(b64token);
ois = new ObjectInputStream( new ByteArrayInputStream(data) );
} catch (Exception e) {
return trackProgress(failed().build());
}
before = System.currentTimeMillis();
try {
o = ois.readObject();
} catch (Exception e) {
o = null;
}
after = System.currentTimeMillis();
ois.close();
delay = (int)(after - before);
if ( delay > 7000 ) {
return trackProgress(failed().build());
}
if ( delay < 3000 ) {
return trackProgress(failed().build());
}
return trackProgress(success().build());
}
}

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