CVE-2021-45105:Log4j2 拒绝服务漏洞分析
报告编号:B6-2021-122201
报告来源:360CERT
报告作者:360CERT
更新日期:2021-12-22
漏洞简述
2021 年 12 月 20 日,360CERT 监测发现Apache 官方
发布了Apache Log4j
的风险通告,漏洞编号为CVE-2021-45105
,漏洞等级:高危
,漏洞评分:7.5
。目前官方已发布安全版本。这是最近在 Log4J 中发现的第三个安全漏洞。
Apache Log4j 是一个基于 Java 语言开源的日志框架,已于 2015 年 8 月 5 日停止维护。Log4j2 是其重构升级版本,引入了大量丰富的特性,可以控制日志信息输送的目的地为控制台、文件、GUI 组件等,并通过定义每一条日志信息的级别,使其能更加细致地控制日志的生成过程。
对此,360CERT 建议广大用户及时将Apache Log4j
升级到最新版本。与此同时,请做好资产自查以及预防工作,以免遭受黑客攻击。
风险等级
360CERT 对该漏洞的评定结果如下
评定方式 | 等级 |
---|---|
威胁等级 | 高危 |
影响面 | 有限 |
攻击者价值 | 高 |
利用难度 | 高 |
360CERT 评分 | 7.5 |
影响版本
组件 | 影响版本 | 安全版本 |
---|---|---|
Apache Log4j | 2.0-alpha1 ~ 2.16.0 | 2.17.0 , 2.12.3 , 2.3.1 |
漏洞详情
该漏洞需要在特定的配置下才能进行利用,当PatternLayout
使用$${ctx:xxx}
从context
上下文获取用户输入的时候才能进行利用。相关配置参考:
https://logging.apache.org/log4j/2.x/manual/lookups.html
测试的配置文件为:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d %p %c{1.} [%t] $${ctx:loginId} %m%n"/> </Console> </Appenders> <Loggers> <Root level="error"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
在初始化Logger
对象的时候,PatternParser
会解析配置文件,解析之后将${ctx:loginId}
赋值给LiteralPatternConverter
。
接着看到PatternLayout#toSerializable
方法,遍历converter
。
@Override public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) { for (LogEventPatternConverter converter : converters) { converter.format(event, buffer); } return buffer; }
MessagePatternConverter
已经删除了lookup
的converter
if (LOOKUPS.equalsIgnoreCase(option) || NOLOOKUPS.equalsIgnoreCase(option)) { LOGGER.info("The {} option will be ignored. Message Lookups are no longer supported.", option); }
将目光放在LiteralPatternConverter
,依然会对表达式进行解析,解析的是literal
,也就是${ctx:loginId}
。
public void format(final LogEvent event, final StringBuilder toAppendTo) { toAppendTo.append(substitute ? config.getStrSubstitutor().replace(event, literal) : literal); }
跟到replace
里,调用StrSubstitutor#substitute
。
解析逻辑
这里会提取${
到第一个}
之间的字符串,ctx:loginId
,接着调用StrSubstitutor#resolveVariable
String varValue = resolveVariable(event, varName, buf, startPos, endPos); ... protected String resolveVariable(final LogEvent event, final String variableName, final StringBuilder buf, final int startPos, final int endPos) { final StrLookup resolver = getVariableResolver(); if (resolver == null) { return null; } return resolver.lookup(event, variableName); }
lookup
里尝试获取协议,这里是没有jndi
协议的,默认情况下已经不提供了。
这里是调用ContextMapLookup#lookup
,这里调用event.getContextData()
public String lookup(final LogEvent event, final String key) { return event.getContextData().getValue(key); }
这里的contextData
就是官方通告所说的攻击者需要能控制Thread Context Map
里面的内容,可以参考官方文档:
https://logging.apache.org/log4j/2.x/manual/thread-context.html
我们看到 3,put
的是session
里的loginId
,而配置文件里是${ctx:loginId}
,key
是一样的,于是在调用event.getContextData().getValue(key)
时,就会提取到攻击者输入的loginId
赋值给varValue
。 如果varValue
不为null
,继续解析。
String varValue = resolveVariable(event, varName, buf, startPos, endPos); if (varValue == null) { varValue = varDefaultValue; } ... if (varValue != null) { // recursive replace final int varLen = varValue.length(); buf.replace(startPos, endPos, varValue); altered = true; int change = substitute(event, buf, startPos, varLen, priorVariables); ... }
substitute
递归解析攻击者输入的内容,在checkCyclicSubstitution
方法里:
private void checkCyclicSubstitution(final String varName, final List<String> priorVariables) { if (!priorVariables.contains(varName)) { return; } final StringBuilder buf = new StringBuilder(BUF_SIZE); buf.append("Infinite loop in property interpolation of "); buf.append(priorVariables.remove(0)); buf.append(": "); appendWithSeparators(buf, priorVariables, "->"); throw new IllegalStateException(buf.toString()); }
这里priorVariables
和varName
的获取规则,以 DOS 漏洞的 poc 为例,递归完之后,退出递归的第一层,得到的是::-${::-j}
。
这里会去匹配:-
,:-
之前的部分就是varName
,即:
,而:-
之后的就是value
,即${::-j}
。
然后,将这一次去掉${}
之前的内容存到priorVariables
里,即::-${::-$${::-j}}
,然后调用checkCyclicSubstitution
方法,检测varName
是否在priorVariables
里,这里就是无限递归的关键点,如果存在,那么就会抛出无限递归错误。
接着看代码
//此时,varName是:,无法解析出协议,即varValue赋值null String varValue = resolveVariable(event, varName, buf, startPos, endPos); if (varValue == null) { //varDefaultValue 是 ${::-j} varValue = varDefaultValue; } if (varValue != null) { // recursive replace final int varLen = varValue.length(); buf.replace(startPos, endPos, varValue); altered = true; //继续递归,注意这里和之前递归提取`${}`内部字符串是不一样的,传入了赋值的priorVariables,递归`${}`内部的字符串时,priorVariables不传,也就是null int change = substitute(event, buf, startPos, varLen, priorVariables); change = change + (varLen - (endPos - startPos)); pos += change; bufEnd += change; lengthChange += change; chars = getChars(buf); // in case buffer was altered }
于是很明显了,在继续递归之后,在解析::-j
的时候也会解析出varName
是:
,而priorVariables
里已经有:
了,就会抛出无限递归的错误。
多次请求后,会导致 log4j 日志记录进程崩溃,无法继续日志记录。
漏洞修复
在 2.17.0 版本中对该漏洞进行了修复,diff 如下:
跟一下isRecursiveEvaluationAllowed
方法。
默认为false
,即不会再进行递归解析。
时间线
2021-12-20 360CERT 发布预警通告
2021-12-22 360CERT 发布分析报告
参考链接
1、 CVE-2021-45105:Apache Log4j 拒绝服务漏洞通告
https://cert.360.cn/warning/detail?id=4e4427335861d0c101b5311c79f87217

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
开源操作系统社区 OpenCloudOS 成立,将成为开放原子开源基金会一员
开源操作系统社区 OpenCloudOS 于今日宣布成立,该社区由腾讯与其合作伙伴共同倡议发起。首批创始单位包括:腾讯及宝德、北京初心、北京红旗、飞腾、浪潮、龙芯中科、OPPO、先进开源、中电科申泰、中科方德、兆芯等 20 余家操作系统生态厂商及用户。 根据介绍,该社区致力于打造一个完全中立、全面开放、安全稳定、高性能的操作系统及生态。完全中立,意味着社区不存在厂商标签,也不由任何一个单独的厂商主导;完全开放,意味着能够聚集起国内外的操作系统研发力量、社区成员共识决策、产学研用共建生态。 背靠腾讯及多家厂商,OpenCloudOS 在云原生、稳定性、性能、硬件支持等方面有一定的技术支撑,可以平等全面地支持所有硬件平台。按照规划,OpenCloudOS 将成为开放原子开源基金会的一员,由基金会托管和监督,以标准开源社区模式运作,保持中立和开放,社区也将由参与单位共同治理。 在技术路径上,各方希望采取头部操作系统厂商联合研发模式,共同建设 OpenCloudOS。开发稳定的操作系统社区版本,保障国产研发供应链安全;同时支持操作系统厂商基于社区稳定版本构建衍生商业版本。 腾讯方面透露,Ope...
- 下一篇
建木:做更好的开源社区,让DevOps更简洁
【51CTO.com原创稿件】“建木”是上古先民崇拜的一种圣树。传说建木是沟通天地人神的桥梁。伏羲、黄帝等众帝都是通过这一神圣的梯子上下往来于人间天庭。《淮南子·��形训》亦曰:“建木在都广,众帝所自上下。日中无景,呼而无响,盖天地之中也。”为此项目命名为“建木”,希望本项目也可以成为不同业务场景下系统间相互沟通的桥梁。建木自动化平台以触发器、流程编排、任务分发等功能为平台核心,可以应用在各类使用场景下,包括但不限于,CI/CD、DevOps、自动化运维、多业务系统集成等场景的自动化。 作为中国最早一批从事“开放云边基础架构技术开发和服务”的专业公司,九州云始终以“开源·赋能云边变革”为核心,坚持自主研发,建立了完整的“云+边”生态体系和解决方案。目前,九州云可以为企业客户提供全栈开放基础架构解决方案。在云侧,九州云有涵盖IaaS云、CaaS云、多云管理、自动化运维平台AutoOps、SD-WAN等的企业云解决方案;在边缘侧,有涵盖边缘中心管理、边缘区域管理、边缘管理、Open UPF、轻量化核心网、边缘场馆/娱乐等的边缘云解决方案。 凭借自身的技术优势,九州云深度参与了OpenSta...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Red5直播服务器,属于Java语言的直播服务器
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- 2048小游戏-低调大师作品
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Docker安装Oracle12C,快速搭建Oracle学习环境