写点什么

我也想说说日志,但是我不想说漏洞。

作者:why技术
  • 2021 年 12 月 14 日
  • 本文字数:3897 字

    阅读完需:约 13 分钟

我也想说说日志,但是我不想说漏洞。

你好呀,我是歪歪。


上周大家应该都被 log4j 的日志漏洞给刷屏了吧?


我看到这个漏洞的时候注意到它有“影响范围非常广,且上手难度低”的特点。


我就想验证一下上手难度到底有多低,于是我翻了很多文章,都是大同小异,说出漏洞了,很牛逼,赶紧修吧,晚了就玩完啦。然后配上一个唤起了计算器的截图,就结束了,也没有人告诉我到底怎么玩啊。


我也想唤起计算器,学(装)习(装)(逼)下。


于是我在网上查了一系列资料,四处摸索。从找资料到完成攻击大概花了一个小时左右的时间。


当时我就震惊了:这玩意上手难度确实很低啊!



本来开始我还是想写写关于漏洞的复现,但是写着写着打消了这个念头。


首先我即使复现了,也还是不太懂它的工作原理是什么。我只知道是可以通过 JNDI 的方式加载攻击者的类,而这个类由于是攻击者编写的,里面就可以搞很多事情了。


你想想,我能在你的代码环境里面执行我写的一些代码,哪怕我再不知道怎么攻击,我写个死循环,写个 sleep 语句也能玩死你了啊。


如果是实在想写出有价值的文章,研究的方向可以去看看 JNDI 相关的技术。


但是我觉得我卷不动了,所以就不写了。


其次我查了一下,还不能写的太详细,毕竟是漏洞,传播其复现方法也不太好,似乎还涉及到法律问题,所以大家知道怎么防范就好。


再说了,这是安全那一帮人干的事儿啊,我不想去卷他们的饭吃。



最后,其实我发现 B 站上已经有比较详细的视频演示了。贴个链接,只是我不知道这个视频还能被保留多久:


https://www.bilibili.com/video/BV1FL411E7g3


因为目前给出的解决方案,就是升级 jar 包嘛,所以这篇文章我主要给大家介绍一个插件吧,能在一定程度上提升大家的升级速度。


我平时也用它,用顺手了后,香的一比。

sb 的日志

我没有骂人啊,我是想说 SpringBoot 的日志。


现在大家的应用都是基于 SpringBoot 去构建的,那么 SpringBoot 默认的日志框架是什么呢?


我也不知道,所以我准备搭建一个纯净的 SpringBoot 项目来看一眼。


又多纯净呢?


就是我通过 IDEA 构建新项目的时候,除了指定 SpringBoot 版本号为 2.6.1 外,没有引入其他的任何的包。



然后,我们看一下 pom 文件,东西非常的少:



确实纯净啊,和纯净水似的。


接着我们把项目启动起来:



你看啊,神奇的事情就出现了,我一行代码都没动呢,什么都还没配置,日志就自动打出来了。


所以之前我从来没有注意到,但是这次的事件让我想到了这个问题:


SpringBoot 默认的日志框架是什么呢?


我想到的第一个方法是这样的:



隔着搁哪的猜啥啊,能用代码解决的问题就少哔哔,加两行日志打印一下不就完事了吗?


从输出我可以知道,哦,原来用的是 logback 啊。


其他的方法

除了前面这个方法之外,还有什么办法能知道是 logback 呢?


于是我紧接着想到了查看 pom 依赖图。


在 IDEA 里面,有个一键查看 pom 依赖图的方式,特别简单。


就是在 maven 标签里面点这个图标就可以了:



如果你找不到这个图标,也可以在 pom 文件里面右键,然后依次选择 Maven->Show Dependencies:



然后你就会看到这样的一个界面,里面有 logback-core 包,说明引入了 logback 日志的实现:



有的小伙伴就要问了:我看依赖里面不是还有一个 log4j-api 吗?你凭什么说不是用的 log4j 呢?


老铁,只有 api 没有 core 包啊,核心实现都在 core 包里面的。


比如这次 log4j 爆出问题的代码,也就是 lookup 那块的逻辑,就都在 core 包里面。


但是为什么修复的建议是让我们同时排出 log4j-api 和 log4j-core 呢?


我个人浅显的认为是 core 都不用了, api 留着意义也不大吧。如果只有 log4j-api 的依赖,根据我掌握的攻击原理,是不会有问题的。


好了,先不扯远了,说回这个纯净的 SpringBoot 项目。


我前面给你说的看依赖图的方式,其实我一般不用。


为什么呢?


因为在真实的项目里面,依赖关系可能是极其复杂的,看起来密密麻麻的,你没有任何想看的欲望,比如给大家看看 dubbo 项目的 pom 依赖图,非常的刺激,非常的有冲击感啊:



到这里,我们先思考一个问题:你一般打开 pom 文件是干啥?


是不是在排查 jar 包冲突或者找 jar 包的时候需要用到?


所以在前面的页面里面可以按了 Ctrl+F 之后进行搜索,就像这样:



但是你去用的时候其实真的还是很不好用的。


于是乎,我要给你介绍的插件就来了。


https://plugins.jetbrains.com/plugin/7179-maven-helper



这个插件,香的一笔啊。


怎么安装就不介绍了,注意自己对应的 IDEA 版本就行。


主要给大家看看它怎么用的。


安装好了之后,你再次打开 pom 文件,可以看到下面有个这个东西:



里面是长这样的:



我们主要关注这个地方,我把注释也给你写上:



这个里面,主要就是用到两个核心功能。


  • 排查依赖冲突。

  • 查询 jar 包依赖。


比如,我们看一下我们这个纯净的项目里面和 log 相关的包:



一目了然,我们也看到了前面提到的 logback-core 包。

实战演练

光说不练假把式,接下来给大家来个使用 maven-helper 的实战演练。


比如我们就拿 Dubbo 开刀,用起来其实非常简单的。


就拿这次 log4j 漏洞事件来说,我们要排查出项目里面所有的 log4j-api 和 log4j-core 包。


我选择 Dubbo 项目里面的这个模块来做演示吧:



比如先打开 autoconfigure 包下面的 pom 文件:



然后搜一下 log4j:



可以看到 log4j-api 是由 spring-boot-starter-logging 引入进来的。


在这里右键,然后点击 Exclude 即可排出:



刷新依赖,再次查询就没了:



就是这么的简单,其他的模块也都是这样,我就不一一演示了。


但是有个问题出现了, Dubbo 作为中间件,排出了之后就不能不管了呀,还得引入一个新的安全版本进来。


我们可以看一下 Dubbo 这次对于 log4j 漏洞提交的 pr:


https://github.com/apache/dubbo/pull/9378/files



可以看到排除了 log4j-api 同时也引入了一个新版本的 log4j-api。


版本号放在了父 pom 里面,实现了对版本的统一管理:



如果后续还需要升级 log4j-api 只需要调整父 pom 里面的版本号就行。


再来一个

再给大家来一个例子,演练一下。


这个例子借鉴于这个链接里面:


https://juejin.cn/post/6945220055399399455


首先是在前面纯净的 SpringBoot 项目中多引入了 Dubbo 的包,然后引入了 zookeeper 作为注册中心:


<dependencies>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter</artifactId>    </dependency>    <dependency>        <groupId>org.apache.dubbo</groupId>        <artifactId>dubbo-spring-boot-starter</artifactId>        <version>2.7.9</version>    </dependency>    <dependency>        <groupId>org.apache.dubbo</groupId>        <artifactId>dubbo-registry-zookeeper</artifactId>        <version>2.7.9</version>    </dependency></dependencies>
复制代码


同时,记得在 application.properties 文件里面加上这行配置,否则启动不起来:


dubbo.application.name=xxx


启动的时候你可以看到这样的提醒日志:



怎么样,是不是很眼熟?在大多数的项目启动的时候都遇到过?


上面的提醒日志可以分为两组,一组是 SLF4J,一组是 log4j。


很多人都知道这个问题肯定是出现依赖冲突,日志框架混乱。


所以首先我们再看一下项目里面的日志依赖,看到有一个 log4j 的依赖冲突:



二话不说,先右键给它排掉,在 pom 文件里面就是这样体现的:



但是需要注意的是,我们不能直接就把 log4j 包删除了就不管了,这里引用了说明项目里面使用了 log4j,因此我们需要把 log4j 桥接到 slf4j 上,从而达到排除了 log4j ,但是日志还能正常打印的目的:


<!--增加log4j-slf4j --><dependency>    <groupId>org.slf4j</groupId>    <artifactId>log4j-over-slf4j</artifactId>    <version>1.7.30</version></dependency>
复制代码


再次启动项目,你就发现,只剩下 SLF4J 这一个问题了:



再次打开依赖分析:



可以发现项目同时拥有了 slf4j-log4j12 和 log4j-to-slf4j,另外还有个 logback 的存在。


所以,项目里面共存了两套 slf4j 的实现,分别是 log4j 和 logback。


其实这一点,从日志中也可以看出来:



日志提醒你了:Class path contains multiple SLF4J bindings.


两套实现,在项目启动的时候先加载那个就使用哪个,这是很不靠谱的事情。


根本的解决方案就是排除其中的一个。


比如我们还是使用默认的 logback,那就排除 slf4j-log4j 这个依赖。


再次启动项目,之前的冲突日志都没有了,舒服了:



好,那么如果我不想用 logback,就想用牛逼的 log4j 怎么办呢?


https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto.logging.log4j


修改一下 maven 就行:



从日志打印就知道了,现在的实现是 log4j。


然后,关于 log4j 这个漏洞,我想说,日志就干好日志的事儿,弄这么多复杂的功能干啥呢?完成 KPI 啊?


说真的,在这个漏洞被爆出来之前,我都不知道它还有这些高级的功能呢,我寻思好像也用不到啊。


感觉就很像是有人特意留下的后门,这就细思极恐了,以及脑补了一场大戏。


最后,看到一个段子,送给大家。


快过年了,不要再讨论什么 log4j、cs、bypass、流量检测之类的了。


你带你的破电脑回到家并不能给你带来任何实质性作用,朋友们兜里掏出一大把钱吃喝玩乐,你默默的在家里摆弄你的破烂 rce。


亲戚朋友吃饭问你收获了什么,你说我装了个虚拟机,把各个工具都玩了一遍,亲戚们懵逼了,你还在心里默默嘲笑他们,笑他们不懂你的自动注入,不懂你的 10 层代理、不懂你的流量混淆,也笑他们连个复杂点的密码都记不住。


你父母的同事都在说自己的子女一年的收获,儿子买了个房,女儿买了个车,姑娘升职加薪了,你的父母默默无言,说我的儿子搞了个破电脑,开起来嗡嗡响、家里电表走得越来越快了。



本文已收录至个人博客,欢迎大家来玩。


https://www.whywhy.vip/

发布于: 2021 年 12 月 14 日阅读数: 8
用户头像

why技术

关注

公众号[why技术],一头风骚的程序猿。 2019.10.16 加入

在这里我会分享一些java技术相关的知识,用匠心敲代码,对每一行代码负责。感谢你的关注,愿你我共同进步。同时也是公众号[why技术]号主。

评论

发布
暂无评论
我也想说说日志,但是我不想说漏洞。