Log4j 漏洞
Log4j是什么
Log4j是Java社区中一个被开发者广泛使用的库,提供了一个简单但强大的框架,可用于记录错误信息、诊断信息等。
Log4j提供了很多让人印象深刻的功能,其中之一是将日志记录至多个目标位置,包括但不限于控制台、文件、远程TCP服务器、Syslog、NT Event Log以及电子邮件。此外,它还支持对日志消息、日志事件、自定义布局等内容进行分层过滤。
它的主要作用就是把重要信息输出到指定文件,以便于定位确定和验证解决一些实际问题。
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIXSyslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
黑客已经利用 Log4j 漏洞来接管受害者的计算机,以执行从加密货币挖矿、发送垃圾邮件、到通过大型僵尸网络发起分布式拒绝服务(DDoS)攻击的任何事情。
如何攻击?
log4j2的强大之处在于,除了可以输出程序中的变量,它还提供了一个叫Lookup的东西,lookup相当于是一个接口,可以用来输出更多内容,lookup,顾名思义就是查找、搜索的意思,那在log4j2中,就是允许在输出日志的时候,通过某种方式去查找要输出的内容。
假如某一个Java程序中,将浏览器的类型记录到了日志中:
logger.info(userAgent);
User-Agent
就属于外界输入的信息,而不是自己程序里定义出来的。只要是外界输入的,就有可能存在恶意的内容,假如有人发来了一个HTTP请求,他的User-Agent
是这样一个字符串:
${jndi:ldap://127.0.0.1/exploit}
接下来,log4j2将会对这行要输出的字符串进行解析,它发现了字符串中有 ${,要单独处理,发现是JNDI扩展内容,再对JNDI进一步解析,发现了是LDAP协议。LDAP服务器在127.0.0.1,要查找的key是exploit,然后调用具体负责LDAP的模块去请求对应的数据。
JNDI支持一个叫命名引用的方式,也就是JNDI可以远程下载class文件来构建对象,下载后加载起来构建对象,如果远程下载的URL指向的是一个黑客的服务器,并且下载的class文件里面藏有恶意代码,什么样的后果都可能出现,这是JNDI注入。
LDAP即Lightweight Directory Access Protocol(轻量级目录访问协议),目录是一个为查询、浏览和搜索而优化的专业分布式数据库,这个东西用在统一身份认证领域比较多,简单理解就是:一个类似于字典的数据源,你可以通过LDAP协议,传一个name进去,就能获取到数据。什么是JNDI?
作用类似于JDBC,JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,JDBC为工具/数据库开发人员提供了一个标准的API,据此可以构建更高级的工具和接口,使数据库开发人员能够用纯 Java API 编写数据库应用程序。JNDI(Java Naming and Directory Interface)是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口,类似JDBC都是构建在抽象层上。)如图:
攻击步骤
有关解决和修复
方式一:禁用lookup或JNDI服务
罪魁祸首就是lookup和JNDI,那么直接修改配置文件log4j2.formatMsgNoLookups=True或禁用JNDI服务,不过一般产生问题的服务都是线上已经在跑的服务,禁用的时候要注意评估一下是否允许。
方式二:升级新版本
新版的log4j2已经修复了这个问题,升级即可解决。修复后的log4j2在JNDI lookup中增加了很多的限制:
1.默认不再支持二次跳转(也就是命名引用)的方式获取对象
2.只有在log4j2.allowedLdapClasses列表中指定的class才能获取。
3.只有远程地址是本地地址或者在log4j2.allowedLdapHosts列表中指定的地址才能获取
这样处理等于是去掉了通过打印日志去远程加载class的方式。