4.2 反射
一、反射
Java 反射机制可以无视类方法、变量访问权限修饰符,可以调用任何类的任意方法、访问并修改成员变量值。也就是说只要发现一处 Java 反射调用漏洞几乎就可以为所欲为了。当然前提可能需要你能控制反射的类名、方法名和参数。
1.获取class类的几种方式
- 1. class.forName(“全类名”),如果你知道某个类的名字,想获取到这个类,就可以使⽤用forName 来获取
- 2. 类名.class,如果你已经加载了某个类,只是想获取到它的java.lang.Class 对象,那么就直接拿它的class 属性即可。这个方法其实不属于反射。
- 3. 对象.getClass(),如果上下文存在某个实例对象,可以通过getClass获取他的类
- 4.ClassLoader.getSystemClassLoader().loadClass(“全类名”)
forName有两个函数重载:
Class<?> forName(String name)
Class<?> forName(String name, boolean initialize, ClassLoader loader)
- 第一个就是我们最常见的获取class的方式,其实可以理解为第二种方式的一个封装:
Class.forName(className)
// 等于
Class.forName(className, true, currentLoader)
默认情况下, forName 的第一个参数是类名;第二个参数表示是否初始化;第三个参数就是ClassLoader。
- 使用功能 “.class” 来创建Class对象的引用时,不会自动初始化该Class对象,使用forName()会自动初始化该Class对象
- static {} 就是在“类初始化”的时候调用的,而{} 中的代码会放在构造函数的super()后面,但在当前构造函数内容的前面。
- forName 中的initialize=true 其实就是告诉Java虚拟机是否执行”类初始化“。
2.获取类之后的方法
- 实例化类对象的方法: newInstance
- 获取函数的方法: getMethod
- 执行函数的方法: invoke
3.类“初始化”执行顺序是什么
public class test {
public static void main(String[] args) {
Ref ref = new Ref();
}
}
class Ref{
static {
System.out.println("最先执行\r\n");
}
{
System.out.println("第二执行\r\n");
}
public Ref(){
System.out.println("最后执行\r\n");
}
}
其中, static {} 就是在“类初始化”的时候调⽤用的,而{} 中的代码会放在构造函数的super() 后面,但在当前构造函数内容的前面。
4.class.newInstance()
作用就是调用这个类的无参构造函数,我们有时候在写漏洞利用方法的时候,会发现使用newInstance 总是不成功,这时候原因可能是:
- 1. 你使用的类没有无参构造函数
- 2. 你使用的类构造函数是私有的
最常见的情况就是java.lang.Runtime,不能直接newInstance(),原因是Runtime 类的构造方法是私有的。因为Runtime类是单例模式,我们只能通过Runtime.getRuntime() 来获取到Runtime 对象,所以正常的payload如下:
Class clazz = Class.forName("java.lang.Runtime");
clazz.getMethod("exec",
String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz),
"calc.exe");
5.getMethod()
通过反射获取一个类的某个特定的公有方法,因为java中类的重载,我们不能只通过一个方法名来确定一个函数,在调用getMethod 的时候,我们需要
传给他你需要获取的函数的参数类型列表。
比如的Runtime.exec 方法有6个重载:

6.invoke()
invoke的作用是执行方法,它的第一个参数是:
- 如果这个方法是一个普通方法,那么第一个参数是类对象
- 如果这个方法是一个静态方法,那么第一个参数是类
这也比较好理解了,我们正常执行方法是[1].method([2], [3], [4]…) ,其实在反射里就是method.invoke([1], [2], [3], [4]…)
所以上面的exec的代码拆分开即如下代码。
Class clazz = Class.forName("java.lang.Runtime");
Method exec = clazz.getMethod("exec", String.class);
Method getRuntime = clazz.getMethod("getRuntime");
Object invoke = getRuntime.invoke(clazz); //这里的clazz就是我们第一步反射回来的 类
exec.invoke(invoke,"calc"); //这里的invoke就是上面通过clazz类创建出来的 类对象
7.class类的其他方法
- 如果一个类没有无参构造方法,也没有类似单例模式里的静态方法,那么我们可以通过getConstructor()指定需要确定的构造函数。
- 如果一个方法或构造方法是私有方法,我们可以通过getDeclaredMethod 系列方法获取的是当前类中**“声明”**的方法,是实在写在这个类里的,包括私有的方法,但从父类里继承来的就不包含了
获取构造方法
cls3.getConstructor("aaa")

最低0.47元/天 解锁文章
315

被折叠的 条评论
为什么被折叠?



