Apache Log4j反序列化详细分析

 

0x00 前言

之前分析了shiro的身份认证和反序列化的漏洞,这次以两个漏洞简单地分析下Log4j在使用时未过滤导致的反序列化问题,相信会对反序列化以及数据过滤有更多的理解。

 

0x01 关于Apache Log4j

在项目中显示相关日志最原始的方式就是在代码段中添加相关打印的语句,这样可以在运行时掌握程序的运行状态。但是这样不仅不方便,而且不美观,不利于代码的查看,所以需要封装一个日志打印的操作类。

Log4j是Apache的开源项目,可以实现对System.out等打印语句的替代,并且可以结合spring等项目,实现把日志输出到控制台或文件等。而且它还可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码,满足了大多数要求。

本次的两个漏洞均为未对传入的需要反序列化的数据做过滤,导致了恶意构造从而造成相关反序列化漏洞。

 

0x02 CVE-2017-5645

漏洞版本

Log4j 2.x <= 2.8.1

具体分析

首先看TcpSocketServer.class#main,启动Log4j后,通过createSerializedSocketServer函数创建SocketServer后,进入socketServer.startNewThread()

1

在startNewThread()中,调用thread.start(),可以继续跟进到TcpSocketServer.class#run中

2

在run函数中首先进入while循环,判断socket是否关闭,之后使用this.serverSocket.accept()等待接收数据,再创建一个SocketHandler用来将收到的数据转换成ObjectInputStream对象。因此跟进TcpSocketServer.SocketHandler(clientSocket)

3

在SocketHandler函数中,首先通过构造函数包装返回一个ObjectInputStream对象给this.inputStream。之后在自身的run函数中直接将先前赋值的this.inputStream传入到TcpSocketServer.this.logEventInput.logEvents函数中,我们跟进

4

在logEvents函数内,进行反序列化inputStream.readObject()

5

利用方式

由于对传入的数据没有进行过滤,因此若存在,即可通过commons-collections的Gadget链直接实现反序列化漏洞。

 

0x03 CVE-2019-17571

漏洞版本

Log4j 1.2.x <= 1.2.17

具体分析

有了上个分析的基础,这个分析就比较好理解了。

进入到SimpleSocketServer.class#main中,开启SocketServer服务器后,会设置监听端口,之后accept等待并接收数据,获取到socket对象,之后进入到SocketNode中对获取的socket对象进行处理,我们跟进

6

在SocketNode类中,首先看构造函数:获取传入的socket后,类似于上面讲到的漏洞,将socket封装为ObjectInputStream对象给this.ois

7

之后我们跟进SocketNode类中的run函数。可以看到没有任何过滤措施,当获取的this.ois不为null时直接用readObject()进行反序列化,造成反序列化漏洞

8

利用方式

由于对传入的数据没有进行过滤,因此若存在,即可通过commons-collections的Gadget链直接实现反序列化漏洞,十分无脑。

 

0x04 结语

通过这次的分析,可以清楚的了解到Log4j漏洞版本存在的问题,以及分析漏洞的过程,尽管可能不会很容易存在Gadget的利用链,但是至少学会了分析以及一种思维方式。而且这更加说明了一个问题:用户的输入永远是不可信的,需要谨慎地处理。本文之后会更新Gadget链,谢谢。

(完)