java安全学习-第二天(反射补充)

0x01、前言

第一天的文章中有个小点写错了,小标题”如何执行类的私有方法”有误,应该改成”如何在类的构造函数是私有类型的情况下进行调用”

还有,方法和函数本质上一个东西,本人对这块叫法比较随意

今天补充一些内容

1、

如果一个类没有无参构造方法

如果一个类并非单例模式(不含getxxx的静态方法)

那该怎样成功的调用这个类呢?

2、类中的私有方法有办法利用吗?

构造方法(构造函数)—->无参构造方法/有参构造方法

接下来开始探索

0x02、开始

第一种情况的应对

我们需要了解一个新的知识点

getConstructor函数

这个函数是用来获得目标类具体构造方法的

而获得构造方法后,我们用第一天将过的知识点class.newInstance()来执行构造方法

我来举一个例子🌰

  1. import java.lang.reflect.*;
  2. public class rat{
  3. public static void main(String[] args) throws Exception {
  4. try{
  5. Class clazz = Class.forName("java.lang.ProcessBuilder");
  6. Constructor name[] = clazz.getConstructors();
  7. for (int i = 0; i < name.length; ++i) {
  8. System.out.println(name[i]);
  9. }
  10. }
  11. catch (Exception e){
  12. e.printStackTrace();
  13. }
  14. }
  15. }

1.png

可以看到,目标ProcessBuilder中有两个含参构造方法

那我们又该如何用这个方法去执行命令呢?

exp:

  1. import java.lang.reflect.*;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import java.io.IOException;
  5. public class rat{
  6. public static void main(String[] args) throws Exception {
  7. try{
  8. Class clazz = Class.forName("java.lang.ProcessBuilder");
  9. String[] cmd = new String[] {"open", "-a", "Calculator"};
  10. clazz.getMethod("start").invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList(cmd)));
  11. }
  12. catch (Exception e){
  13. e.printStackTrace();
  14. }
  15. }
  16. }

2.png

估计你们会有些疑惑。start是哪来的?为什么要用List.class

start方法是ProcessBuilder中执行命令的一种方法

而我们这里,默认初始化时是使用List的参数(也就是第一种有参构造函数),所以用到了List.class

毕竟要把构造函数运行后才算真正调用了一个类

先给ProcessBuilder附上初始化的值——>再由start创建一个新进程执行命令

第二种情况的应对

我们以Runtime类举例

在第一天中,我们是使用了单例模式下静态方法的特性,才能成功调用私有属性的方法exec

那我们是否可以不用第一天的方法呢?

答案是肯定的

我们先来了解获取方法的区别,这里引用p牛的文章

getMethod 系列方法获取的是当前类中所有公共方法,包括从父类继承的方法

getDeclaredMethod 系列方法获取的是当前类中“声明”的方法,是实在写在这个类里的,包括私有的方法,但从父类里继承来的就不包含了

同理,getConstructor和getDeclaredConstructor也是如此

一个是获取public类构造方法,一个是获取所有的构造方法(包括私有)

Exp:

  1. import java.lang.reflect.*;
  2. public class siyou{
  3. public static void main(String[] args) throws Exception {
  4. try{
  5. Class clazz = Class.forName("java.lang.Runtime");
  6. String cmd = "open"+" "+"-a"+" "+"Calculator";
  7. Constructor cmds = clazz.getDeclaredConstructor(); //获取私有构造方法
  8. cmds.setAccessible(true); //设置作用域使私有函数能执行
  9. clazz.getMethod("exec",String.class).invoke(cmds.newInstance(),cmd); //私有构造方法初始化变为Runtime class
  10. }
  11. catch (Exception e){
  12. e.printStackTrace();
  13. }
  14. }
  15. }

关于setAccessible,这个,我认为只要记住就行了,它的作用是修改作用域,能让你的私有函数(构造方法)执行

3.png

0x03、小结

第一天的知识点理顺后,感觉作用还是蛮大的,能更快的理解第二天的知识点

最后,以花爷的话结尾

“Web,有手就行”