Java代码审计基础—反射(渗透测试)

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")
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thunderclap_

点赞、关注加收藏~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值