ToDo-Java安全漫谈

java安全漫谈github(方便获取demo代码)

java反序列化深入剖析与实战

jdbc攻击(java数据库连接攻击)

01 反射(1)

反射:运行时才知道要操作的类具体是什么:程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法

Java安全:反序列化漏洞——可以从反射开始说起

反射是⼤多数语⾔⾥都必不可少的组成部分

对象通过反射——获取他的类——类通过反射拿到所有⽅法(包括私有)——拿到的⽅法可以调⽤

通过“反射”,可以将Java这种静态语⾔附加上动态特性

“动态特性”——⼀段代码,改变其中的变量,将会导致这段代码产⽣功能性的变化

⽐如:⼀段代码,在你不知道传⼊的参数值的时候,你是不知道他的作⽤是什么的

1java.lang.class

  • java.lang.class 是一个重要的类,是 java 反射机制的核心,其允许
    • 运行时动态获取类信息
    • 具体包括:
      • 类名、字段(成员变量)、类方法、类构造方法、父类、接口

1.1 常用方法

  • 类的对象:是 Java 的反射机制中,用来表示类的元数据(即关于类的结构、字段、方法等信息)的对象
    • 每个类都有一个与之关联的Class 对象,包含了类的信息,如类的名称、方法、字段、构造函数等
  • 类的实例: 是类的具体对象,是类的一个实例化对象(通过调用构造函数创建)
    • 实例拥有类的属性和方法,可以执行类定义的行为

在反射中,clazz 是一个 Class 类型的对象,它代表了一个类的信息。你可以通过 Class 对象来获取类的方法、字段、构造函数等。

1
2
3
4
public void execute(String className, String methodName) throws Exception {
Class clazz = Class.forName(className);
clazz.getMethod(methodName).invoke(clazz.newInstance());
}
  • Class.forName("com.example.Hello");:根据类的完全限定名(包括包名)加载类

    • 如果不存在会抛异常
  • clazz.getMethod(methodName):获取类的指定公有方法(只接受方法名,不能携带参数)

    • 目的是:运行时动态获取类的方法、方便后续的执行(invoke)
    • getMethod 可以获取类的 Method 对象,然后可以用 invoke 调用它
    • 如果不指定方法名会返回一个方法数组:该类的所有公用方法
      • Method[] methods = clazz.getMethods();
    • clazz.getDeclaredMethod(String name, Class<?>... parameterTypes):可以携带参数
      • 可以获取私有方法
  • clazz.newInstance():使用反射创建一个新的类实例=调用类的无参构造方法

  • .invoke(obj,para)是 Method 对象的一个方法,参数是方法调用需要的目标对象&调用方法的参数

    • obj:调用哪个对象的该方法
    • para:传入的参数数组,可为 null
  • 总结:

    • clazz.getMethod(methodName)通过反射获取了 clazz 类中名为methodName公用方法——得到一个 Method 对象
    • clazz.newInstance():通过反射创建类 clazz 的一个新的实例=调用类的无参构造方法,创建该类的一个对象。
    • invoke(clazz.newInstance()):调用 Method 对象,其是一个名为 methodName的方法。invoke 方法会执行 clazz 类的 methodName 方法,并且在这个方法上使用 clazz.newInstance() 创建的实例作为目标对象。

1.2 获取类对象的方法

  • obj.getClass():通过一个实例获取其类对象
    • 动态获取
    • 场景: 有一个对象,并且想知道这个对象是什么类型
  • <font style="color:rgb(51,51,51);">Test.class()</font> 如果你已经加载了某个类,只是想获取到它的 java.lang.Class 对象
    • 那么就直接拿它的 class 属性即可。这个⽅法其实不属于反射(效率很高,编译时就知道)
    • 场景: 这种方式适用于你已经知道某个类的名字,并且在编译时就能确定
  • <font style="color:rgb(51,51,51);">Class.forName()</font> 如果你知道某个类的名字,想获取到这个类,就可以使⽤ forName 来获取
    • 通过完全限定名动态获取
    • 场景:当你在运行时才知道类的名称,或者类名是动态提供的

3 沙盒绕过 ctf 例题

Code-Breaking2018沙盒绕过

4forName 重载

使用 forName()会自动初始化该 Class 对象

  • forName有两个函数重载:

    • Class<?> forName(String name)
      • 第⼀个就是常⻅获取class的⽅式,可以理解为第⼆种⽅式的封装
      • 等价于:
      • Class.forName(name, true, Thread.currentThread().getContextClassLoader());
    • Class<?> forName(String name, **boolean** initialize, ClassLoader loader)
      • 第⼀个参数是类名;第⼆个参数表示是否初始化;第三个参数就是 ClassLoader
      • ClassLoader就是⼀个“加载器”,告诉Java虚拟机如何加载这个类
      • Java默认的 ClassLoader 就是根据类名来加载类(类名需要是完整路径)
  • 加载和初始化

    • 加载:把类的.class 文件加载到 JVM 内容,Class 对象已被创建
    • 初始化:执行类的静态代码块,和静态变量(在类加载时执行,且只执行一次)
    • 加载但不初始化好处:
      • 1 反射:用 ClassLoader 加载类,获取其元信息、无需执行其静态代码块。
        • eg:加载一个工具类,只需要调用方法,但不需要执行其静态代码
      • 2 性能优化、延迟加载、避免静态代码被执行…

forName 与 .class