diff --git a/tools/aegis4j/build.gradle b/tools/aegis4j/build.gradle
index e4084b0261..e3242d73ca 100644
--- a/tools/aegis4j/build.gradle
+++ b/tools/aegis4j/build.gradle
@@ -37,6 +37,7 @@ dependencies {
testImplementation "io.netty:netty:3.10.5.Final"
testImplementation "com.h2database:h2:$h2_version"
testImplementation "javax.servlet:javax.servlet-api:${servlet_version}" // Needed to load H2 Web Console
+ testImplementation "org.liquibase:liquibase-core:$liquibase_version"
}
sourceCompatibility = 8
diff --git a/tools/aegis4j/src/main/java/net/gredler/aegis4j/Patcher.java b/tools/aegis4j/src/main/java/net/gredler/aegis4j/Patcher.java
index 64fd104443..a7fff21698 100644
--- a/tools/aegis4j/src/main/java/net/gredler/aegis4j/Patcher.java
+++ b/tools/aegis4j/src/main/java/net/gredler/aegis4j/Patcher.java
@@ -106,13 +106,18 @@ public final class Patcher implements ClassFileTransformer {
System.err.println("ERROR: Method not found: " + className + "." + mod.methodName);
}
for (CtMethod method : methods) {
- method.setBody(mod.newBody);
+ if (mod.newBody.startsWith("throw ")) {
+ method.setBody(mod.newBody);
+ } else {
+ method.insertBefore(mod.newBody);
+ }
}
}
}
}
return clazz.toBytecode();
} catch (NotFoundException | CannotCompileException | IOException e) {
+ e.printStackTrace();
return null;
}
}
diff --git a/tools/aegis4j/src/test/java/net/gredler/aegis4j/CVE_2022_0839.java b/tools/aegis4j/src/test/java/net/gredler/aegis4j/CVE_2022_0839.java
new file mode 100644
index 0000000000..8e8919db19
--- /dev/null
+++ b/tools/aegis4j/src/test/java/net/gredler/aegis4j/CVE_2022_0839.java
@@ -0,0 +1,95 @@
+/* Copyright (c) 2022, Daniel Gredler. All rights reserved. */
+
+package net.gredler.aegis4j;
+
+import liquibase.changelog.ChangeLogParameters;
+import liquibase.exception.ChangeLogParseException;
+import liquibase.parser.core.xml.XMLChangeLogSAXParser;
+import liquibase.resource.ResourceAccessor;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ConnectException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * Tests Liquibase patching.
+ */
+public class CVE_2022_0839 {
+ @AfterAll
+ public static void uninstallAgent() throws Exception {
+ System.clearProperty("aegis4j.additional.args");
+ }
+
+ @Test
+ public void test() throws Exception {
+ TestUtils.installAgent("path=" + System.getProperty("aegis4j.projectDir") + "/src/test/resources/liquibase-mods.properties");
+ try {
+ /*
+ String xmlpoc = "]>&xxe;";
+
+ SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
+ saxParserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ SAXParser saxParser = saxParserFactory.newSAXParser();
+ saxParser.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "http,https");
+ saxParser.parse(new ByteArrayInputStream(xmlpoc.getBytes()), new HandlerBase());
+ */
+
+ String changeLog = "\n" +
+ "]>\n" +
+ "\n" +
+ "\n" +
+ " \n" +
+ " &xxe;\n" +
+ " \n" +
+ "";
+
+
+ XMLChangeLogSAXParser parser = new XMLChangeLogSAXParser();
+ parser.parse("", new ChangeLogParameters(), new StringResourceAccessor("", changeLog));
+
+ } catch (ChangeLogParseException e) {
+ if (e.getCause() instanceof ConnectException) {
+ fail("Exception not expected", e);
+ }
+ }
+ }
+
+ static class StringResourceAccessor implements ResourceAccessor {
+ private String resource;
+ private String resourceContent;
+
+ public StringResourceAccessor(String resource, String resourceContent) {
+ this.resource = resource;
+ this.resourceContent = resourceContent;
+ }
+
+ @Override
+ public Set getResourcesAsStream(String path) throws IOException {
+ if (resource.equals(path)) {
+ return Collections.singleton(new ByteArrayInputStream(resourceContent.getBytes(StandardCharsets.UTF_8)));
+ } else {
+ return Collections.singleton(this.getClass().getResource(path).openStream());
+ }
+ }
+
+ @Override
+ public Set list(String relativeTo, String path, boolean includeFiles, boolean includeDirectories, boolean recursive) throws IOException {
+ return null;
+ }
+
+ @Override
+ public ClassLoader toClassLoader() {
+ return null;
+ }
+ }
+}
diff --git a/tools/aegis4j/src/test/resources/liquibase-mods.properties b/tools/aegis4j/src/test/resources/liquibase-mods.properties
new file mode 100644
index 0000000000..69d39476a7
--- /dev/null
+++ b/tools/aegis4j/src/test/resources/liquibase-mods.properties
@@ -0,0 +1,4 @@
+# format: ..=
+# CVE-2022-0839
+LIQUIBASE.liquibase.parser.core.xml.XMLChangeLogSAXParser.parseToNode=saxParserFactory.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
+LIQUIBASE.liquibase.parser.core.xml.XMLChangeLogSAXParser.trySetSchemaLanguageProperty=parser.setProperty(javax.xml.XMLConstants.ACCESS_EXTERNAL_SCHEMA, "http,https");
diff --git a/tools/cliutils/src/main/resources/mods.properties b/tools/cliutils/src/main/resources/mods.properties
index c9f1e19983..b880c228f3 100644
--- a/tools/cliutils/src/main/resources/mods.properties
+++ b/tools/cliutils/src/main/resources/mods.properties
@@ -69,4 +69,5 @@ H2.org.h2.server.web.WebServlet.WebServlet=throw new java.lang.RuntimeException(
# CVE-2021-23463
H2.org.h2.jdbc.JdbcSQLXML.getSource=throw new java.lang.RuntimeException("H2 SQL XML blocked by aegis4j");
# CVE-2022-0839
-#LIQUIBASE.liquibase.parser.core.xml.XMLChangeLogSAXParser.parseToNode=saxParserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
\ No newline at end of file
+LIQUIBASE.liquibase.parser.core.xml.XMLChangeLogSAXParser.parseToNode=saxParserFactory.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
+LIQUIBASE.liquibase.parser.core.xml.XMLChangeLogSAXParser.trySetSchemaLanguageProperty=parser.setProperty(javax.xml.XMLConstants.ACCESS_EXTERNAL_SCHEMA, "http,https");