Java安全之原生readObject方法解读

Java安全之原生readObject方法解读0x00前言在上篇文章分析shiro中,遇到了Shiro重写了ObjectInputStream的resolveClass导致的一些基于Invoke

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

Java安全之原生readObject方法解读

0x00 前言

在上篇文章分析shiro中,遇到了Shiro重写了ObjectInputStreamresolveClass导致的一些基于InvokerTransformer去实现的利用链没法使用,因为这需要去定义一个InvokerTrans数组,而该数组传入到Shiro重写后的resolveClass方法中会报错。但是在此之前,并没有去对readObject方法去做一个解读和分析。所以也不知道他具体的实现。包括在分析利用链的时候,只知道到调用了ObjectInputStream.readObject方法后,如果readObject被重写的话,就会调用重写后的readObject方法,但是我们也并不知道在内部是怎么样去做一个实现的。那么下面来分析一下readObject的功能实现。

0x01 readObject方法分析

在前面先贴一张readObject的执行流程图,这是一张weblogic的反序列化执行流程图。第一个readObject直接忽略,到下篇文weblogic再做讲解。

Java安全之原生readObject方法解读

这里写一段测试代码去进行反序列化操作,然后进行动态跟踪。

User实体类:

package com.nice0e3;

import java.io.Serializable;

public class User implements Serializable {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "User{" +
                "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 User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

ReadTest类:

package com.nice0e3;

import java.io.*;

public class ReadTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        User user = new User();
        user.setName("nice0e3");
        user.setAge(20);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.txt"));
        oos.writeObject(user);
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("1.txt"));
        Object o = ois.readObject();
    }
}

然后将断点落在ObjectInputStream.readObject方法中,进行执行测试类代码动态跟踪。

Java安全之原生readObject方法解读

这里对enableOverride进行了一个判断,不为flase的话就会去返回readObjectOverride方法,而在构造方法中就定义该值为flase。

Java安全之原生readObject方法解读

下面就直接执行到了这步

Java安全之原生readObject方法解读

调用了readObject0方法,选择跟进查看一下内部的实现。

Java安全之原生readObject方法解读

在这里会去获取序列化信息第一个字节,如果为TC_RESET就会调用bin.readByte()handleReset();方法。

查看TC_RESET内容。

Java安全之原生readObject方法解读

而该值转换Byte后,为121,我们序列化数据的第一个字节为151,这里就跳过不执行了。

接下来代码中定义了一个switch去做一个判断,TC_OBJECT的值转换后刚刚好为115。那么就会执行到这一步。

Java安全之原生readObject方法解读

在这里面会调用readOrdinaryObject方法,进行跟进。

Java安全之原生readObject方法解读

在该方法中还会去调用readClassDesc方法,继续跟进。

Java安全之原生readObject方法解读

看到这里发现就很有意思了,获取我们序列化数据的第二个字节,然后又进行一次switch,这次走到了readNonProxyDesc方法中,跟进!

Java安全之原生readObject方法解读

Java安全之原生readObject方法解读

在这又调用了resolveClass方法然后传入readDesc参数。还是跟进方法。

Java安全之原生readObject方法解读

这里返回了

Class.forName(name, false, latestUserDefinedLoader());

latestUserDefinedLoader()方法返回的是sun.misc.VM.latestUserDefinedLoader()说明指定了该加载器。

返回到readOrdinaryObject方法中继续做分析。
Java安全之原生readObject方法解读

直接定位到这一步,该方法对反序列化的操作进行实现。

Java安全之原生readObject方法解读

这里的slotDesc.hasReadObjectMethod()获取的是readObjectMethod这个属性,如果反序列化的类没有重写readobject(),那么readObjectMethod这个属性就是空,如果这个类重写了readobject(),那么就会进入到if之中的

slotDesc.invokeReadObject(obj, this);

Java安全之原生readObject方法解读

如果readobject()方法被重写则是走到这一步

Java安全之原生readObject方法解读

0x02 Shiro resolveClass方法分析

在shiro里面resolveClass方法被进行了重写,导致大部分利用链都使用不了,查看一下该方法实现。

Java安全之原生readObject方法解读

这里去调用了ClassUtils.forName方法进行跟踪。

Java安全之原生readObject方法解读

这里是调用了THREAD_CL_ACCESSOR.loadClass,查看一下THREAD_CL_ACCESSOR是什么。

Java安全之原生readObject方法解读

跟进查看一下该类。

Java安全之原生readObject方法解读

这里调用getClassLoader方法获取类加载器,而在这里获取到的是ParallelWebappClassLoader,那么下面调用的肯定也就是ParallelWebappClassLoader.loadClass

上面内容中的一些补充:

TC_NULL描述符表示空对象引用

TC_REFERENCE描述符表示引用已写入流的对象

TC_PROXYCLASSDESC是新的代理类描述符

TC_CLASSDESC是新的类描述符

参考文章

https://blog.csdn.net/niexinming/article/details/106665753

https://www.anquanke.com/post/id/192619#h2-2

0x03 结尾

其实在前面的一些cc链的调试铺垫下,再去调试其他的一些漏洞,都会比较熟练。本文也是为了下文去做了一个较好的铺垫。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119896.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java数组排序去重_JAVA数组去重排序

    java数组排序去重_JAVA数组去重排序今天也是很丧的一天,天气真的好热啊,胃不舒服,一直打嗝,中午吃了一碗凉掉的粥,然后开始拉肚子,一点不想要过来医院学习(基本上都是自己傻坐着,又没有老师来教我们,幽怨.jpg),但不来又过不去自己心里的那道坎,像是逃课的感觉,就很烦,然后在校门口纠结了十分钟还是过来了,emmmmm……然后就有了下面的代码packageArray;publicclassBubbleSort{publi…

    2022年6月29日
    19
  • 完全理解icmp协议

    完全理解icmp协议1.ICMP出现的原因在IP通信中,经常有数据包到达不了对方的情况。原因是,在通信途中的某处的一个路由器由于不能处理所有的数据包,就将数据包一个一个丢弃了。或者,虽然到达了对方,但是由于搞错了端口号,服务器软件可能不能接受它。这时,在错误发生的现场,为了联络而飞过来的信鸽就是ICMP报文。在IP网络上,由于数据包被丢弃等原因,为了控制将必要的信息传递给发信方。ICMP协议是为了辅助IP…

    2022年7月12日
    20
  • 激光导航和slam导航区别_激光导航和视觉导航的区别

    激光导航和slam导航区别_激光导航和视觉导航的区别激光SLAM基本原理基本原理

    2022年8月23日
    5
  • ping命令详解 ping命令入门详解

    ping命令详解 ping命令入门详解在这个时代,科技越来越发达,网络已经越来越成为人们不可缺少的一部分。计算机也已经是很多学校的课程了,因为计算机技术是非常有技术性的专业,它其中涉及到很多专业知识,需要通过学习才能掌握。今日小编就为大家介绍一个计算机的命令,它叫做Ping,这边介绍一下它的入门知识,主要是关于ping连接和命令方面的介绍。  1、Ping的基础知识  ping命令相信大家已经再熟悉不过了,但是能把ping的功能发…

    2022年9月22日
    0
  • singTask和FLAG_ACTIVITY_CLEAR_TOP的区别

    singTask和FLAG_ACTIVITY_CLEAR_TOP的区别假设所有的activity启动方式是standard,两者的区别就是1.intent中的flag为FLAG_ACTIVITY_CLEAR_TOP时,将指定activity上面的其他activity出栈,指定activity位于栈顶,但是可以使用已有的实例或者重新创建一个实例,取决于是否加一个FLAG_ACTIVITY_SINGLE_TOP标志如果加了,则不会重建实例,在onNewIntent()

    2022年7月17日
    13
  • webpack版本选择_webpack官网

    webpack版本选择_webpack官网1.先确认node和npm有没有安装node-vnpm-v2.创建一个打包文件夹mkdirtest3.全局安装webpack和webpack-cli使用npm安装会卡在一个地方,因此这里我使用cnpm,没有安装的话,可以百度看看怎么安装cnpminstallwebpack@3.39.2i-gcnpminstallwebpack-cli@3.3.7-gcnpminstallwebpack-dev-server@3.8.0-g4.在test文件夹下面安装对应版

    2022年8月10日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号