• 实例解析Java反射


    在这里插入图片描述

    反射是大多数语言里都必不不可少的组成部分,对象可以通过反射获取他的类,类可以通过反射拿到所有方法(包括私有),拿到的方法可以调用,总之通过“反射”,我们可以将Java这种静态语言附加上动态特性。

    什么是反射

    java的反射是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法,并且对于任意一个对象。

    基本形式

    public void execute(String className, String methodName) throws Exception {
    Class clazz = Class.forName(className);
    clazz.getMethod(methodName).invoke(clazz.newInstance());
    }
    
    • 1
    • 2
    • 3
    • 4

    上面的例子中,我演示了几个在反射里极为重要的方法:
    获取类的方法: forName
    实例例化类对象的方法: newInstance
    获取函数的方法: getMethod
    执行函数的方法: invoke

    反射的作用:

    让Java具有动态性,修改已有对象的属性,动态生成对象,动态调用方法,操作内部类和私有方法

    在反序列化漏洞中的应用

    定制需要的对象,通过invoke调用除了同名函数以外的函数,通过class类创建对象,引入不能序列化的类

    java反射举例

    此处引用白日梦组长的例子,具体讲解一下反射。

    【----帮助网安学习,以下所有学习资料免费领!加weix:yj009991,备注“ csdn ”获取!】

    ① 网安学习成长路径思维导图

    ② 60+网安经典常用工具包

    ③ 100+SRC漏洞分析报告

    ④ 150+网安攻防实战技术电子书

    ⑤ 最权威CISSP 认证考试指南+题库

    ⑥ 超1800页CTF实战技巧手册

    ⑦ 最新网安大厂面试题合集(含答案)

    ⑧ APP客户端安全检测指南(安卓+IOS)

    先写一个Person作为我们下面演示的原型类

    public class Person {
        private String name;
        public int age;
    
        public void act(){
            System.out.println("test");
        }
        @Override
        public String toString() {
            return "Persion{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    
    • 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

    获取原型类

    使用forName方法

    Class c = Class.forName("Person");
    
    • 1

    在此也写一种基于ClassLoader的动态类加载方式

    this.getClass().getClassLoader().loadClass("Person");
    
    • 1

    从原型class里面实例化对象

    利用构造函数实例化

    Constructor constructor = c.getConstructor(String.class,int.class);
    Person p1 = (Person) constructor.newInstance("abc",22);
    
    • 1
    • 2

    我们来逐行写一下分析

    Constructor constructor = c.getConstructor(String.class,int.class);
    这一行是为了获取原型类中重载的构造方法
    public Person(String name, int age) {
    	this.name = name;
    	this.age = age;
    }
    
    对构造方法进行传参实例化一个对象
    Person p1 = (Person) constructor.newInstance("abc",22);
    我们可以打印一下p1看一下返回结果
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    img

    获取类里面的属性

    private String name;
    public int age;
    
    • 1
    • 2
    public
    Field ageField = c.getField("age");
    ageField.set(p1,11);
    
    • 1
    • 2

    img

    private
    Field nameField = c.getDeclaredField("name");
    nameField.setAccessible(true);
    nameField.set(p1,"xinyuan");
    
    • 1
    • 2
    • 3

    img

    获取类方法

    Method actmethod = c.getMethod("act",String.class);
    actmethod.invoke(p1,"SKyMirror");
    
    • 1
    • 2

    getMethod 与上面的获取构造函数类似,第一个参数是函数名,第二个是传参的类型

    invoke方法第一个传入对象,第二个是传入参数值

    img

    利用URLDNS(反射)

    这条链子算是反射的一个简单应用。

    利用点

    URL这个类重写了hashCode方法,导致在执行hashCode的时候,此利用点不能命令执行,但是会请求DNS,所以被用来验证是否存在反序列化漏洞。

    源码如下:

    img

    img

    可以看到当我们调用一次hashCode方法,他会对传进去的URL对象发起请求,即我们如果去DNSLOG申请一个地址,根据访问来判断是否成功执行了hashCode方法进而判断是否执行了反序列化的操作。

    URL这个类实现了java.io.Serializable,可以进行序列化的操作。

    img

    因此,在这里我们可以验证一下我们上面的想法。

    img

    img

    链子

    这个链子也比较短,比较简单,主要是利用HashMap来执行hashCode方法

    HashMap实现了Serializable可以序列化,此处注意反序列化时HashMap的readObject方法

    img

    我们跟进一下hash方法

    img

    key参数可控,key又是由反序列化的时候生成的。在HashMap中用put传入一个URL的对象,即可在反序列化的时候调用到此方法,从而触发整个链子。

    有一点需要注意,我们在序列化的时候,进行的put传参会修改掉传入的URL对象的hashCode的值,因为hashCode值不等于-1,从而导致无法正常触发下面的方法,即无法触发DNS请求。

    img

    同时在正常put传参的时候会执行一次DNS请求,所以我们在put传参之前修改hashCode的值(不为-1就行),传参之后修改hashCode为-1,在反序列化的时候就可以正常执行了。

    payload如下

    public static void main(String[] args) throws Exception{
    HashMap  hashMap = new HashMap<>();
    URL u = new URL("http://i2loelbsvarbmabqf89qi9k88zep2e.burpcollaborator.net/");
    Class c = u.getClass();
    //在进行put方法传参之前修改URL对象的hashCode值
    Field hashcodeField = c.getDeclaredField("hashCode");
    hashcodeField.setAccessible(true);
    hashcodeField.set(u,123);
    
    hashMap.put(u,123);
    //修改URL对象的hashCode值为-1
    hashcodeField.set(u,-1);
    serialize(hashMap);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    编译器一日一练(DIY系列之总结)
    回顾本科毕设内容,用惯了PyTorch环境,结果用tensorflow环境一直出错,没错,本篇博客就是记录用tensorflow的错(自用!)
    SAP: 建立HTTPS 连接时,报错 ICM_HTTP_SSL_PEER_CERT_UNTRUSTED
    智慧城市-疫情流调系列4-GlobalPointer
    类加载器ClassLoader
    团队管理|如何提高技术 Leader 的思考技巧?
    Linux C语言基础 day10
    【ROS】机器人使用Nomachine进行远程控制
    Acwing 周赛135 解题报告 | 珂学家 | 反悔堆贪心
    Windows7安装SSH客户端的解决方案
  • 原文地址:https://blog.csdn.net/qq_38154820/article/details/126869770