Automne's Shadow.

Log4j反序列化漏洞分析

2020/02/11 Share

Web

Log4j使用示例

Apache Log4j是基于Java的日志记录工具。

在IDEA里使用Log4j日志组件。以log4j-1.2.17为例,创建java工程,并添加配置文件log4j.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
### 设置###
log4j.rootLogger = debug,stdout,D,E

### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到debug.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://Works/IDEAProjects/TestDemo2/logs/debug.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

### 输出ERROR 级别以上的日志到error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = D://Works/IDEAProjects/TestDemo2/logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

测试demo

automne

CVE-2017-5645

automne

可见该CVE的影响版本是Log4j的2.x – 2.8.2版本。在使用TCP/UDP 套接字接口监听获取序列化的日志事件时,存在反序列化漏洞。

测试环境:jdk 1.7 + log4j 2.8

测试demo

automne

运行该demo后TcpSocketServer将会在本地监听1337端口。因为Log4j本身并没有爆出可命令执行的反序列化gadget,所以这里使用commons-collections-3.1.jar的利用链,利用ysoserial生成payload再利用nc发送到1337端口上实现命令执行。

1
java -jar ysoserial-master-30099844c6-1.jar CommonsCollections1 "calc" > test.ser

automne

接下来开始漏洞分析。

跟入上面demo的main函数

上图可以看到引入了jcommander-1.48.jar,主要是main函数里的parseCommandLine需要。

automne

来到了org.apache.logging.log4j.core.net.server. TcpSocketServer里

automne

重点关注图中的标记处,可见创建了一个socketServer并且通过startNewThread启用了一个新进程。

automne

根据java中线程的生命周期,接下来在TcpSocketServer.class里寻找run函数

automne

于是接下来就是跟入这个SocketHandler里

automne

从上图的标记处可见首先调用了wrapStream打包输入流,接着将输入流传入到logEvents函数里,直接跟入这两个函数都是接口,所以需要寻找实现类。

automne

于是回到上面socketServer开始创建的地方,也就是createSerializedSocketServer函数里

automne

进到ObjectInputStreamLogEventBridge类里,看到了上面两个接口的实现方法

automne

从代码里可以看到,没有对外界可控的输入流做任何过滤直接传入readObject()进行反序列化,从而存在反序列化漏洞。

CVE-2019-17571

automne

该CVE的影响版本是Log4j的1.2 - 1.2.17版本。

测试环境:jdk 1.7 + log4j 1.2.17

测试demo

automne

注意这里的参数

automne

log4j.properties文件内容从网上找了一个

1
2
3
4
5
6
7
8
# Root logger option
log4j.rootLogger=INFO, stdout

# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

如果提示没有读取到配置文件,查看工作目录是否配置正确

automne

接下来开始漏洞分析

跟入main函数,可以看到这里建立了一个线程对象,并调用了SocketNode类对socket做了处理。

automne

跟入SocketNode类

automne

直接从socket里获取输入流并封装到ObjectInputStream对象中,然后在SocketNode.class找到run函数,直接调用了ObjectInputStream.readObject()进行反序列化。

automne

参考链接

https://www.anquanke.com/post/id/195932

https://mochazz.github.io/2019/12/26/Log4j%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%88%86%E6%9E%90/#CVE-2017-5645

https://blog.csdn.net/Evankaka/article/details/45815047

CATALOG
  1. 1. Log4j使用示例
  2. 2. CVE-2017-5645
  3. 3. CVE-2019-17571
  4. 4. 参考链接