一、java安全 —— 反射
文章是本人java安全漫谈系列文章学习过程的记录,希望通过写博客督促自己学习,如有错误希望各位大佬指正。
1、反射机制浅析
java反射机制是很多java漏洞的基础,尤其在反序列化中,反射十分重要,首先来了解一下反射是什么?
反射在很多语言中都存在,反射使对象能获取他的类,类可以通过反射获取方法,而获取方法后可以进行调用,在java中,反射可以赋予语言动态特性。动态特性是指相对于编译时将已编写代码进行生成对象,获取属性以及调用方法等操作,在程序运行时,根据反射的相关性质动态生成对象,获取属性以及调用方法等。
首先让我们看看反射的基础用法
public void execute(String className, String methodName) throws Exception {
Class clazz = Class.forName(className);
clazz.getMethod(methodName).invoke(clazz.newInstance());
}
这里涉及了反射过程中的一些重要方法:
forName
:获取类getMethod
:获取类的方法invoke
:调用方法newInstance
:实例化对象
简单描述上述反射过程,forName
通过className(类名)
获取到一个特定类clazz
,接下来Clazz
中的getMethod
方法通过methodName(方法名)
获取需要执行的方法,最后通过newInstance
方法对clazz进行实例化并通过invoke方法执行。
编写一个反射的方法类
public class invoke_exec {
public void execute1(String className, String methodName) throws Exception {
Class clazz = Class.forName(className);
clazz.getMethod(methodName).invoke(clazz.newInstance());
}
}
编写一个测试类
public class invokeTest {
public void print() {
System.out.println("反射成功");
}
}
使用反射调用print方法
public class start {
public static void main(String[] args) throws Exception {
invoke_exec invokeTest = new invoke_exec();
invokeTest.execute1("invokeTest", "print");
}
}
2、forName方法分析
forName
是获取class
对象的一种方法,通过传入string类型参数,通过jvm查找和加载指定类,返回一个class
对象的引用,此时对象没有被实例化。在反射中还需要通过其他方法实例化对象才能调用其中方法,如newInstance
。
forName有两种重载
Class<?> forName(String className)
Class<?> forName(String name, boolean initialize, ClassLoader loader)
分析源码发现forName方法都会返回forName0,而第一种重载中,initialize=true
,loader
是当前类的类加载器,在java中默认的ClassLoader通过类名加载类(类的完整路径)。
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
这里提一下initialize
初始化的问题,这里的初始化是指forName方法的静态初始化,并不会执行指定类的构造函数进行初始化,而是执行static代码块。这意味着恶意代码执行不需要通过invoke方法,仅仅通过forName方法对类进行静态初始化即可执行恶意代码。
这里可以编写恶意类,在static代码块中写入恶意代码
public class hack {
static {
try {
Runtime rt = Runtime.getRuntime();
String commands = "calc.exe";
Process p = rt.exec(commands);
p.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
public void print() {
System.out.println("反射成功");
}
}
用一个简单的方法进行验证
通过反射方法类获取hack类
public class start {
public static void main(String[] args) throws Exception {
invoke_exec invokeTest = new invoke_exec();
invokeTest.execute1("hack", "print");
}
}
接下来会继续更新
标签:反射,forName,java,String,invoke,安全,方法,public From: https://www.cnblogs.com/p1a0m1a0/p/17065681.html