考试太忙啦,我写这篇文章的时候这个惊天大洞已经快凉透了

1 前置知识

1.1 Apache Log4j2

Apache Log4j2 是一款优秀的 Java 日志框架。该工具重写了 Log4j 框架,并且引入了大量丰富的特性。该日志框架被大量用于业务系统开发,用来记录日志信息。大多数情况下,开发者可能会将用户输入导致的错误信息写入日志中。

在Log4j2中,可以使用了lookup来查找、搜索内容,下面的东西它都能搜到,功能很强大

来自log4j的官网:https://logging.apache.org/log4j/2.x/manual/lookups.html

1.2 JNDI

JNDI即Java Naming and Directory Interface(JAVA命名和目录接口),它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象。

1.3 LDAP

LDAP即Lightweight Directory Access Protocol(轻量级目录访问协议),目录是一个为查询、浏览和搜索而优化的专业分布式数据库,它呈树状结构组织数据,就好象Linux/Unix系统中的文件目录一样。目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以目录天生是用来查询的,就好像它的名字一样。

2 漏洞详情

2.1 影响版本

Apache Log4j 2.x <= 2.14.1

Minecraft 全版本所有系列服务端,除 Mohist 1.18 外

2.2 攻击检测

可以通过检查日志中是否存在”jndi:ldap://“, “jndi:rmi“等字符来发现可能的攻击行为。

2.3 安全建议

  1. 升级 Apache Log4j2 所有相关应用到最新的 log4j-2.15.0-rc1 版本,https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc1
  2. 升级已知受影响的应用及组件,如 spring-boot-strater-log4j2 / Apache Solr / Apache Flink / Apache Druid

建议同时采用如下临时措施进行漏洞防范:

  • 1)添加 jvm 启动参数-Dlog4j2.formatMsgNoLookups=true
  • 2)在应用 classpath 下添加 log4j2.component.properties 配置文件,文件内容为 log4j2.formatMsgNoLookups=true
  • 3)JDK 使用 11.0.1、8u191、7u201、6u211 及以上的高版本;
  • 4)部署使用第三方防火墙产品进行安全防护。
  • 5)将系统环境变量 FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 设置为 true
  • 6)尽快升级Apache Log4j2所有相关应用到最新的 log4j-2.15.0-rc2 版本,地址 https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc2

3 漏洞原理——JNDI注入攻击

假如某一个Java程序中,将浏览器的类型记录到了日志中:

String userAgent = request.getHeader("User-Agent");
logger.info(userAgent);

假如有人发来了一个HTTP请求,他的User-Agent是这样的字符串:

${jndi:ldap://127.0.0.1/exploit}

接下来,log4j2将会对这行要输出的字符串进行解析。

首先,它发现了字符串中有 ${},知道这个里面包裹的内容是要单独处理的。

进一步解析,发现是JNDI扩展内容。

再进一步解析,发现了是LDAP协议,LDAP服务器在127.0.0.1,要查找的key是exploit。

最后,调用具体负责LDAP的模块去请求对应的数据。

如果只是请求普通的数据,那也没什么,但问题就出在还可以请求Java对象!

而JNDI还支持一个叫命名引用(Naming References)的方式,可以通过远程下载一个class文件,然后下载后加载起来构建对象。

4 漏洞复现

别看了,还没写呢

5 漏洞修复

https://logging.apache.org/log4j/2.x/manual/lookups.html#JndiLookup

修复后的log4j2在JNDI lookup中增加了很多的限制:

1.默认不再支持二次跳转(也就是命名引用)的方式获取对象

2.只有在log4j2.allowedLdapClasses列表中指定的class才能获取。

3.只有远程地址是本地地址或者在log4j2.allowedLdapHosts列表中指定的地址才能获取

彻底封锁了通过打印日志去远程加载class的方式

6 参考资料