diff --git a/test-17 b/test-17 new file mode 100644 index 0000000000..54231e8935 --- /dev/null +++ b/test-17 @@ -0,0 +1,286 @@ +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.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.SneakyThrows; +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.owasp.webgoat.container.lessons.Assignment; + +public class CSRFIntegrationTest extends IntegrationTest { + + private static final String trickHTML3 = + "
\n" + + "\n" + + "\n" + + "
"; + + private static final String trickHTML4 = + "
\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "
\n" + + ""; + + private static final String trickHTML7 = + "
\n" + + "\n" + + "\n" + + "
"; + + private static final String trickHTML8 = + "
\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "
"; + + private String webwolfFileDir; + + @BeforeEach + @SneakyThrows + public void init() { + startLesson("CSRF"); + webwolfFileDir = getWebWolfFileServerLocation(); + uploadTrickHtml("csrf3.html", trickHTML3.replace("WEBGOATURL", url("csrf/basic-get-flag"))); + uploadTrickHtml("csrf4.html", trickHTML4.replace("WEBGOATURL", url("csrf/review"))); + uploadTrickHtml("csrf7.html", trickHTML7.replace("WEBGOATURL", url("csrf/feedback/message"))); + uploadTrickHtml( + "csrf8.html", + trickHTML8.replace("WEBGOATURL", url("login")).replace("USERNAME", this.getUser())); + } + + @TestFactory + Iterable testCSRFLesson() { + return Arrays.asList( + dynamicTest("assignment 3", () -> checkAssignment3(callTrickHtml("csrf3.html"))), + dynamicTest("assignment 4", () -> checkAssignment4(callTrickHtml("csrf4.html"))), + dynamicTest("assignment 7", () -> checkAssignment7(callTrickHtml("csrf7.html"))), + dynamicTest("assignment 8", () -> checkAssignment8(callTrickHtml("csrf8.html")))); + } + + @AfterEach + public void shutdown() throws IOException { + // logout(); + login(); // because old cookie got replaced and invalidated + startLesson("CSRF", false); + checkResults("/csrf"); + } + + private void uploadTrickHtml(String htmlName, String htmlContent) throws IOException { + + // remove any left over html + Path webWolfFilePath = Paths.get(webwolfFileDir); + if (webWolfFilePath.resolve(Paths.get(this.getUser(), htmlName)).toFile().exists()) { + Files.delete(webWolfFilePath.resolve(Paths.get(this.getUser(), htmlName))); + } + + // upload trick html + RestAssured.given() + .when() + .relaxedHTTPSValidation() + .cookie("WEBWOLFSESSION", getWebWolfCookie()) + .multiPart("file", htmlName, htmlContent.getBytes()) + .post(webWolfUrl("fileupload")) + .then() + .extract() + .response() + .getBody() + .asString(); + } + + private String callTrickHtml(String htmlName) { + String result = + RestAssured.given() + .when() + .relaxedHTTPSValidation() + .cookie("JSESSIONID", getWebGoatCookie()) + .cookie("WEBWOLFSESSION", getWebWolfCookie()) + .get(webWolfUrl("files/" + this.getUser() + "/" + htmlName)) + .then() + .extract() + .response() + .getBody() + .asString(); + result = result.substring(8 + result.indexOf("action=\"")); + result = result.substring(0, result.indexOf("\"")); + + return result; + } + + private void checkAssignment3(String goatURL) { + String flag = + RestAssured.given() + .when() + .relaxedHTTPSValidation() + .cookie("JSESSIONID", getWebGoatCookie()) + .header("Referer", webWolfUrl("files/fake.html")) + .post(goatURL) + .then() + .extract() + .path("flag") + .toString(); + + Map params = new HashMap<>(); + params.clear(); + params.put("confirmFlagVal", flag); + checkAssignment(url("csrf/confirm-flag-1"), params, true); + } + + private void checkAssignment4(String goatURL) { + + Map params = new HashMap<>(); + params.clear(); + params.put("reviewText", "test review"); + params.put("stars", "5"); + params.put( + "validateReq", "2aa14227b9a13d0bede0388a7fba9aa9"); // always the same token is the weakness + + boolean result = + RestAssured.given() + .when() + .relaxedHTTPSValidation() + .cookie("JSESSIONID", getWebGoatCookie()) + .header("Referer", webWolfUrl("files/fake.html")) + .formParams(params) + .post(goatURL) + .then() + .extract() + .path("lessonCompleted"); + assertEquals(true, result); + } + + private void checkAssignment7(String goatURL) { + Map params = new HashMap<>(); + params.put( + "{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is the" + + " best!!", + "\"}"); + + String flag = + RestAssured.given() + .when() + .relaxedHTTPSValidation() + .cookie("JSESSIONID", getWebGoatCookie()) + .header("Referer", webWolfUrl("files/fake.html")) + .contentType(ContentType.TEXT) + .body( + "{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is" + + " the best!!=\"}") + .post(goatURL) + .then() + .extract() + .asString(); + flag = flag.substring(9 + flag.indexOf("flag is:")); + flag = flag.substring(0, flag.indexOf("\"")); + + params.clear(); + params.put("confirmFlagVal", flag); + checkAssignment(url("csrf/feedback"), params, true); + } + + private void checkAssignment8(String goatURL) { + + // first make sure there is an attack csrf- user + registerCSRFUser(); + + Map params = new HashMap<>(); + params.clear(); + params.put("username", "csrf-" + this.getUser()); + params.put("password", "password"); + + // login and get the new cookie + String newCookie = + RestAssured.given() + .when() + .relaxedHTTPSValidation() + .cookie("JSESSIONID", getWebGoatCookie()) + .header("Referer", webWolfUrl("files/fake.html")) + .params(params) + .post(goatURL) + .then() + .extract() + .cookie("JSESSIONID"); + + // select the lesson + RestAssured.given() + .when() + .relaxedHTTPSValidation() + .cookie("JSESSIONID", newCookie) + .get(url("CSRF.lesson.lesson")) + .then() + .statusCode(200); + + // click on the assignment + boolean result = + RestAssured.given() + .when() + .relaxedHTTPSValidation() + .cookie("JSESSIONID", newCookie) + .post(url("csrf/login")) + .then() + .statusCode(200) + .extract() + .path("lessonCompleted"); + + assertThat(result).isTrue(); + + login(); + startLesson("CSRF", false); + + Overview[] assignments = + RestAssured.given() + .cookie("JSESSIONID", getWebGoatCookie()) + .relaxedHTTPSValidation() + .get(url("service/lessonoverview.mvc")) + .then() + .extract() + .jsonPath() + .getObject("$", Overview[].class); + // assertThat(assignments) + // .filteredOn(a -> a.getAssignment().getName().equals("CSRFLogin")) + // .extracting(o -> o.solved) + // .containsExactly(true); + } + + @Data + private static class Overview { + Assignment assignment; + boolean solved; + } + + /** Try to register the new user. Ignore the result. */ + private void registerCSRFUser() { + + RestAssured.given() + .when() + .relaxedHTTPSValidation() + .formParam("username", "csrf-" + this.getUser()) + .formParam("password", "password") + .formParam("matchingPassword", "password") + .formParam("agree", "agree") + .post(url("register.mvc")); + } +}