log4j2远程执行漏洞原理以及解决方案

好久没更新博客了,因为最近实在是超级忙,最近Log4j2核弹级别漏洞被疯狂刷屏。

2021年12月9日,国内多家机构监测到Apache Log4j2存在任意代码执行漏洞,并紧急通报相关情况。由于Apache Log4j存在递归解析功能,未取得身份认证的用户,可以从远程发送数据请求输入数据日志,轻松触发漏洞,最终在目标上执行任意代码。鉴于Apache Log4j本身涉及多种应用组件,猿码优创将此漏洞威胁等级调整为:严重。

 目前经过不懈努力,猿码优创已经给复现了。

还给大家画了一个流程图:

产生原因:存在JNDI注入漏洞,当程序将用户输入的数据被日志记录时,即可触发此漏洞,成功利用此漏洞可以在目标服务器上执行任意远端代码。

我们来看一个简单的业务场景:

下面是一个登录页面:

 后端我们把用户谁登录了进行打印。

public void login(string name){
  logger.info("{},刚刚登录了猿码优创系统", name); //日志框架为:log4j2
}
输出结果为:yuanmayouchuang刚刚登录了猿码优创系统,这个就忽略演示了。

很简单的一个业务场景,但是如果在这个地方输入:{java:os}会发生什么呢?

执行:logger.info("${java:os}"); //logger为log4j
输出结果:Windows 10 10.0, architecture: amd64-64

 有没有感觉特别像SQL注入。

为什么会发生这样的事呢?

log4j2的强大之处在于,除了可以输出程序中的变量,它还提供了一个叫Lookup的东西,可以用来输出更多内容:

 lookup 翻译过来就是查找、搜索的意思。那么log4j2中,就是在输出日志的时候,通过方法去查找要输出的内容。相当于一个接口,具体去哪里找,怎么找找,就需要编写具体的代码去实现,就相当于java中的多态差不多意思。

log4j2提供了很多查找方法:

 我们主要看一下本次漏洞的罪魁祸首:JNDI 什么是JNDI?它是干嘛的??我们问一下百度百科。

 以上看的是不是超级懵,看看上面咱们做的那个实验,传参为:${java:os} 输出计算机系统名称,相当于类似于一个字典的数据源,通过传参,然后找字典然后输出相应的信息。

这个时候小伙伴就有想了,跟我有什么关系,输出系统变量,不会引起很大的事故吧。最多欺骗日志输出,能引起什么腥风血浪。

别急,听猿码优创给你慢慢道来。JNDI 既然相当于一个字典,那里面有很多数据源。

 其中有一个数据源就是本次漏洞的受害者,那就是LDAP

什么是LDAP?我们先问问百度百科。

 what????怎么看了一脸懵逼。

有没有在一些开源系统中看到过这个单词LDAP登录。

LDAP是开放的Internet标准,支持跨平台的Internet协议,在业界中得到广泛认可的,并且市场上或者开源社区上的大多产品都加入了对LDAP的支持,因此对于这类系统,不需单独定制,只需要通过LDAP做简单的配置就可以与服务器做认证交互。“简单粗暴”,可以大大降低重复开发和对接的成本。

这样说能明白了不?再举个例子,比如你们公司购买了一个OA系统,但是呢你们原来有自己的域账户,这个时候OA系统厂家不会为你们单独改造一套系统出来,这样成本太大,这个时候LDAP就派上了用场,通过简单配置,就可以用域账户登录购买的OA系统。但是简单配置相当于是远端加载了一些信息。

来上面两个 lookup和LDAP大家有没有一个简单的了解。好我们来说这次的漏洞原理。

这个时候我们还是用代码举例子。

 @GetMapping(value = "/test")
    public String test(String info) {
        //执行远程代码
        logger.error("----------------log4j漏洞演示--------------------");
        logger.info(info); //logger为log4j
        return "success";

    }
这个时候我们info传递:${jndi:ldap://127.0.0.1:3001/}

这个时候log4j一发现${} 这个时候里面的信息就是要单独处理的。

发现是JDNI扩展内容:${jndi:ldap://127.0.0.1:3001/yuanmayouchuang} ldap服务器在127.0.0.1 直接查找key是:yuanmayouchuang 然后查找完毕去返回相应的数据。

如果是普通的数据那就没什么?问题就是出现在可以请求java对象!启动完项目 Java对象一般只存在于内存中,但也可以通过序列化的方式将其存储到文件中,或者通过网络传输。但更危险的在于:JNDI还支持一个叫命名引用(Naming References)的方式,可以通过远程下载一个class文件,然后下载后加载起来构建对象。

注意:这里就是核弹级别漏洞问题了:JNDI可以远程下载class文件来构建对象!!!

就是下载的class(java编译后的代码)如果里面有恶意代码这不完蛋了吗?

 一句话总结漏洞:就是该输出日志的地方执行了远端服务器恶意Class代码

互联网流传一句话:永远不要相信用户的输入的内容。

修复方案:Log4j2修复方案官方地址https://logging.apache.org/log4j/2.x/security.html

Log4j2废弃解决方案(在2021年12月15日官方推翻)
版本号 解决方案
2.10-2.14版本 系统属性 log4j2.formatMsgNoLookups 或环境变量 LOG4J_FORMAT_MSG_NO_LOOKUPS 设置为 true
2.7-2.14.1之间的版本 设置log4j2.xml的%m为 %m{nolookups}
2.10以下版本 删除org/apache/logging/log4j/core/lookup/JndiLookup.class这个类

 哎呀,大家很幸运,然后今天我打开log4j官方发现昨天的翻译就是我上面发的给推翻了。。。

这是最新的解决方案:升级到最新2.0.16版本

log4j2.0.16 core版本 pom文件: https://mvnrepository.com/artifact/org.apache.logging.log4j
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.16.0</version>
</dependency>
log4j2.0.16 api版本 pom文件: https://mvnrepository.com/artifact/org.apache.logging.log4j
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.16.0</version>
</dependency>

到此本文就介绍完毕了。

稍后我会把LDAP模拟攻击源码发出来了,需要大家遵守以下协议。

源码是针对Log4j2超高危RCE漏洞`CVE-2021-4428`的复现DEMO,目的是认识该漏洞的危害性并根据您系统的情况做出针对性的防御。
警告---重要
本DEMO只是针对技术层面的研究,不涉及恶意远程计算机侵入方面的相关脚本。请勿利用漏洞进行非法侵入他人计算机的违法活动。否则您将可能承担以下侵权责任:

1. 根据《中华人民共和国治安管理处罚法》第二十九条 对违反国家规定,侵入计算机信息系统,造成危害的,处五日以下拘留;情节较重的,处五日以上十日以下拘留。
2. 根据《中华人民共和国刑法》第二百八十五条第一款的规定,犯本罪的,处三年以下有期徒刑或者拘役。单位犯本罪的,对单位判处罚金,并对其直接负责的主管人员和其他直接责任人员,依照上述规定处罚。
请勿用于非法用途,否则将承担相应的法律责任。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>