st404

导航

log4j2漏洞复现及漏洞分析

一、漏洞复现

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

  由于Apache Log4j2某些功能(lookup)存在递归解析功能,未经身份验证的攻击者通过发送特别构造的数据请求包,可在目标服务器上执行任意代码。

  实际受影响范围如下:

  Apache Log4j 2.x < 2.15.0-rc2

  JDK在11.0.1、8u191、7u201、6u211及以上的高版本,将一定程度上导致利用失败。

  复现环境:

  IDEA 2018 (用最新版的2022编译时弹不了,应该加了安全限制)

  JDK 1.8.0_144

  Log4j版本:2.13.3

  因为属于maven项目,直接通过pom.xml下载依赖组件即可:

 

 

 

 

 

 

  然后直接运行即可:

  选择的jdk版本为1.8

 

 

 

 

  然后先运行JNDIExploit,java -jar JNDIExploit-1.2-SNAPSHOT.jar -i IP地址

  

  最后点击右上角的run就行,最后运行结果如下图所示:

 

二、漏洞分析

  一般log4j2项目中会引用到两个组件包,log4j-api和log4j-core,log4j-api是日志接口,log4j-core是日志标准库。

  Log4j2的Lookup主要功能是通过引用一些变量,往日志中添加动态的值。这些变量可以是外部环境变量,也可以是MDC中的变量,还可以是日志上下文数据等。

  

  env:允许系统在全局文件(如 /etc/profile)或应用程序的启动脚本中配置环境变量,然后在日志输出过程中,查找这些变量。例如:${env:USER}。

  java:允许查找Java环境配置信息。例如:${java:version}。

  jndi:允许通过 JNDI 检索变量。

  log4j2中包含两个关键组件LogManager和LoggerContext。LogManager是Log4J2启动的入口,可以初始化对应的LoggerContext。LoggerContext会对配置文件进行解析等其它操作。

  常见的Log4J用法是从LogManager中获取Logger接口的一个实例,并调用该接口上的方法。运行下列代码查看打印结果。

  

  

  log4j2支持多种日志级别,通过日志级别我们可以将日志信息进行分类,在合适的地方输出对应的日志。哪些信息需要输出,哪些信息不需要输出,只需在一个日志输出控制文件中稍加修改即可。级别由高到低共分为6个:fatal, error, warn, info, debug, trace(堆栈)。

  

  

  当日志级别(调用)大于等于系统设置的intLevel的时候,log4j2才会启用日志打印。在存在配置文件的时候,会读取配置文件中<root level="error">值设置intLevel。当然我们也可以通过Configurator.setLevel("当前类名", Level.INFO);来手动设置。如果没有配置文件也没有指定则会默认使用Error级别,也就是200。

  在本次漏洞分析过程中日志等级为Level.LEVEL,它的intLevel()为200,而本环境中默认的日志级别为ERROR(200),如下图所示:

  

    

        

  

  转换器名称msg对应的插件实例MessagePatternConverter对于日志中的消息内容处理存在问题,在大多数场景下这部分是攻击者可控的。MessagePatternConverter会将日志中的消息内容为${prefix:key}格式的字符串进行解析转换,用来读取环境变量等

  传入的message会通过MessagePatternConverter.format(),判断如果config存在并且noLookups为false(默认为false),然后匹配到${则通过getStrSubstitutor()替换原有的字符串,比如这里的${java:os},如下图所示:

  

  

  属性占位符之Interpolator(插值器)

  log4j2中环境变量键值对被封装为了StrLookup对象。这些变量的值可以通过属性占位符来引用,格式为:${prefix:key}。在Interpolator(插值器)内部以Map<String,StrLookup>的方式则封装了多个StrLookup对象。

  这些实现类存在于org.apache.logging.log4j.core.lookup包下,可以看到处理event的时候根据前缀选择对应的StrLookup进行处理,目前支持date,jndi,java,main等多种类型,如果构造的event是jndi,则通过JndiLoopup进行处理,从而构造漏洞。如下图所示:

  

  使用${jndi:key}时,将会调用JndiLookup的lookup方法。

  因为JNDI支持从指定的远程服务器上下载class文件,加载到本地JVM中,并通过适当的方式创建对象,从而可以利用JNDI注入来执行命令。

三、利用条件

  在版本小于Apache Log4j 2.x < 2.15.0-rc2及JDK满足的情况下,还需以下两点:

  1、代码中日志等级的优先级高于或等于默认级别(ERROR(200),数值越低优先级越高)才可以成功。

  2、必须能够控制log方法中的参数内容。

四、修复方法

  在log4j2.component.properties配置文件,增加如下内容为:

  log4j2.formatMsgNoLookups=true

  或者删除jndilooup类文件

posted on 2022-09-28 08:50  st404  阅读(1307)  评论(0编辑  收藏  举报