Use separate project for integration tests so we can start WebGoat and WebWolf

This commit is contained in:
Nanne Baars 2019-08-25 17:43:14 +02:00
parent 139651615e
commit ff530e926e
33 changed files with 793 additions and 742 deletions

View File

@ -143,6 +143,7 @@
<module>webgoat-lessons</module>
<module>webgoat-server</module>
<module>webwolf</module>
<module>webgoat-integration-tests</module>
</modules>
<dependencies>

View File

@ -30,7 +30,6 @@
*/
package org.owasp.webgoat;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.plugins.PluginEndpointPublisher;
import org.owasp.webgoat.plugins.PluginsLoader;
import org.owasp.webgoat.session.Course;
@ -38,30 +37,17 @@ import org.owasp.webgoat.session.UserSessionData;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.session.WebgoatContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.web.client.RestTemplate;
import java.io.File;
@SpringBootApplication
@Slf4j
public class WebGoat extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebGoat.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(WebGoat.class, args);
}
@Configuration
public class WebGoat {
@Bean(name = "pluginTargetDirectory")
public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) {

View File

@ -58,7 +58,7 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
* Constructor for the Lesson object
*/
public AbstractLesson() {
id = new Integer(++count);
id = ++count;
}

View File

@ -36,40 +36,40 @@ import lombok.Getter;
*/
public enum Category {
INTRODUCTION("Introduction", new Integer(5)),
GENERAL("General", new Integer(100)),
INTRODUCTION("Introduction", 5),
GENERAL("General", 100),
INJECTION("(A1) Injection", new Integer(300)),
AUTHENTICATION("(A2) Broken Authentication", new Integer(302)),
INSECURE_COMMUNICATION("(A3) Sensitive Data Exposure", new Integer(303)),
XXE("(A4) XML External Entities (XXE)", Integer.valueOf(304)),
ACCESS_CONTROL("(A5) Broken Access Control", new Integer(305)),
INJECTION("(A1) Injection", 300),
AUTHENTICATION("(A2) Broken Authentication", 302),
INSECURE_COMMUNICATION("(A3) Sensitive Data Exposure", 303),
XXE("(A4) XML External Entities (XXE)", 304),
ACCESS_CONTROL("(A5) Broken Access Control", 305),
XSS("(A7) Cross-Site Scripting (XSS)", new Integer(307)),
INSECURE_DESERIALIZATION("(A8) Insecure Deserialization", new Integer(308)),
VULNERABLE_COMPONENTS("(A9) Vulnerable Components", new Integer(309)),
XSS("(A7) Cross-Site Scripting (XSS)", 307),
INSECURE_DESERIALIZATION("(A8) Insecure Deserialization", 308),
VULNERABLE_COMPONENTS("(A9) Vulnerable Components", 309),
REQUEST_FORGERIES("(A8:2013) Request Forgeries", new Integer(318)),
REQUEST_FORGERIES("(A8:2013) Request Forgeries", 318),
REQ_FORGERIES("Request Forgeries", new Integer(450)),
REQ_FORGERIES("Request Forgeries", 450),
INSECURE_CONFIGURATION("Insecure Configuration", new Integer(600)),
INSECURE_STORAGE("Insecure Storage", new Integer(800)),
INSECURE_CONFIGURATION("Insecure Configuration", 600),
INSECURE_STORAGE("Insecure Storage", 800),
AJAX_SECURITY("AJAX Security", new Integer(1000)),
BUFFER_OVERFLOW("Buffer Overflows", new Integer(1100)),
CODE_QUALITY("Code Quality", new Integer(1200)),
CONCURRENCY("Concurrency", new Integer(1300)),
ERROR_HANDLING("Improper Error Handling", new Integer(1400)),
DOS("Denial of Service", new Integer(1500)),
MALICIOUS_EXECUTION("Malicious Execution", new Integer(1600)),
CLIENT_SIDE("Client side", new Integer(1700)),
SESSION_MANAGEMENT("Session Management Flaws", new Integer(1800)),
WEB_SERVICES("Web Services", new Integer(1900)),
ADMIN_FUNCTIONS("Admin Functions", new Integer(2000)),
CHALLENGE("Challenges", new Integer(3000));
AJAX_SECURITY("AJAX Security", 1000),
BUFFER_OVERFLOW("Buffer Overflows", 1100),
CODE_QUALITY("Code Quality", 1200),
CONCURRENCY("Concurrency", 1300),
ERROR_HANDLING("Improper Error Handling", 1400),
DOS("Denial of Service", 1500),
MALICIOUS_EXECUTION("Malicious Execution", 1600),
CLIENT_SIDE("Client side", 1700),
SESSION_MANAGEMENT("Session Management Flaws", 1800),
WEB_SERVICES("Web Services", 1900),
ADMIN_FUNCTIONS("Admin Functions", 2000),
CHALLENGE("Challenges", 3000);
@Getter
private String name;

View File

@ -51,7 +51,7 @@ public abstract class LessonAdapter extends AbstractLesson {
// Do Nothing - called when restart lesson is pressed. Each lesson can do something
}
private final static Integer DEFAULT_RANKING = new Integer(1000);
private final static Integer DEFAULT_RANKING = 1000;
/**
* <p>getDefaultRanking.</p>

View File

@ -16,7 +16,7 @@ import javax.validation.constraints.Size;
public class UserForm {
@NotNull
@Size(min=6, max=20)
@Size(min=6, max=40)
@Pattern(regexp = "[a-z0-9-]*", message = "can only contain lowercase letters, digits, and -")
private String username;
@NotNull

View File

@ -22,7 +22,7 @@ import static org.mockito.Mockito.when;
* @since 5/20/17.
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(locations = "classpath:/application-test.properties")
@TestPropertySource(locations = {"classpath:/application-webgoat.properties", "classpath:/application-test.properties"})
public abstract class LessonTest {
@LocalServerPort

View File

@ -0,0 +1,66 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>webgoat-integration-tests</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-parent</artifactId>
<version>v8.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-server</artifactId>
<version>${project.version}</version>
<classifier>internal</classifier>
</dependency>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webwolf</artifactId>
<version>${project.version}</version>
<classifier>internal</classifier>
</dependency>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webwolf</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<forkCount>0</forkCount>
<reuseForks>true</reuseForks>
<argLine>
--illegal-access=permit
</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,127 @@
package org.owasp.webgoat;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class GeneralLessonTest extends IntegrationTest {
@Test
public void httpBasics() {
startLesson("HttpBasics");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("person", "goatuser");
checkAssignment(url("HttpBasics/attack1"), params, true);
params.clear();
params.put("answer", "POST");
params.put("magic_answer", "33");
params.put("magic_num", "4");
checkAssignment(url("HttpBasics/attack2"), params, false);
params.clear();
params.put("answer", "POST");
params.put("magic_answer", "33");
params.put("magic_num", "33");
checkAssignment(url("HttpBasics/attack2"), params, true);
checkResults("/HttpBasics/");
}
@Test
public void httpProxies() {
startLesson("HttpProxies");
Assert.assertThat(RestAssured.given()
.when().config(restConfig).cookie("JSESSIONID", getWebGoatCookie()).header("x-request-intercepted", "true")
.contentType(ContentType.JSON)
.get(url("HttpProxies/intercept-request?changeMe=Requests are tampered easily"))
.then()
.statusCode(200).extract().path("lessonCompleted"), CoreMatchers.is(true));
checkResults("/HttpProxies/");
}
@Test
public void cia() {
startLesson("CIA");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("question_0_solution", "Solution 3: By stealing a database where names and emails are stored and uploading it to a website.");
params.put("question_1_solution", "Solution 1: By changing the names and emails of one or more users stored in a database.");
params.put("question_2_solution", "Solution 4: By launching a denial of service attack on the servers.");
params.put("question_3_solution", "Solution 2: The systems security is compromised even if only one goal is harmed.");
checkAssignment(url("/WebGoat/cia/quiz"), params, true);
checkResults("/cia/");
}
@Test
public void securePasswords() {
startLesson("SecurePasswords");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("password", "ajnaeliclm^&&@kjn.");
checkAssignment(url("/WebGoat/SecurePasswords/assignment"), params, true);
checkResults("SecurePasswords/");
startLesson("AuthBypass");
params.clear();
params.put("secQuestion2", "John");
params.put("secQuestion3", "Main");
params.put("jsEnabled", "1");
params.put("verifyMethod", "SEC_QUESTIONS");
params.put("userId", "12309746");
checkAssignment(url("/WebGoat/auth-bypass/verify-account"), params, true);
checkResults("/auth-bypass/");
startLesson("HttpProxies");
Assert.assertThat(RestAssured.given().when().config(restConfig).cookie("JSESSIONID", getWebGoatCookie()).header("x-request-intercepted", "true")
.contentType(ContentType.JSON)
.get(url("/WebGoat/HttpProxies/intercept-request?changeMe=Requests are tampered easily")).then()
.statusCode(200).extract().path("lessonCompleted"), CoreMatchers.is(true));
checkResults("/HttpProxies/");
}
@Test
public void chrome() {
startLesson("ChromeDevTools");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("param1", "42");
params.put("param2", "24");
String result =
RestAssured.given()
.when()
.config(restConfig)
.cookie("JSESSIONID", getWebGoatCookie())
.header("webgoat-requested-by", "dom-xss-vuln")
.header("X-Requested-With", "XMLHttpRequest")
.formParams(params)
.post(url("/WebGoat/CrossSiteScripting/phone-home-xss"))
.then()
.statusCode(200)
.extract().path("output");
String secretNumber = result.substring("phoneHome Response is ".length());
params.clear();
params.put("successMessage", secretNumber);
checkAssignment(url("/WebGoat/ChromeDevTools/dummy"), params, true);
params.clear();
params.put("number", "24");
params.put("network_num", "24");
checkAssignment(url("/WebGoat/ChromeDevTools/network"), params, true);
checkResults("/ChromeDevTools/");
}
}

View File

@ -0,0 +1,200 @@
package org.owasp.webgoat;
import io.restassured.RestAssured;
import io.restassured.config.RestAssuredConfig;
import io.restassured.config.SSLConfig;
import lombok.Getter;
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.owasp.webwolf.WebWolf;
import org.springframework.boot.builder.SpringApplicationBuilder;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.Map;
import java.util.UUID;
public abstract class IntegrationTest {
private static String WEBGOAT_URL = "http://localhost:8080/WebGoat/";
private static String WEBWOLF_URL = "http://localhost:9090/";
//This also allows to test the application with HTTPS when outside testing option is used
protected static RestAssuredConfig restConfig = RestAssuredConfig.newConfig().sslConfig(new SSLConfig().relaxedHTTPSValidation());
@Getter
private String webGoatCookie;
@Getter
private String webWolfCookie;
@Getter
private String webgoatUser = UUID.randomUUID().toString();
private static boolean started = false;
@BeforeClass
public static void beforeAll() {
if (!started) {
started = true;
if (!areAlreadyRunning()) {
SpringApplicationBuilder wgs = new SpringApplicationBuilder(StartWebGoat.class)
.properties(Map.of("spring.config.name", "application-webgoat"));
wgs.run();
SpringApplicationBuilder wws = new SpringApplicationBuilder(WebWolf.class)
.properties(Map.of("spring.config.name", "application-webwolf"));
wws.run();
}
}
}
private static boolean areAlreadyRunning() {
return checkIfServerIsRunnningOn(9090) && checkIfServerIsRunnningOn(8080);
}
private static boolean checkIfServerIsRunnningOn(int port) {
try (var ignored = new ServerSocket(port)) {
return false;
} catch (IOException e) {
return true;
}
}
protected String url(String url) {
url = url.replaceFirst("/WebGoat/", "");
url = url.replaceFirst("/WebGoat", "");
url = url.startsWith("/") ? url.replaceFirst("/", "") : url;
return WEBGOAT_URL + url;
}
protected String webWolfUrl(String url) {
url = url.startsWith("/") ? url.replaceFirst("/", "") : url;
return WEBWOLF_URL + url;
}
@Before
public void login() {
webGoatCookie = RestAssured.given()
.when()
.config(restConfig)
.formParam("username", webgoatUser)
.formParam("password", "password")
.formParam("matchingPassword", "password")
.formParam("agree", "agree")
.post(url("register.mvc"))
.then()
.cookie("JSESSIONID")
.statusCode(302)
.extract()
.cookie("JSESSIONID");
webWolfCookie = RestAssured.given()
.when()
.config(restConfig)
.formParam("username", webgoatUser)
.formParam("password", "password")
.post(WEBWOLF_URL + "login")
.then()
.cookie("WEBWOLFSESSION")
.statusCode(302)
.extract()
.cookie("WEBWOLFSESSION");
}
@After
public void logout() {
RestAssured.given()
.when()
.config(restConfig)
.get(WEBGOAT_URL + "logout")
.then()
.statusCode(200);
}
/**
* At start of a lesson. The .lesson.lesson is visited and the lesson is reset.
*
* @param lessonName
*/
public void startLesson(String lessonName) {
RestAssured.given()
.when()
.config(restConfig)
.cookie("JSESSIONID", getWebGoatCookie())
.get(url(lessonName + ".lesson.lesson"))
.then()
.statusCode(200);
RestAssured.given()
.when()
.config(restConfig)
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/restartlesson.mvc"))
.then()
.statusCode(200);
}
/**
* Helper method for most common type of test.
* POST with parameters.
* Checks for 200 and lessonCompleted as indicated by expectedResult
*
* @param url
* @param params
* @param expectedResult
*/
public void checkAssignment(String url, Map<String, ?> params, boolean expectedResult) {
Assert.assertThat(
RestAssured.given()
.when()
.config(restConfig)
.cookie("JSESSIONID", getWebGoatCookie())
.formParams(params)
.post(url)
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult));
}
/**
* Helper method for most common type of test.
* PUT with parameters.
* Checks for 200 and lessonCompleted as indicated by expectedResult
*
* @param url
* @param params
* @param expectedResult
*/
public void checkAssignmentWithPUT(String url, Map<String, ?> params, boolean expectedResult) {
Assert.assertThat(
RestAssured.given()
.when()
.config(restConfig)
.cookie("JSESSIONID", getWebGoatCookie())
.formParams(params)
.put(url)
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult));
}
public void checkResults(String prefix) {
Assert.assertThat(RestAssured.given()
.when()
.config(restConfig)
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/lessonoverview.mvc"))
.then()
.statusCode(200).extract().jsonPath().getList("solved"), CoreMatchers.everyItem(CoreMatchers.is(true)));
Assert.assertThat(RestAssured.given()
.when()
.config(restConfig)
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/lessonoverview.mvc"))
.then()
.statusCode(200).extract().jsonPath().getList("assignment.path"), CoreMatchers.everyItem(CoreMatchers.startsWith(prefix)));
}
}

View File

@ -0,0 +1,76 @@
package org.owasp.webgoat;
import io.restassured.RestAssured;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import java.util.Map;
public class PasswordResetLessonTest extends IntegrationTest {
@Test
public void solveAssignment() {
//WebGoat
startLesson("PasswordReset");
clickForgotEmailLink("tom@webgoat-cloud.org");
//WebWolf
var link = getPasswordResetLinkFromLandingPage();
//WebGoat
changePassword(link);
checkAssignment(url("PasswordReset/reset/login"), Map.of("email", "tom@webgoat-cloud.org", "password", "123456"), true);
}
@Test
public void sendEmailShouldBeAvailabeInWebWolf() {
startLesson("PasswordReset");
clickForgotEmailLink(getWebgoatUser() + "@webgoat.org");
var responseBody = RestAssured.given()
.when()
.config(restConfig)
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/WebWolf/mail"))
.then()
.extract().response().getBody().asString();
Assertions.assertThat(responseBody).contains("Hi, you requested a password reset link");
}
private void changePassword(String link) {
RestAssured.given()
.when()
.config(restConfig)
.cookie("JSESSIONID", getWebGoatCookie())
.formParams("resetLink", link, "password", "123456")
.post(url("PasswordReset/reset/change-password"))
.then()
.statusCode(200);
}
private String getPasswordResetLinkFromLandingPage() {
var responseBody = RestAssured.given()
.when()
.config(restConfig)
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("WebWolf/requests"))
.then()
.extract().response().getBody().asString();
int startIndex = responseBody.lastIndexOf("\"path\" : \"/PasswordReset/reset/reset-password/");
var link = responseBody.substring(startIndex + "\"path\" : \"/PasswordReset/reset/reset-password/".length(), responseBody.indexOf(",", startIndex) - 1);
return link;
}
private void clickForgotEmailLink(String user) {
RestAssured.given()
.when()
.header("host", "localhost:9090")
.config(restConfig)
.cookie("JSESSIONID", getWebGoatCookie())
.formParams("email", user)
.post(url("PasswordReset/ForgotPassword/create-password-reset-link"))
.then()
.statusCode(200);
}
}

View File

@ -0,0 +1,49 @@
package org.owasp.webgoat;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class SqlInjectionAdvancedTest extends IntegrationTest {
@Test
public void runTests() {
startLesson("SqlInjectionAdvanced");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("username_reg", "tom' AND substring(password,1,1)='t");
params.put("password_reg", "password");
params.put("email_reg", "someone@microsoft.com");
params.put("confirm_password", "password");
checkAssignmentWithPUT(url("/WebGoat/SqlInjectionAdvanced/challenge"), params, true);
params.clear();
params.put("username_login", "tom");
params.put("password_login", "thisisasecretfortomonly");
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/challenge_Login"), params, true);
params.clear();
params.put("userid_6a", "'; SELECT * FROM user_system_data;--");
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true);
params.clear();
params.put("userid_6a", "Smith' union select userid,user_name, user_name,user_name,password,cookie,userid from user_system_data --");
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true);
params.clear();
params.put("userid_6b", "passW0rD");
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6b"), params, true);
params.clear();
params.put("question_0_solution", "Solution 4: A statement has got values instead of a prepared statement");
params.put("question_1_solution", "Solution 3: ?");
params.put("question_2_solution", "Solution 2: Prepared statements are compiled once by the database management system waiting for input and are pre-compiled this way.");
params.put("question_3_solution", "Solution 3: Placeholders can prevent that the users input gets attached to the SQL query resulting in a seperation of code and data.");
params.put("question_4_solution", "Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/quiz"), params, true);
checkResults("/SqlInjectionAdvanced/");
}
}

View File

@ -0,0 +1,82 @@
package org.owasp.webgoat;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class SqlInjectionLessonTest extends IntegrationTest {
private static final String sql_2 = "select department from employees where last_name='Franco'";
private static final String sql_3 = "update employees set department='Sales' where last_name='Barnett'";
private static final String sql_4_drop = "alter table employees drop column phone";
private static final String sql_4_add = "alter table employees add column phone varchar(20)";
private static final String sql_5 = "grant alter table to UnauthorizedUser";
private static final String sql_9_account = " ' ";
private static final String sql_9_operator = "or";
private static final String sql_9_injection = "'1'='1";
private static final String sql_10_login_count = "2";
private static final String sql_10_userid = "1 or 1=1";
private static final String sql_11_a = "Smith' or '1' = '1";
private static final String sql_11_b = "3SL99A' or '1'='1";
private static final String sql_12_a = "Smith";
private static final String sql_12_b = "3SL99A' ; update employees set salary= '100000' where last_name='Smith";
private static final String sql_13 = "%update% '; drop table access_log ; --'";
@Test
public void runTests() {
startLesson("SqlInjection");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("query", sql_2);
checkAssignment(url("/WebGoat/SqlInjection/attack2"), params, true);
params.clear();
params.put("query", sql_3);
checkAssignment(url("/WebGoat/SqlInjection/attack3"), params, true);
params.clear();
params.put("query", sql_4_drop);
checkAssignment(url("/WebGoat/SqlInjection/attack4"), params, false);
params.clear();
params.put("query", sql_4_add);
checkAssignment(url("/WebGoat/SqlInjection/attack4"), params, true);
params.clear();
params.put("query", sql_5);
checkAssignment(url("/WebGoat/SqlInjection/attack5"), params, true);
params.clear();
params.put("operator", sql_9_operator);
params.put("account", sql_9_account);
params.put("injection", sql_9_injection);
checkAssignment(url("/WebGoat/SqlInjection/assignment5a"), params, true);
params.clear();
params.put("login_count", sql_10_login_count);
params.put("userid", sql_10_userid);
checkAssignment(url("/WebGoat/SqlInjection/assignment5b"), params, true);
params.clear();
params.put("name", sql_11_a);
params.put("auth_tan", sql_11_b);
checkAssignment(url("/WebGoat/SqlInjection/attack8"), params, true);
params.clear();
params.put("name", sql_12_a);
params.put("auth_tan", sql_12_b);
checkAssignment(url("/WebGoat/SqlInjection/attack9"), params, true);
params.clear();
params.put("action_string", sql_13);
checkAssignment(url("/WebGoat/SqlInjection/attack10"), params, true);
checkResults("/SqlInjection/");
}
}

View File

@ -1,37 +1,39 @@
package org.owasp.webgoat;
import java.util.HashMap;
import java.util.Map;
public class SqlInjectionMitigation_TestHelper extends TestHelper {
public void runTests(String webgoatURL, String cookie) {
startLesson(cookie, webgoatURL, "SqlInjectionMitigations");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("field1", "getConnection");
params.put("field2", "PreparedStatement prep");
params.put("field3", "prepareStatement");
params.put("field4", "?");
params.put("field5", "?");
params.put("field6", "prep.setString(1,\"\")");
params.put("field7", "prep.setString(2,\\\"\\\")");
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjectionMitigations/attack10a", params, true);
params.put("editor", "try {\r\n" +
" Connection conn = DriverManager.getConnection(DBURL,DBUSER,DBPW);\r\n" +
" PreparedStatement prep = conn.prepareStatement(\"select id from users where name = ?\");\r\n" +
" prep.setString(1,\"me\");\r\n" +
" prep.execute();\r\n" +
" System.out.println(conn); //should output 'null'\r\n" +
"} catch (Exception e) {\r\n" +
" System.out.println(\"Oops. Something went wrong!\");\r\n" +
"}");
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjectionMitigations/attack10b", params, true);
//checkResults(cookie, webgoatURL, "/SqlInjectionMitigations/");
}
}
package org.owasp.webgoat;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class SqlInjectionMitigationTest extends IntegrationTest {
@Test
public void runTests() {
startLesson("SqlInjectionMitigations");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("field1", "getConnection");
params.put("field2", "PreparedStatement prep");
params.put("field3", "prepareStatement");
params.put("field4", "?");
params.put("field5", "?");
params.put("field6", "prep.setString(1,\"\")");
params.put("field7", "prep.setString(2,\\\"\\\")");
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10a"), params, true);
params.put("editor", "try {\r\n" +
" Connection conn = DriverManager.getConnection(DBURL,DBUSER,DBPW);\r\n" +
" PreparedStatement prep = conn.prepareStatement(\"select id from users where name = ?\");\r\n" +
" prep.setString(1,\"me\");\r\n" +
" prep.execute();\r\n" +
" System.out.println(conn); //should output 'null'\r\n" +
"} catch (Exception e) {\r\n" +
" System.out.println(\"Oops. Something went wrong!\");\r\n" +
"}");
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10b"), params, true);
//checkResults(webGoatCookie, webgoatURL, "/SqlInjectionMitigations/");
}
}

View File

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

View File

@ -7,7 +7,6 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@ -17,69 +16,67 @@ import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.UUID;
import static org.springframework.util.StringUtils.*;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
/**
* Part of the password reset assignment. Used to send the e-mail.
*
* @author nbaars
* @since 8/20/17.
*/
@AssignmentPath("/PasswordReset/ForgotPassword")
public class ResetLinkAssignmentForgotPassword extends AssignmentEndpoint {
private final RestTemplate restTemplate;
private final String webWolfMailURL;
private final RestTemplate restTemplate;
private final String webWolfMailURL;
public ResetLinkAssignmentForgotPassword(RestTemplate restTemplate,
@Value("${webwolf.url.mail}") String webWolfMailURL) {
this.restTemplate = restTemplate;
this.webWolfMailURL = webWolfMailURL;
}
public ResetLinkAssignmentForgotPassword(RestTemplate restTemplate,
@Value("${webwolf.url.mail}") String webWolfMailURL) {
this.restTemplate = restTemplate;
this.webWolfMailURL = webWolfMailURL;
}
@RequestMapping(method = POST, value = "/create-password-reset-link")
@ResponseBody
public AttackResult sendPasswordResetLink(@RequestParam String email, HttpServletRequest request, @CookieValue("JSESSIONID") String cookie) {
String resetLink = UUID.randomUUID().toString();
ResetLinkAssignment.resetLinks.add(resetLink);
String host = request.getHeader("host");
if (org.springframework.util.StringUtils.hasText(email)) {
if (email.equals(ResetLinkAssignment.TOM_EMAIL) && host.contains("9090")) { //User indeed changed the host header.
ResetLinkAssignment.userToTomResetLink.put(getWebSession().getUserName(), resetLink);
fakeClickingLinkEmail(host, resetLink);
} else {
@RequestMapping(method = POST, value = "/create-password-reset-link")
@ResponseBody
public AttackResult sendPasswordResetLink(@RequestParam String email, HttpServletRequest request) {
String resetLink = UUID.randomUUID().toString();
ResetLinkAssignment.resetLinks.add(resetLink);
String host = request.getHeader("host");
if (hasText(email)) {
if (email.equals(ResetLinkAssignment.TOM_EMAIL) && host.contains("9090")) { //User indeed changed the host header.
ResetLinkAssignment.userToTomResetLink.put(getWebSession().getUserName(), resetLink);
fakeClickingLinkEmail(host, resetLink);
} else {
try {
sendMailToUser(email, host, resetLink);
} catch (Exception e) {
return failed().output("E-mail can't be send. please try again.").build();
}
}
}
return success().feedback("email.send").feedbackArgs(email).build();
}
private void sendMailToUser(@RequestParam String email, String host, String resetLink) {
int index = email.indexOf("@");
String username = email.substring(0, index == -1 ? email.length() : index);
PasswordResetEmail mail = PasswordResetEmail.builder()
.title("Your password reset link")
.contents(String.format(ResetLinkAssignment.TEMPLATE, host, resetLink))
.sender("password-reset@webgoat-cloud.net")
.recipient(username).build();
this.restTemplate.postForEntity(webWolfMailURL, mail, Object.class);
}
private void fakeClickingLinkEmail(String host, String resetLink) {
try {
sendMailToUser(email, host, resetLink);
} catch(Exception e) { return failed().output("E-mail can't be send. please try again.").build(); }
}
HttpHeaders httpHeaders = new HttpHeaders();
HttpEntity httpEntity = new HttpEntity(httpHeaders);
new RestTemplate().exchange(String.format("http://%s/PasswordReset/reset/reset-password/%s", host, resetLink), HttpMethod.GET, httpEntity, Void.class);
} catch (Exception e) {
//don't care
}
}
return success().feedback("email.send").feedbackArgs(email).build();
}
private void sendMailToUser(@RequestParam String email, String host, String resetLink) {
int index = email.indexOf("@");
String username = email.substring(0, index == -1 ? email.length() : index);
PasswordResetEmail mail = PasswordResetEmail.builder()
.title("Your password reset link")
.contents(String.format(ResetLinkAssignment.TEMPLATE, host, resetLink))
.sender("password-reset@webgoat-cloud.net")
.recipient(username)
.time(LocalDateTime.now()).build();
this.restTemplate.postForEntity(webWolfMailURL, mail, Object.class);
}
/**
* We need to add the current cookie of the user otherwise we cannot distinguish in WebWolf for
* which user we need to trace the incoming request. In normal situation this HOST will be in your
* full control so every incoming request would be valid.
*/
private void fakeClickingLinkEmail(String host, String resetLink) {
try {
HttpHeaders httpHeaders = new HttpHeaders();
HttpEntity httpEntity = new HttpEntity(httpHeaders);
new RestTemplate().exchange(String.format("http://%s/PasswordReset/reset/reset-password/%s", host, resetLink), HttpMethod.GET, httpEntity, Void.class);
} catch (Exception e) {
//don't care
}
}
}

View File

@ -9,6 +9,8 @@ password-questions-wrong-user=You need to find a different user you are logging
password-questions-unknown-user=User {0} is not a valid user.
password-questions-one-successful=You answered one question successfully please try another one.
email.send=An e-mail has been send to {0}
password-reset-no-user=Please supply a valid e-mail address.
password-reset-solved=Congratulations you solved the assignment, please type in the following code in the e-mail field: {0}
password-reset-not-solved=Sorry but you did not redirect the reset link to WebWolf

View File

@ -139,17 +139,6 @@
<artifactId>secure-passwords</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
<!--uncommment below to run/include lesson template in WebGoat Build-->
<!--<dependency>-->
<!--<groupId>org.owasp.webgoat.lesson</groupId>-->
@ -199,6 +188,22 @@
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<phase>test-compile</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>internal</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

View File

@ -27,6 +27,11 @@ package org.owasp.webgoat;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Import;
import java.util.Map;
/**
* Main entry point, this project is here to get all the lesson jars included to the final jar file
@ -36,10 +41,11 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
*/
@SpringBootApplication
@Slf4j
public class StartWebGoat {
public class StartWebGoat extends SpringBootServletInitializer {
public static void main(String[] args) {
log.info("Starting WebGoat with args: {}", args);
SpringApplication.run(WebGoat.class, args);
System.setProperty("spring.config.name", "application-webgoat");
SpringApplication.run(StartWebGoat.class, args);
}
}

View File

@ -1,137 +0,0 @@
package org.owasp.webgoat;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.util.HashMap;
import java.util.Map;
import io.restassured.http.ContentType;
public class General_TestHelper extends TestHelper {
public void httpBasics(String webgoatURL, String cookie) {
startLesson(cookie, webgoatURL, "HttpBasics");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("person", "goatuser");
checkAssignment(cookie, webgoatURL+"/WebGoat/HttpBasics/attack1", params, true);
params.clear();
params.put("answer", "POST");
params.put("magic_answer", "33");
params.put("magic_num", "4");
checkAssignment(cookie, webgoatURL+"/WebGoat/HttpBasics/attack2", params, false);
params.clear();
params.put("answer", "POST");
params.put("magic_answer", "33");
params.put("magic_num", "33");
checkAssignment(cookie, webgoatURL+"/WebGoat/HttpBasics/attack2", params, true);
checkResults(cookie, webgoatURL, "/HttpBasics/");
}
public void httpProxies(String webgoatURL, String cookie) {
startLesson(cookie, webgoatURL, "HttpProxies");
assertThat(given()
.when().config(restConfig).cookie("JSESSIONID", cookie).header("x-request-intercepted", "true")
.contentType(ContentType.JSON)
//.log().all()
.get(webgoatURL + "/WebGoat/HttpProxies/intercept-request?changeMe=Requests are tampered easily").then()
//.log().all()
.statusCode(200).extract().path("lessonCompleted"), is(true));
checkResults(cookie, webgoatURL, "/HttpProxies/");
}
public void cia(String webgoatURL, String cookie) {
startLesson(cookie, webgoatURL, "CIA");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("question_0_solution", "Solution 3: By stealing a database where names and emails are stored and uploading it to a website.");
params.put("question_1_solution", "Solution 1: By changing the names and emails of one or more users stored in a database.");
params.put("question_2_solution", "Solution 4: By launching a denial of service attack on the servers.");
params.put("question_3_solution", "Solution 2: The systems security is compromised even if only one goal is harmed.");
checkAssignment(cookie, webgoatURL+"/WebGoat/cia/quiz", params, true);
checkResults(cookie, webgoatURL, "/cia/");
}
public void securePasswords(String webgoatURL, String cookie) {
startLesson(cookie, webgoatURL, "SecurePasswords");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("password", "ajnaeliclm^&&@kjn.");
checkAssignment(cookie, webgoatURL+"/WebGoat/SecurePasswords/assignment", params, true);
checkResults(cookie, webgoatURL, "SecurePasswords/");
startLesson(cookie, webgoatURL, "AuthBypass");
params.clear();
params.put("secQuestion2", "John");
params.put("secQuestion3", "Main");
params.put("jsEnabled", "1");
params.put("verifyMethod", "SEC_QUESTIONS");
params.put("userId", "12309746");
checkAssignment(cookie, webgoatURL + "/WebGoat/auth-bypass/verify-account", params, true);
checkResults(cookie, webgoatURL, "/auth-bypass/");
startLesson(cookie, webgoatURL, "HttpProxies");
assertThat(given().when().config(restConfig).cookie("JSESSIONID", cookie).header("x-request-intercepted", "true")
.contentType(ContentType.JSON)
//.log().all()
.get(webgoatURL + "/WebGoat/HttpProxies/intercept-request?changeMe=Requests are tampered easily").then()
//.log().all()
.statusCode(200).extract().path("lessonCompleted"), is(true));
checkResults(cookie, webgoatURL, "/HttpProxies/");
}
public void chrome(String webgoatURL, String cookie) {
startLesson(cookie, webgoatURL, "ChromeDevTools");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("param1", "42");
params.put("param2", "24");
String result =
given()
.when()
.config(restConfig)
.cookie("JSESSIONID", cookie)
.header("webgoat-requested-by","dom-xss-vuln")
.header("X-Requested-With", "XMLHttpRequest")
.formParams(params)
.post(webgoatURL+"/WebGoat/CrossSiteScripting/phone-home-xss")
.then()
//.log().all()
.statusCode(200)
.extract().path("output");
String secretNumber = result.substring("phoneHome Response is ".length());
params.clear();
params.put("successMessage", secretNumber);
checkAssignment(cookie, webgoatURL+"/WebGoat/ChromeDevTools/dummy", params, true);
params.clear();
params.put("number", "24");
params.put("network_num", "24");
checkAssignment(cookie, webgoatURL+"/WebGoat/ChromeDevTools/network", params, true);
checkResults(cookie, webgoatURL, "/ChromeDevTools/");
}
}

View File

@ -1,48 +0,0 @@
package org.owasp.webgoat;
import java.util.HashMap;
import java.util.Map;
public class SqlInjectionAdvanced_TestHelper extends TestHelper {
public void runTests(String webgoatURL, String cookie) {
startLesson(cookie, webgoatURL, "SqlInjectionAdvanced");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("username_reg", "tom' AND substring(password,1,1)='t");
params.put("password_reg", "password");
params.put("email_reg", "someone@microsoft.com");
params.put("confirm_password", "password");
checkAssignmentWithPUT(cookie, webgoatURL+"/WebGoat/SqlInjectionAdvanced/challenge", params, true);
params.clear();
params.put("username_login", "tom");
params.put("password_login", "thisisasecretfortomonly");
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjectionAdvanced/challenge_Login", params, true);
params.clear();
params.put("userid_6a", "'; SELECT * FROM user_system_data;--");
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjectionAdvanced/attack6a", params, true);
params.clear();
params.put("userid_6a", "Smith' union select userid,user_name, user_name,user_name,password,cookie,userid from user_system_data --");
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjectionAdvanced/attack6a", params, true);
params.clear();
params.put("userid_6b", "passW0rD");
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjectionAdvanced/attack6b", params, true);
params.clear();
params.put("question_0_solution", "Solution 4: A statement has got values instead of a prepared statement");
params.put("question_1_solution", "Solution 3: ?");
params.put("question_2_solution", "Solution 2: Prepared statements are compiled once by the database management system waiting for input and are pre-compiled this way.");
params.put("question_3_solution", "Solution 3: Placeholders can prevent that the users input gets attached to the SQL query resulting in a seperation of code and data.");
params.put("question_4_solution", "Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjectionAdvanced/quiz", params, true);
checkResults(cookie, webgoatURL, "/SqlInjectionAdvanced/");
}
}

View File

@ -1,80 +0,0 @@
package org.owasp.webgoat;
import java.util.HashMap;
import java.util.Map;
public class SqlInjection_TestHelper extends TestHelper {
private static final String sql_2 = "select department from employees where last_name='Franco'";
private static final String sql_3 = "update employees set department='Sales' where last_name='Barnett'";
private static final String sql_4_drop = "alter table employees drop column phone";
private static final String sql_4_add = "alter table employees add column phone varchar(20)";
private static final String sql_5 = "grant alter table to UnauthorizedUser";
private static final String sql_9_account = " ' ";
private static final String sql_9_operator = "or";
private static final String sql_9_injection = "'1'='1";
private static final String sql_10_login_count = "2";
private static final String sql_10_userid = "1 or 1=1";
private static final String sql_11_a = "Smith' or '1' = '1";
private static final String sql_11_b = "3SL99A' or '1'='1";
private static final String sql_12_a = "Smith";
private static final String sql_12_b = "3SL99A' ; update employees set salary= '100000' where last_name='Smith";
private static final String sql_13 = "%update% '; drop table access_log ; --'";
public void runTests(String webgoatURL, String cookie) {
startLesson(cookie, webgoatURL, "SqlInjection");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("query", sql_2);
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjection/attack2", params, true);
params.clear();
params.put("query", sql_3);
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjection/attack3", params, true);
params.clear();
params.put("query", sql_4_drop);
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjection/attack4", params, false);
params.clear();
params.put("query", sql_4_add);
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjection/attack4", params, true);
params.clear();
params.put("query", sql_5);
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjection/attack5", params, true);
params.clear();
params.put("operator", sql_9_operator);
params.put("account", sql_9_account);
params.put("injection", sql_9_injection);
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjection/assignment5a", params, true);
params.clear();
params.put("login_count", sql_10_login_count);
params.put("userid", sql_10_userid);
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjection/assignment5b", params, true);
params.clear();
params.put("name", sql_11_a);
params.put("auth_tan", sql_11_b);
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjection/attack8", params, true);
params.clear();
params.put("name", sql_12_a);
params.put("auth_tan", sql_12_b);
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjection/attack9", params, true);
params.clear();
params.put("action_string", sql_13);
checkAssignment(cookie, webgoatURL+"/WebGoat/SqlInjection/attack10", params, true);
checkResults(cookie, webgoatURL, "/SqlInjection/");
}
}

View File

@ -1,118 +0,0 @@
package org.owasp.webgoat;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.everyItem;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.junit.Assert.assertThat;
import java.util.Map;
import io.restassured.config.RestAssuredConfig;
import io.restassured.config.SSLConfig;
public class TestHelper {
//This also allows to test the application with HTTPS when outside testing option is used
protected RestAssuredConfig restConfig = RestAssuredConfig.newConfig().sslConfig(new SSLConfig().relaxedHTTPSValidation());
/**
* At start of a lesson. The .lesson.lesson is visited and the lesson is reset.
* @param cookie
* @param url
* @param lessonName
*/
public void startLesson(String cookie, String url, String lessonName) {
given()
.when()
.config(restConfig)
.cookie("JSESSIONID", cookie)
.get(url+"/WebGoat/"+lessonName+".lesson.lesson")
.then()
.statusCode(200);
given()
.when()
.config(restConfig)
.cookie("JSESSIONID", cookie)
.get(url+"/WebGoat/service/restartlesson.mvc")
.then()
.statusCode(200);
}
/**
* Helper method for most common type of test.
* POST with parameters.
* Checks for 200 and lessonCompleted as indicated by expectedResult
* @param webgoatCookie
* @param url
* @param params
* @param expectedResult
*/
public void checkAssignment(String webgoatCookie, String url, Map<String, ?> params, boolean expectedResult) {
assertThat(
given()
.when()
.config(restConfig)
.cookie("JSESSIONID", webgoatCookie)
.formParams(params)
.post(url)
.then()
//.log().all()
.statusCode(200)
.extract().path("lessonCompleted"), is(expectedResult));
}
/**
* Helper method for most common type of test.
* PUT with parameters.
* Checks for 200 and lessonCompleted as indicated by expectedResult
* @param webgoatCookie
* @param url
* @param params
* @param expectedResult
*/
public void checkAssignmentWithPUT(String webgoatCookie, String url, Map<String, ?> params, boolean expectedResult) {
assertThat(
given()
.when()
.config(restConfig)
.cookie("JSESSIONID", webgoatCookie)
.formParams(params)
.put(url)
.then()
//.log().all()
.statusCode(200)
.extract().path("lessonCompleted"), is(expectedResult));
}
/**
* Helper method at the end of a lesson.
* Check if all path paramters are correct for the progress.
* Check if all are solved.
* @param webgoatCookie
* @param webgoatURL
* @param prefix
*/
public void checkResults(String webgoatCookie, String webgoatURL, String prefix) {
assertThat(given()
.when()
.config(restConfig)
.cookie("JSESSIONID", webgoatCookie)
.get(webgoatURL+"/WebGoat/service/lessonoverview.mvc")
.then()
//.log().all()
.statusCode(200).extract().jsonPath().getList("solved"),everyItem(is(true)));
assertThat(given()
.when()
.config(restConfig)
.cookie("JSESSIONID", webgoatCookie)
.get(webgoatURL+"/WebGoat/service/lessonoverview.mvc")
.then()
//.log().all()
.statusCode(200).extract().jsonPath().getList("assignment.path"),everyItem(startsWith(prefix)));
}
}

View File

@ -1,162 +0,0 @@
package org.owasp.webgoat;
import static io.restassured.RestAssured.given;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.embedded.LocalServerPort;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes=WebGoat.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@EnableAutoConfiguration
public class WebGoatIntegrationTest extends TestHelper {
/*
* Unique port for http server. Database port is not yet overruled. But this is
* not a problem for the integration test.
*/
@LocalServerPort
int randomServerPort;
private General_TestHelper generalTestHelper = new General_TestHelper();
private SqlInjection_TestHelper sqlInjectionHelper = new SqlInjection_TestHelper();
private SqlInjectionAdvanced_TestHelper sqlInjectionAdvancedHelper = new SqlInjectionAdvanced_TestHelper();
private SqlInjectionMitigation_TestHelper sqlInjectionMitigationHelper = new SqlInjectionMitigation_TestHelper();
String webgoatURL = System.getProperty("WEBGOAT_URL","");
String webgoatUser = System.getProperty("WEBGOAT_USER","");
String webgoatPassword = System.getProperty("WEBGOAT_PASSWORD","password");
String cookie = "";
@Before
public void init() {
/*
* If no system properties are set, the test runs against the random port
* of the webgoat application that starts with this test.
* If set you can use it to test an oustide running application. If testing
* against outside running applications, the tests that require WebWolf can be tested as well.
*/
//TODO add support for testing the lessons that require WebWolf as well.
if (webgoatURL.equals("")) {
webgoatURL = "http://127.0.0.1:"+randomServerPort;
}
/*
* If not defined a random user will be registered and used in the test.
* If you run against an outside application and want to visually see the results,
* you can set a username.
*/
if (webgoatUser.equals("")) {
webgoatUser = "tester"+Math.round(Math.random()*1000);
}
//check if user exists
String location = given()
.when()
.config(restConfig)
.formParam("username", webgoatUser)
.formParam("password", "password")
.post(webgoatURL+"/WebGoat/login")
.then()
//.log().all()
.cookie("JSESSIONID")
.statusCode(302)
.extract().header("Location");
//register when not existing, otherwise log in and save the cookie
if (location.endsWith("error")) {
cookie = given()
.when()
.config(restConfig)
.formParam("username", webgoatUser)
.formParam("password", "password")
.formParam("matchingPassword", "password")
.formParam("agree", "agree")
.post(webgoatURL+"/WebGoat/register.mvc")
.then()
.cookie("JSESSIONID")
.statusCode(302)
.extract()
.cookie("JSESSIONID");
} else {
cookie = given()
.when()
.config(restConfig)
.formParam("username", webgoatUser)
.formParam("password", "password")
.post(webgoatURL+"/WebGoat/login")
.then()
//.log().all()
.cookie("JSESSIONID")
.statusCode(302)
.extract().cookie("JSESSIONID");
}
}
@Test
public void testGeneral_HttpBasics() {
generalTestHelper.httpBasics(webgoatURL, cookie);
}
@Test
public void testGeneral_HttpProxies() {
generalTestHelper.httpProxies(webgoatURL, cookie);
}
@Test
public void testGeneral_CIA() {
generalTestHelper.cia(webgoatURL, cookie);
}
@Test
public void testGeneral_Chrome() {
generalTestHelper.chrome(webgoatURL, cookie);
}
@Test
public void testSecurePassords() {
generalTestHelper.securePasswords(webgoatURL, cookie);
}
@Test
public void testSQLInjection() {
sqlInjectionHelper.runTests(webgoatURL, cookie);
}
@Test
public void testSQLInjectionAdvanced() {
sqlInjectionAdvancedHelper.runTests(webgoatURL, cookie);
}
@Test
public void testSQLInjectionMitigation() {
sqlInjectionMitigationHelper.runTests(webgoatURL, cookie);
}
}

View File

@ -110,6 +110,22 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<phase>test-compile</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>internal</classifier>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>

View File

@ -1,29 +1,24 @@
package org.owasp.webwolf;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webwolf.requests.WebWolfTraceRepository;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import java.util.Map;
@SpringBootApplication
@Slf4j
public class WebWolf extends SpringBootServletInitializer {
public class WebWolf {
@Bean
public TraceRepository traceRepository() {
return new WebWolfTraceRepository();
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebWolf.class);
}
public static void main(String[] args) throws Exception {
public static void main(String[] args) {
System.setProperty("spring.config.name", "application-webwolf");
SpringApplication.run(WebWolf.class, args);
}
}

View File

@ -25,6 +25,7 @@ public class Email implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@JsonIgnore
private LocalDateTime time = LocalDateTime.now();
@Column(length = 1024)
private String contents;

View File

@ -42,7 +42,7 @@ public class Requests {
}
@GetMapping
public ModelAndView get(HttpServletRequest request) {
public ModelAndView get() {
ModelAndView m = new ModelAndView("requests");
List<Tracert> traces = traceRepository.findAllTraces().stream()
.map(t -> new Tracert(t.getTimestamp(), path(t), toJsonString(t))).collect(toList());

View File

@ -7,7 +7,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.trace.Trace;
import org.springframework.boot.actuate.trace.TraceRepository;
import java.util.*;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Keep track of all the incoming requests, we are only keeping track of request originating from
@ -20,7 +23,7 @@ import java.util.*;
public class WebWolfTraceRepository implements TraceRepository {
private final EvictingQueue<Trace> traces = EvictingQueue.create(10000);
private List<String> exclusionList = Lists.newArrayList("/WebWolf/home", "/WebWolf/mail","/WebWolf/files", "/images/", "/login", "/favicon.ico", "/js/", "/webjars/", "/WebWolf/requests", "/css/", "/mail");
private List<String> exclusionList = Lists.newArrayList("/WebWolf/home", "/WebWolf/mail", "/WebWolf/files", "/images/", "/login", "/favicon.ico", "/js/", "/webjars/", "/WebWolf/requests", "/css/", "/mail");
@Override
public List<Trace> findAll() {
@ -40,21 +43,9 @@ public class WebWolfTraceRepository implements TraceRepository {
@Override
public void add(Map<String, Object> map) {
Optional<String> host = getFromHeaders("host", map);
String path = (String) map.getOrDefault("path", "");
if (host.isPresent() && !isInExclusionList(path)) {
if (!isInExclusionList(path)) {
traces.add(new Trace(new Date(), map));
}
}
private Optional<String> getFromHeaders(String header, Map<String, Object> map) {
Map<String, Object> headers = (Map<String, Object>) map.get("headers");
if (headers != null) {
Map<String, Object> request = (Map<String, Object>) headers.get("request");
if (request != null) {
return Optional.ofNullable((String) request.get(header));
}
}
return Optional.empty();
}
}

View File

@ -15,7 +15,7 @@ import javax.validation.constraints.Size;
public class UserForm {
@NotNull
@Size(min=6, max=20)
@Size(min=6, max=40)
private String username;
@NotNull
@Size(min=6, max=10)

View File

@ -1,22 +0,0 @@
package org.owasp.webwolf.user;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import java.io.Serializable;
/**
* @author nbaars
* @since 8/20/17.
*/
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class WebGoatUserCookie implements Serializable {
@Id
private String username;
private String cookie;
}

View File

@ -10,6 +10,7 @@ spring.datasource.url=jdbc:hsqldb:hsql://${WEBGOAT_HOST:127.0.0.1}:${WEBGOAT_HSQ
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.messages.basename=i18n/messages
spring.jmx.enabled=false
logging.level.org.springframework=INFO
logging.level.org.springframework.boot.devtools=WARN