从安全角度谈Java反射机制--序章


前言

首发:https://www.sec-in.com/article/307
   众所周知,Java目前影响最大的是反序列化漏洞,换一句话说Java安全是从反序列化漏洞开始,但反序列化漏洞又可以基于反射,这次笔者带你走进Java安全的大门。
   Java反序列化的payload大多与反射机制密切相关,但仅仅是因为这个吗?答案肯定是片面的。反射作为大多数编程语言里必不可缺的组成部分,对象可以通过反射获取其他的类,类可以通过反射拿到所有的方法(包括私有方法),获取到方法可以调用。一句话,反射给Java等类似的静态语言赋予了“灵魂”

ps: 本文实验代码都上传JavaLearnVulnerability项目,为了让更多人知道,麻烦动动小手star一下。


反射基础

   Java反射操作的对象是java.lang.Class对象,如果想要使用Java反射,首先得获取Class对象。下面我们看一段代码。

1
2
3
4
public static void main(String[] args) throws Exception {
Class cls = Class.forName(className);
cls.getMethod(methodName).invoke(cls.newInstance());
}

示例代码中,笔者演示几个比较重要的方法:

  • 获取类对象的方法forName
  • 从获取类对象中获取方法 getMethod
  • 执行得到获取的方法的方法invoke
  • 实例化对象newInstance

ps:当然反射不可能仅仅只是这些方法,下面中笔者有提及其他的方法,当然不可能是全部都一一道来,正所谓授之与鱼,不如授之于渔。更多方法建议大家去看JDK文档,在线的文档百度一搜就有。


类源码

   首先笔者构造了两个类studentsclassdemo1


实体类students源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Students {
private Integer age = 18;
private String name = "samny";
private Integer CardId = 332323223;
private Integer id = 10012;
private String hello = "hello world";


public Students(Integer age, String name, Integer cardId, Integer id, String hello) {
this.age = age;
this.name = name;
this.CardId = cardId;
this.id = id;
this.hello = hello;

}


@Override
public String toString() {
return "Students{" +
"age=" + age +
", name='" + name + '\'' +
", CardId=" + CardId +
", id=" + id +
", ags='" + hello + '\'' +
'}';
}

public Students() {

}

public Integer getAge() {
return age;
}
// 以下省略set,get以及toString方法。

}

实体类classdemo1的源码:

1
2
3
4
5
6
7
8
9
10
public class classdemo1 {
private String name;
public void print(){
System.out.println("parameterlessMethod:hello");

}
public void print2(String name){
System.out.println( "parameterMethod: hello" + name);
}
}

反射方法获取Students类。

实例化所需要的类集合 Class[] classes = new Class[]{Integer.class,String.class,Integer.class,Integer.class,String.class};
通过构造器构造类Constructor constructor = cls.getDeclaredConstructor(classes);
通过调用有参构造器实例化类Object str = constructor.newInstance(18, “samny”, 32326663, 10021, “hello!!”);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void reflectmethod1(){
try {

// 获取对象

Class cls = Class.forName("samny.reflection.Students");

// // 获取构造器方法
Class[] classes = new Class[]{Integer.class,String.class,
Integer.class,Integer.class,String.class};
Constructor constructor = cls.getDeclaredConstructor(classes);

Object str = constructor.newInstance(18, "samny", 32326663, 10021, "hello!!");
System.out.println(str);
// 或者下面这样子输出
// System.out.println(constructor.newInstance(18, "samny", 32326663, 10021, "hello!!"));

} catch (ClassNotFoundException | NoSuchMethodException |
IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
}

常规开发人员实例化类构造类demo

1
2
3
4
5
6
7
8
9
public static void Sts(){
Students students = new Students();
students.setAge(18);
students.setName("samny");
students.setCardId(32336666);
students.setId(1001);
students.setAgs("helloooo!!");
System.out.println(students.toString());
}

对比一下效果是没有任何的区别,但反射操作只需要知道类名就可以完全操作类甚至是类中的私有方法之后文章会详细说明,本文不做说明。
在这里插入图片描述


反射调用类中的无参和有参方法。

之前说过的知识就不在说明
开头就说了,invoke是执行获取类得到方法的方法
但调用有参方法和无参方法有点细微的差别
getMethod方法的第一个参数是类方法名称,第二个是类对象。这里先留个疑问,如果是多个类对象呢?
invoke函数的第一个参数是实例化的类对象,第二个是参数值
常规方法的调用,直接Class.method()即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static void reflectmethod2(){
try {
Class cls = Class.forName("samny.reflection.classdemo1");
// 无参方法调用
Object ob = cls.newInstance();
// Method mt = cls.getMethod("print"); 有没有null均可
Method mt = cls.getMethod("print",null);
mt.invoke(ob,null);
// 有参方法调用
Method mt2 = cls.getMethod("print2", String.class);
mt2.invoke(ob,"world");


} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}

在这里插入图片描述



参考

P神-Java安全漫谈-反射篇


文章作者: SummerSec
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 SummerSec !
  目录