Aprendizaje de seguridad de Javaweb: reflejo de Java

Mecanismo de reflexión de Java

La reflexión de Java ( Reflection) es una característica dinámica muy importante de Java. Mediante el uso de la reflexión, no solo podemos obtener información como métodos de miembros ( Methods), variables de miembros ( Fields) y constructores ( ) de cualquier clase Constructors, sino también crear dinámicamente instancias de clases de Java y llame a cualquier método de clase, modifique valores de variables de miembros de clase arbitrarios, etc. El mecanismo de reflexión de Java es una encarnación importante de la naturaleza dinámica del lenguaje Java , y también es el alma de la implementación subyacente de varios marcos Java.

Obtener objeto de clase

La reflexión de Java opera en los java.lang.Classobjetos, por lo que primero debemos encontrar una manera de obtener el objeto Clase. Por lo general, tenemos las siguientes formas de obtener el objeto Clase de una clase:

  1. Class.forName("ClassName");
  2. ClassLoader.loadClass("ClassName");//En el uso real, debe especificar un cargador específico, como ClassLoader.getSystemClassLoader(), y luego llamarloadClass方法
  3. ClassName.class;// la clase ha sido cargada, solo obtén su java.lang.Classobjeto
  4. obj.getClass();//Disponible cuando hay una instancia obj de una clase en el contexto

Class.forName(String)Es la forma más utilizada para obtener Class, forname()existen dos métodos sobrecargados:

  • public static Class<?> forName(String className)
    
  • public static Class<?> forName(String name,
                   boolean initialize,
                   ClassLoader loader)
    

El primer método puede entenderse como un paquete del segundo método, y llamar a este método es equivalente al segundo método.

Class.forName("Foo")

es equivalente a:

Class.forName("Foo", true, this.getClass().getClassLoader())

Vale la pena señalar que el segundo y tercer parámetro del segundo método, el segundo parámetro indica si se debe inicializar, y el tercer parámetro es ClassLoader(mencionado en el contenido de la sección anterior).

El segundo parámetro initialize se refiere a la 初始化inicialización de la clase.En el ejemplo de la sección anterior, Class.forname()también se menciona que el bloque de declaraciones se llama en el 类初始化momento static{}(escribir una clase maliciosa, poner el código malicioso en el bloque de declaraciones estáticas para cargar it), p El ejemplo dado por Dios en Java Security Talk muestra la diferencia entre los tres métodos de "inicialización" y el orden en que se llaman.

inserte la descripción de la imagen aquí

Otro método ClassLoader.loadClass(String)también tiene una sobrecarga de métodos como la anterior

Class<?> loadClass(String name)   //调用此方法等效于调用loadClass(name, false)
Class<?> loadClass(String name,
                 boolean resolve)

El primero ( Class.forName();) será:

  • Use el cargador de clases que carga la clase que llama a este código
  • Inicialice la clase (es decir, se ejecutarán todos los inicializadores estáticos)

Otro ( ClassLoader.getSystemClassLoader().loadClass();) hará:

  • Utilice el cargador de clases "sistema" ( reemplazable )
  • la clase no está inicializada

Ejemplo: obtener el fragmento de código de objeto de clase de clase de tiempo de ejecución:

String className     = "java.lang.Runtime";
Class  runtimeClass1 = Class.forName(className);
Class  runtimeClass2 = ClassLoader.getSystemClassLoader().loadClass(className);
Class  runtimeClass3 = java.lang.Runtime.class;

obtener clase interna

$Debe usarse en su lugar al llamar a clases internas por reflexión ., por ejemplo Common$Inner, al Class.forname("Common$Inner");cargar

class Common {
    
    
    static {
    
    
        System.out.printf("CommonClass: %s\n", Common.class);
    }
    class Inner{
    
    
        Inner(){
    
    
            System.out.printf("InnerClass: %s\n", Inner.class);}}}

Cuando se compile, serán dos archivos Common$Inner.classy Common.classcomo dos clases.

El presagio ha terminado, vayamos al punto a continuación.

Generar y manipular objetos usando la reflexión.

El objeto Class puede obtener:

  • método ( Method对象representado por), Method对象ejecutando el método;
  • el constructor ( Constructor对象representado por ), por Constructor对象el cual se llama al constructor;
  • valor de la variable miembro ( Field对象representado por), Field对象accediendo directamente y modificando el valor de la variable miembro del objeto;

Crear objeto (instancia de clase)

Debe usar el método Class对象para obtener el especificado 构造方法(Constructor对象)y luego llamar al método del objeto Constructor newInstance()(la función es llamar al constructor sin parámetros obtenido) para crear una instancia de la clase correspondiente del objeto Class.

En general, hay dos formas de obtener el constructor en la clase Clase:

getConstructor*()método, sólo se pueden obtener métodos públicos.

* Constructor<?>[] getConstructors()
* Constructor<T> getConstructor(<?>... parameterTypes)

getDeclaredConstructor*()para obtener el constructor privado de la clase (incluidos los constructores con otros modificadores), debe establecerse setAccessible()en verdadero.

* Constructor<?>[] getDeclaredConstructors()
* Constructor<T> getDeclaredConstructor(<?>... parameterTypes)

método de llamada

Después de obtener una instancia de una clase (objeto Class), el método se obtiene a través del getMethod*()OR getDeclaredMethod*()del objeto Class.

getMethod*()method para obtener todos los métodos públicos de la clase, incluido él mismo, todos los métodos públicos heredados de las clases base y todos los métodos públicos implementados desde las interfaces.

Method[] getMethods()  //全部方法 返回Method对象
Method getMethod(String name,<?>... parameterTypes)   //指定方法 返回Method数组

getDeclaredMethod*()método, puede obtener todos los métodos declarados por la propia clase, incluidos los métodos públicos, protegidos y privados.

 Method[] getDeclaredMethods()
 Method getDeclaredMethod(String name,<?>... parameterTypes)

Luego, después de obtener el objeto Método, invoke()se puede llamar a su método correspondiente a través del método del objeto Método.

Object invoke(Object obj, Object... args) 
    obj - 被调用方法的类实例对象(静态方法则为类)
	args - 用于方法调用的参数类型列表(Java存在方法重载,以此确定要调用的方法)

Al llamar al método privado de un objeto, Methon.setAccessible(true)primero debe usar las restricciones establecidas para ignorar los derechos de acceso.

llamada variable miembro

Las variables miembro especificadas contenidas en la clase se pueden obtener a través del método getField*()o del objeto Clase .getDeclaredField*()

getField*()Solo se puede acceder a las variables decoradas públicamente.

Field[] getFields() //全部变量
Field getField(String name)  //指定变量

getDeclaredField*()Puede acceder libremente a todas las variables miembro del objeto especificado, incluidas las variables miembro privadas.

Field[] getDeclaredFields()
Field getDeclaredField(String name)

Obtenga el valor de la variable miembro:

Object obj = field.get(类实例对象);

Modificar el valor de la variable miembro:

field.set(类实例对象, 修改后的值);

Al manipular variables privadas, field.setAccessible(true)puede ignorar las restricciones de acceso a las variables miembro.

Para modificar una variable miembro modificada por finaluna palabra clave, primero debe modificar el método set.

// 反射获取Field类的modifiers
Field modifiers = field.getClass().getDeclaredField("modifiers");

// 设置modifiers修改权限
modifiers.setAccessible(true);

// 修改成员变量的Field对象的modifiers值
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);

// 修改成员变量值
field.set(类实例对象, 修改后的值);

Las tres partes anteriores mencionaron llamar a un setAccessible()método para resolver el problema de permisos del modificador. El método no pertenece a una de las tres categorías, pero setAccessible()pertenece a la clase principal de los objetos Field, Method y Constructor AccessibleObject. Proporciona la capacidad de marcar un objeto que suprime las comprobaciones de control de acceso del lenguaje Java predeterminado cuando se utiliza un objeto reflexivo, su propiedad de anulación se establece de forma predeterminada en falso y el setAccessible()método invocable cambia. Entonces Field, Method, Constructor pueden llamar a este método.

Ejemplo: reflejo de la ejecución del comando java.lang.Runtime

// 获取Runtime类对象
Class runtimeClazz = Class.forName("java.lang.Runtime");

// 获取Runtime类的无参构造方法(该方法为私有方法)
Constructor constructor = runtimeClazz.getDeclaredConstructor();
//修改方法的访问权限(constructor.setAccessible(true))
constructor.setAccessible(true);

// 创建Runtime类实例,等价于 Runtime rt = new Runtime();
Object runtimeInstance = constructor.newInstance();

// 获取Runtime的exec(String cmd)方法
Method runtimeMethod = runtimeClazz.getMethod("exec", String.class);

// 调用exec方法,等价于 rt.exec(cmd);
runtimeMethod.invoke(runtimeInstance, "calc.exe");

Runtime es la clase más utilizada cuando se escriben comandos para ejecutar cargas útiles, y la clase Runtime está en modo singleton.inserte la descripción de la imagen aquí

El constructor es privado, pero se proporciona un método estático getRuntime()para obtener el objeto Runtime, por lo que también puede usar la siguiente carga útil

Class clazz = Class.forName("java.lang.Runtime");
Method execMethod = clazz.getMethod("exec", String.class);
Method getRuntimeMethod = clazz.getMethod("getRuntime");
Object runtime = getRuntimeMethod.invoke(clazz);
execMethod.invoke(runtime, "calc.exe");

Resumen del mecanismo de reflexión de Java

El mecanismo de reflexión de Java es la manifestación más importante de la dinámica de Java. Usando el mecanismo de reflexión, podemos realizar fácilmente la llamada dinámica de las clases de Java. La mayoría de los marcos de Java se implementan utilizando mecanismos de reflexión (como: Spring MVC, ORM框架etc.), y la reflexión de Java juega un papel crucial en la escritura de códigos de explotación, la auditoría de códigos y eludir las restricciones del método RASP.
thod.invoke(clazz);
execMethod.invoke(tiempo de ejecución, "calc.exe");


## Java反射机制总结

Java反射机制是Java动态性中最为重要的体现,利用反射机制我们可以轻松的实现Java类的动态调用。Java的大部分框架都是采用了反射机制来实现的(如:`Spring MVC`、`ORM框架`等),Java反射在编写漏洞利用代码、代码审计、绕过RASP方法限制等中起到了至关重要的作用。

Supongo que te gusta

Origin blog.csdn.net/weixin_43610673/article/details/123894582
Recomendado
Clasificación