初探Java反序列化漏洞学习笔记
Posted 青草池塘部落格
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初探Java反序列化漏洞学习笔记相关的知识,希望对你有一定的参考价值。
1 前言
小编近期对“Java反序列化漏洞”进行了一定的了解。这篇博客是我对Java反序列漏洞的典型案例“Apache-CommonsCollections 序列化RCE漏洞”的一点学习笔记,请您拍砖!这篇文章的主要内容包括了:
Java反序列化漏洞利用原理
CommonsCollections反序列化漏洞导致的RCE原理分析
运用IntelliJ IDEA以及Eclipse对PoC进行详细分析
运用脚本对JBoss的CommonsCollections反序列化漏洞进行检测
运用JBoss反序列化终极检测工具进行检测
运用JBoss反序列化漏洞getshell工具进行检测
总结
参考资料
2 漏洞原理
2.1 Java反序列化漏洞利用原理
在Java中,序列化是指将对象转换成字节流,以便于存储在内存、文件、数据库中或者在网络上进行传送,该处理由ObjectOutputStream类的writeObject()方法实现;反序列化是序列化的逆过程,将字节流还原成Java 对象,该处理由ObjectInputStream类的readObject()方法实现。Java对象从序列化到反序列化的完整处理流程如图所示。
Java 序列化及反序列化处理在基于Java 架构的Web应用中具有尤为重要的作用。位于网络两端、彼此不共享内存信息的两个Web应用在进行远程通信时,无论相互间发送何种类型的数据,在网络中实际上都是以二进制序列的形式传输的。为此,发送方就必须将要发送的Java 对象序列化为字节流,接收方则需要将字节流再反序列化还原得到Java 对象,才能实现正常通信。
然而,只要Java应用允许对用户输入的不可信数据进行反序列化处理,那么攻击者就可以通过构造恶意输入来使反序列产生非预期的Java 对象,在产生过程中就可能带来任意代码执行问题,这就是Java 反序列化漏洞的产生原理[1]。
例1和例2可以展示漏洞的基本原理。例1的代码可将String对象obj序
列化后写入文件object.db文件中,随后又从该文件反序列化得到该对象。
而例2对例1做了一定的修改。
在运行例2的时候,有个计算器被弹出了。通过分析代码可以发现,MyObject类实现了java.io.Serializable接口。要被序列化的对象所在的类一定要实现该接口,并且实现接口中的readObject()方法,readObject()方法可以定制反序列化的一些行为。这里的readObject()方法包含了可执行系统命令:“Runtime.getRuntime().exec("calc.exe");”[2]。
2.2 CommonsCollections反序列化漏洞导致的RCE原理分析
Apache-CommonsCollections类库的Java反序列化漏洞引发RCE(Remote Code Execution,远程代码执行)的基本原理如下:
CommonsCollections包实现了一个名为TransformedMap的类,该类是对Java数据结构Map接口的一个扩展。该类的功能是当一个元素被加入到集合中时,对该元素进行特定的变换,变换的逻辑由Transformer类定义。Transformer类对象在TransformedMap实例化时作为参数传入其构造方法。
当TransformedMap对象的keyTransformer或者valueTransformer发生变化时,会被触发相应Transformer类transform()方法。为了对Map进行某种变换,可调用decorate()方法。
而这里的Transformer是一个接口,其中定义的transform()方法用来将一个对象转换成另一个对象。
Apache CommonsCollection类库中内置了一系列常用的Transformer类,其中InvokerTransformer类的构造方法具备根据传入的类名和方法名反射执行的能力。此外,利用Transformer数组可以构造ChainedTransformer类的实例。在构造过程中,ChainedTransformer类可按索引顺序调用一系列Transformer类的transform()方法。
由上述分析可见,InvokerTransformer类和ChainedTransformer类俨然已成为引发攻击的导火索,只需找到一个火花即可达到任意代码执行的效果。为此,我们可以首先构造一个Map和一个能够执行代码的ChainedTransformer,以此生成一个TransformedMap,然后想办法去触发Map中的Entry产生修改(例如setValue()方法),即可触发我们构造的ChainedTransformer中的一系列变换方法。例3的PoC的Test2类的源码如下:
当上面的代码运行到setValue()时,就会触发ChainedTransformer中的一系列变换方法:首先通过ConstantTransformer获得Runtime类,进一步通过反射调用getMethod找到invoke()方法,最后再运行命令“calc.exe”。
但是目前的构造还需要依赖于触发Map中某一项来调用setValue(),这是“主动的”。而RCE往往是“被动的”(远程的受攻击的机器并不想执行这些恶意代码),为了实现RCE,我们需要想办法通过readObject()直接触发[3]。
到目前为止,我们找到了一些创造RCE的条件:
(1)使用InvokeTransformer,通过transform()方法执行代码
(2)使用TransformedMap,通过执行setValue()方法触发transform()方法
(3)找到可同时满足上面两点的实现了Serializable接口的类,类中包含readObject()方法
条件(1)比较容易满足,而AnnotationInvocationHandler类恰好可充当
火花的角色。因为它满足条件(2),有一个Map类型的成员变量memberValues。
该类也满足条件(3),在反序列化过程中调用readObject()方法时,对memberValues成员变量的每一项都调用setValue()方法。
至此,攻击者只需要实例化一个AnnotationInvocationHandler对象,将其成员变量Map类型的memberValues精心构造成恶意的TransformedMap对象。将该对象序列化后,提交给未做安全性检查的Java应用,通过反序列化操作,恶意的TransformedMap对象中transform()方法将被执行,从而实现远程代注入攻击[4]。触发恶意代码的示意图如下:
PoC的大致逻辑如下:
3 运用IntelliJ IDEA以及Eclipse对漏洞进行详细分析
在博客[2]有对例3的PoC的详细分析过程,亲们可以前往查看。我跟着博客[2]对PoC走一遍时的一点点心得:
(1)为了让PoC跑起来,有时需要补充一些jar包。当不知道某个类来自哪个jar包时,可以借助http://www.findjar.com/index.x这个网站。
(2)为了查看jar包源码,有时需要导入jar包源码,可参考:https://jingyan.baidu.com/article/ce436649f3b94e3772afd376.html。
(3)IntelliJ IDEA的“Evaluate Expression”功能让人眼前一亮。
4 运用脚本对JBoss的CommonsCollections反序列化漏洞进行检测
例4借鉴文献[4]以及网页[5]的方法对JBoss 6.1.0的CommonsCollections漏洞的存在性进行检测。所运用的Python脚本尝试在服务器的默认应用中创建空文件,并对该空文件进行访问。如果访问正常,则说明服务器存在此漏洞;如果访问不正常,则说明可能不存在此类型的漏洞。
实验的服务器是Ubuntu虚拟机,攻击机是Kali 2虚拟机。
主要实验步骤如下:
(1)在服务器搭建JBoss 6.1.0容器
在搭建JBoss 6.1.0时参考了博文[6-7]。
我们还可在服务器grep受影响的类“InvokerTransformer”。
(2)在攻击机生成有效攻击载荷;
ysoserial是一个专门针对不安全Java反序列化的payload生成工具,通过ysoserial可以自定义生成WebLogic、Spring、Groovy等平台的有效攻击载荷。
我们还可以通过“管道”与“xxd”命令,可以查看生成的载荷中有“ACED0005”。它们分别是java.IO.ObjectStreamConstants类中的STEAM_MAGIC和STREAM_VERSION常量,表示对象序列化文件和序列化方法的版本。
(3)在攻击机运行脚本,检测漏洞;
在运行脚本之后,我们可以发现Jboss容器的默认根目录里有新文件“newFile”。
我们也可以在服务器上使用tcpdump将端口为8080的流量保存到pcap文件,并用wireshark分析pcap文件。
在例3的PoC中会生成一个“obj”文件,我们也可以将该文件序列化为二进制以作为payload,并用例4中的python脚本将payload发送给Windows Server 2003的服务器,以可以通过RCE在Win Server 2003打开计算器。
5 运用JBoss反序列化终极测试工具进行检测
在例5的实验中,将借助“执行命令”功能,在Win 7 攻击机实施以下操作,以在Windows Server 2003靶机上添加非法用户并进行远程登录:
在Java反序列化终极测试工具的CMD栏:
(1)执行“whoami”;
(2)执行“net localgroup administrators”查看管理员组;
(3)执行“net user test password /add”添加一个用户名为“tester”,密码为“password”的用户;
(4)执行“net localgroup administrators test /add”将用户加入管理员组;
(5)执行“net localgroup administrators”,可见管理员组列表新增了“tester”用户[8];
(6)执行“
REG ADD HKLMSYSTEMCurrentControlSetControlTerminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f”开启3389端口。
接着,在Win 7攻击机的控制台执行“mstsc”做远程桌面连接。
6 运用JBoss反序列化漏洞getshell工具进行检测
在例6的实验中,借助“JBoss漏洞利用工具”上传webshell,并用“中国菜刀”连接该webshell。
JBoss漏洞利用工具是一个专门针对JBoss反序列化漏洞利用的工具,它直接通过war包的部署来获取一个“中国菜刀”的webshell[9]。
7 总结
如何发现Java反序列化漏洞?
(1)从流量中发现反序列化的痕迹,关键字:aced 0005,ROoAB
(2)从源码入手,可以被序列化的类一定实现了Serializable接口
(3)观察反序列化时的readObject()方法是否被重写,重写中是否有设计不合理,可被利用之处
如何防范?
(1)类白名单检验
(2)禁止JVM执行外部命令Runtime.exec
如何修复?
(1)使用官方提供的高版本commons-collections.jar替换Java应用程序lib目录的原有库可规避漏洞风险;
(2)在不影响正常业务的情况下,删除commons-collections.jar中的InvokerTransformer.class文件,对于JBoss,还需同时删除InstantiateFactory.class和InstantiateTransformer.class文件;
(3)将Java应用程序升级至最新版本或者不在影响范围内的版本。
8 参考资料
[1] 郭瑞. Java反序列化漏洞研究[J]. 信息安全与技术, 2016, 7(3):27-30.
[2] 血梦.深入理解JAVA反序列化漏洞[EB/OL].[2017-12-4].http://www.hacksec.cn/codesec/568.html.
[3] 长亭科技.Lib之过?Java反序列化漏洞通用利用分析[EB/OL].[2015-11-11].[3]https://blog.chaitin.cn/2015-11-11_java_unserialize_rce/.
[4] 钱劼, 雷敏, 邹仕洪. Java反序列化漏洞自动检测脚本设计[J]. 网络安全技术与应用, 2017(8):66-68.
[5] 知道创宇.JBoss “Java 反序列化”过程远程命令执行漏洞[EB/OL].[2015-11-12].https://www.seebug.org/vuldb/ssvid-89723.
[6] 酒樽舞曲.Ubuntu 安装JBoss[EB/OL].[2011-9-19].http://blog.csdn.net/w709854369/article/details/6790837.
[7] WNFK.JBOss启动只能在本机访问的解决办法[EB/OL].[2013-11-17].http://www.cnblogs.com/hanxianlong/p/3427938.html.
[8] 徐江珮, 王捷, 蔡攸敏,等. Java反序列化漏洞探析及其修复方法研究[J]. 湖北电力, 2016(11).
[9] icq8756c1a2.JBoss反序列化漏洞环境搭建与复现[EB/OL].[2017-8-31].https://bbs.ichunqiu.com/thread-26613-1-1.html.
注:这篇小博客的一些相关资源已经上传到百度云,想要尝试的亲们可以到此处下载:https://pan.baidu.com/s/1bp54IcR
欢迎长按二维码,关注“青草池塘部落格”!
以上是关于初探Java反序列化漏洞学习笔记的主要内容,如果未能解决你的问题,请参考以下文章
Java学习笔记6.3.3 文件操作 - 对象序列化与反序列化