java安全-
反射
学习之前推荐你们看一下这个文章
要学的东西太多,但是时间却不够了,由于我也是第一次学,希望有错误的地方能有大佬给纠正
需要了解到这几个函数
获取类的⽅法: forName
实例化类对象的⽅法: newInstance
获取函数的⽅法: getMethod
执⾏函数的⽅法: invoke
一般来说最简单的形式就是这个样子的
Class c = Class.forName(className); c.getMethod(methodName).invoke(c.newInstance());
但实际上在真实的生活中往往需要绕过各式各样的东西
在这里需要说一下在类的运行时
class A{
public A(){
System.out.println("A");
}
static {
System.out.println("B");
}
{
System.out.println("C");
}
}
首先调用的是static,其次是{},最后是构造函数,也就是BCA
static在类初始化的时候就会调用,{}是在构造函数的super()之后
所以在forName对类进行初始化的时候实际上会调用static模块
java在普通类的class_1中如果你在后面接着定义了一个class_2类,会生成class_1.class和class_1$class_2.class
所以该怎么利用呢?
如果有一个函数里面如果有一个这个语句
Class.forName(class);
这个时候我们可以控制其中的class,那么我们就可以自己编写一个恶意类,将恶意代码放在static模块下面
在使用这个方法的时候我们就已经获得了一个类了,接下来我们要获得它里面的东西了
class.newInstance()可以调用类的无参构造函数。但是如果类是私有的就会报错
如果想要调用私有类就不能使用这个函数了,我们因该用class.getMethod来调用这个私有类中的静态函数去调用这个私有类的构造函数(这里可能有点绕),因为一般私有类都会有一个静态函数实现相应的功能
在将这个之前我要说一下两个函数getMEthod
和invoke
getMethod
的作用是通过反射获取一个类的某个特定的共有方法,因为java中类可能会有很多重载,我们没有办法通过函名儿去确定一个函数,所以需要传递一个函数参数类型的列表
method(String str)=>class.getMethod("method",String.class)
method(String[] strN)=>class.getMethod("method",String[].class)
举个例子java.lang.Runtime
就是一个私有类,在调用这个私有类的构造函数的时候不能直接
Class clazz = Class.forName("java.lang.Runtime");
clazz.getMethod("exec", String.class).invoke(clazz.newInstance(), "id");
invoke
的作用是执行方法,一般紧跟着getMethod使用
我们应该利用getMethod
函数去获得这个类的Runtime.getRuntime()
方法来获得对象
所以这个payload
可以改成
Class c = Class.forName("java.lang.Runtime");
c.getMethod("exec", String.class).invoke(c.getMethod("getRuntime").innoke(c), "id");
这个payload
可以一步一步的去看
第一步获得java.lang.Runtime
类
Class c = Class.forName("java.lang.Runtime");
第二步获得我们想要执行的exec
方法
Method method = c.getMethod("exec",String.class);
第三步获得我们这个类的对象
method getObject = c.getMethod("getRuntime");
第四步实现第三步
Object run= getObject.invoke(c);
第五步实现我们的payload
method.invoke(run,"id");
在这之前我们说过一个问题:类是私有类的时候不能直接使用newInstance()来获取无参构造函数,用getMethod去调用它的方法,那如果方法是私有的怎么办?
那就是使用getDeclared
系列的反射
继续上面的例子
我们不用getMethod
去获得getRuntime
我们直接用getDclaredConstructor
来获取私方法
它的使用方法和getMethod类似,不过需要使用setAccessible
来修改作用域
Class c = Class.forName("java.lang.Runtime");
Constructor gouzao = c.getDeclaredConstructor():
gouzao.setAccessible(true);
c.getMethod("exec",String.class).invoke(gouzo.newInstance(),"id");
如果我们要获得有参的构造函数呢
那就是用getConstructor
是不是与上面的玩意儿很眼熟我去百度了一波他们的区别
getMethod 系列方法获取的是当前类中所有公共方法,包括从父类继承的方法 getDeclaredMethod 系列方法获取的是当前类中“声明”的方法,是实在写在这个类里的,包括私 有的方法,但从父类里继承来的就不包含了
getConstructor
与getDeclaredConstructor
也类似
我先创建一个类
package DG
public class test {
private int age;
private String name;
public test( String name,int age) {
this.age = age;
this.name = name;
System.out.println("有参数");
}
public test() {
System.out.println("无参数");
}
}
我们再去获得有参构造函数
Class cl=Class.forName("DG.test");
Constructor con=cl.getConstructor(String.class,int.class);
Object obj=con.newInstance("DG",19);
最终回显为“有参数”
再看看我们常用的另一个有命令执行的类ProcessBuilder
它的构造函数有两个
一个的参数是List<String> command
另一个是String command
随便选一个
Class clazz = Class.forName("java.lang.ProcessBuilder"); clazz.getMethod("start").invoke(clazz.getConstructor(String.class).newInstance( "calc.exe"));
如果有什么错误的地方希望大神能够指点我一下,嘻嘻嘻嘻