Panda | 热爱安全的理想少年 - java 反序列化
type: channel
link: https://www.cnpanda.net/tag/java-反序列化
items: 欢迎购买我的新书《Java代码审计(入门篇)》
items: JEP290的基本概念
items: 序列化流程分析总结
items: JDK7u21反序列化漏洞分析笔记

欢迎购买我的新书《Java代码审计(入门篇)》
type: item
date: 2021-07-15T05:54:00+00:00
description: 关于这本书这本书在去年 12 月就已经写完，从修改时到发售，历经 7 个月的时间，十分不易这本书非常适合新人入门，算是我的系列文章【Java 代码审计入门】的横纵延伸（这也是【Java 代码审计入门】系列文章那么久没有更新的原因）所以想学习 java 代码审计的朋友可以考虑买本书看看购买链接https://item.jd.com/10033832360716.html本书目录本书的简介本书介绍本书推荐

JEP290的基本概念
type: item
date: 2021-06-25T11:49:24+00:00
description: JEP2900x01 什么是JEP?JDK Enhancement Proposal 简称JEP，是 JDK 增强提议的一个项目，目前索引编号已经达到了JEP415，本文重点来谈谈什么是JEP290，JEP290做了哪些事，JEP290绕过的方法总结等。0x02 什么是JEP290?JEP290的描述是Filter Incoming Serialization Data，即过滤传入的序列化数据F Clo 9core/io:serialization290Filter Incoming Serialization DataJEP290 是 Java 为了防御反序列化攻击而设置的一种过滤器，其在 JEP 项目中编号为290，因而通常被简称为JEP2900x03 JEP290的适用范围Java™ SE Development Kit 8, Update 121 (JDK 8u121)Java™ SE Development Kit 7, Update 131 (JDK 7u131)Java™ SE Development Kit 6, Update 141 (JDK 6u141)0x04 JEP290 的作用Provide a flexible mechanism to narrow the classes that can be deserialized from any class available to an application down to a context-appropriate set of classes. [提供一个限制反序列化类的机制，白名单或者黑名单]Provide metrics to the filter for graph size and complexity during deserialization to validate normal graph behaviors. [限制反序列化的深度和复杂度]Provide a mechanism for RMI-exported objects to validate the classes expected in invocations. [ 为RMI远程调用对象提供了一个验证类的机制]The filter mechanism must not require subclassing or modification to existing subclasses of ObjectInputStream. [定义一个可配置的过滤机制，比如可以通过配置 properties文件的形式来定义过滤器]JEP290 具体内容1、限制的情况：反序列化类数组时的数组元素数 ( arrayLength )每个嵌套对象的深度( depth )当前数量对象引用 ( references ) 的数量当前消耗的字节数 ( streamBytes )2、支持 3 种配置过滤器的方式自定义过滤器进程范围过滤器（也称为全局过滤器）用于 RMI 注册表和分布式垃圾收集 (DGC)使用的内置过滤器3、自定义过滤器当反序列化要求与整个应用程序中的任何其他反序列化过程不同时，就会出现自定义过滤器的配置场景；可以通过实现ObjectInputFilter接口并覆盖checkInput(FilterInfo filterInfo)方法来创建自定义过滤器：如以下示例：static class VehicleFilter implements ObjectInputFilter { final Class<?> clazz = Vehicle.class; final long arrayLength = -1L; final long totalObjectRefs = 1L; final long depth = 1l; final long streamBytes = 95L; public Status checkInput(FilterInfo filterInfo) { if (filterInfo.arrayLength() < this.arrayLength || filterInfo.arrayLength() > this.arrayLength || filterInfo.references() < this.totalObjectRefs || filterInfo.references() > this.totalObjectRefs || filterInfo.depth() < this.depth || filterInfo.depth() > this.depth || filterInfo.streamBytes() < this.streamByt…

序列化流程分析总结
type: item
date: 2021-06-13T08:16:00+00:00
description: 目录目录0x01 写在前面0x02 流程分析0x03 总结0x04 参考0x01 写在前面本文写的比较细，推荐复制demo代码，然后一步一步跟随笔者的分析进行debug调试跟随，这样跟能够帮助读者理解此文。0x02 流程分析所谓的序列化即是一个将对象写入到IO流中的过程。序列化的步骤通常是首先创建一个ObjectOutputStream输出流，然后调用ObjectOutputStream对象的writeObject方法，按照一定格式(上面提到的)输出可序列化对象。如下段Demo代码：package com.panda.alipay; import java.io.*; public class Main { public static class Demo implements Serializable { private String string; transient String name = "hello"; public Demo(String s) { this.string = s; } public static void main(String[] args) throws IOException { Demo demo = new Demo("panda"); ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("panda.out")); outputStream.writeObject(new Demo("panda")); outputStream.close(); } } }整个代码中最关键的两行为：ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("panda.out")); outputStream.writeObject(new Demo("panda"));这两行其实就包括了整个序列化的流程。首先来看ObjectOutputStream，ObjectOutputStream是一个实现了ObjectOutput接口的OutputStream的子类，其类定义如下：public class ObjectOutputStream extends InputStream implements ObjectInput, ObjectStreamConstants{ ... }当我们实例化ObjectOutputStream并传入参数后，首先调用的是ObjectOutputStream的构造方法。ObjectOutputStream构造方法有两个，一个是public的单参数构造函数，一个是protected的无参构造函数，上述代码中我们传入了new FileOutputStream("panda.out")为参数，因此调用的是ObjectOutputStream的public的单参数构造函，该函数内容如下：/** * 创建写入指定输出流的ObjectOutputStream。 * 此构造函数将序列化流头写入底层流； * 调用者可能希望立即刷新流，以确保接收ObjectInputStreams的构造函数在读取头时不会阻塞。 * 如果安装了安全管理器，则当重写ObjectOutputStream.putFields或ObjectOutputStream.writeUnshared方法的子类的构造函数直接或间接调用时，此构造函数将检查“enableSublassimplementation”SerializablePermission。 */ public ObjectOutputStream(OutputStream out) throws IOException { verifySubclass(); bout = new BlockDataOutputStream(out); handles = new HandleTable(10, (float) 3.00); subs = new ReplaceTable(10, (float) 3.00); enableOverride = false; writeStreamHeader(); bout.setBlockDataMode(true); if (extendedDebugInfo) { debugInfoStack = new DebugTraceInfoStack(); } else { debugInfoStack = null; } }在该构造函数的开始，首先会调用verifySubclass方法处理缓存信息，要求该类(或子类)进行验证…

JDK7u21反序列化漏洞分析笔记
type: item
date: 2021-06-10T15:06:00+00:00
description: 目录目录0x01 写在前面0x02 所需的知识点0x03 基础知识1、Java 反射2、javassist 动态修改类3、Java 静态类加载4、Java 动态代理Proxy 类InvocationHandler 接口5、hash碰撞0x04 jdk7u21 payload0x05 漏洞分析0x06 漏洞修复0x07 总结0x08 参考0x01 写在前面JDK7u21原生gadget链的构造十分经典，在对于其构造及思想学习后，写下本文作为笔记。0x02 所需的知识点JDK7u21这个链用了很多的Java基础知识点，主要如下：Java 反射javassist 动态修改类Java 静态类加载Java 动态代理hash碰撞为了方便大家理解此文，因此我会对这些知识点进行简单介绍，如果都了解的朋友可以直接翻到后面的分析过程。0x03 基础知识1、Java 反射反射 (Reflection) 是 Java 的特征之一，在C/C++中是没有反射的，反射的存在使得运行中的 Java 程序能够获取自身的信息，并且可以操作类或对象的内部属性。那么什么是反射呢？对此， Oracle 官方有着相关解释：“Reflection enables Java code to discover information about thefields, methods and constructors of loaded classes, and to usereflected fields, methods, and constructors to operate on theirunderlying counterparts, within security restrictions.”（反射使Java代码能够发现有关已加载类的字段、方法和构造函数的信息，并在安全限制内使用反射的字段、方法和构造函数对其底层对应的对象进行操作。）简单来说，通过反射，我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。同样的，JAVA的反射机制也是如此，在运行状态中，通过 Java 的反射机制，对于任意一个类，我们都能够判断一个对象所属的类；对于任意一个类，都能够知道这个类的所有属性和方法；对于任意一个对象，都能够调用它的任意一个方法和属性；这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。既然利用Java的反射机制，我们可以无视类方法、变量访问权限修饰符，可以调用任何类的任意方法、访问并修改成员变量值，那么这可能导致安全问题，如果一个攻击者能够通过应用程序创建意外的控制流路径，那么就有可能绕过安全检查发起相关攻击。假设有段代码如下： String name = request.getParameter("name"); Command command = null; if (name.equals("Delect")) { command = new DelectCommand(); } else if (ctl.equals("Add")) { command = new AddCommand(); } else { ... } command.doAction(request);存在一个字段为name，当获取用户请求的name字段后进行判断，如果请求的是 Delect 操作，则执行DelectCommand 函数，若执行的是 Add 操作，则执行 AddCommand 函数，如果不是这两种操作，则执行其他代码。此时，假如有位开发者看到了这段代码，他觉得可以使用Java 的反射来重构此代码以减少代码行，如下所示：String name = request.getParameter("name"); Class ComandClass = Class.forName(name + "Command"); Command command = (Command) CommandClass.newInstance(); command.doAction(request);这样的重构看起来使得代码行减少，消除了if/else块，而且可以在不修改命令分派器的情况下添加新的命令类型，但是如果没有对传入进来的name字段进行限制，那么我们就能实例化实现Command接口的任何对象，从而导致安全问题。实际上，攻击者甚至不局限于本例中的Command接口对象，而是使用任何其他对象来实现，如调用系统中任何对象的默认构造函数，再如调用Runtime对象去执行系统命令，这就可能导致远程命令执行漏洞。更多关于反射的内容具体可以参考我以前写的这篇文章：https://www.cnpanda.net/codeaudit/705.html2、javassist 动态修改类…