2

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

 2 years ago
source link: https://segmentfault.com/a/1190000041114286
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

发布于 6 分钟前

你好呀,我是歪歪。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

https://www.bilibili.com/vide...

因为目前给出的解决方案,就是升级 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...

这个插件,香的一笔啊。

怎么安装就不介绍了,注意自己对应的 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/dub...

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

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

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

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

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

https://juejin.cn/post/694522...

首先是在前面纯净的 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...

修改一下 maven 就行:

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

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

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

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

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

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

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

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

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

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

https://www.whywhy.vip/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK