侧边栏壁纸
博主头像
why

一个主要敲代码,经常怼文章,偶尔拍视频的成都人。

  • 累计撰写 181 篇文章
  • 累计创建 11 个标签
  • 累计收到 88 条评论

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

why
why
2021-12-13 / 0 评论 / 0 点赞 / 379 阅读 / 4,691 字
温馨提示:
关注公众号why技术,第一时间接收最新文章。

你好呀,我是歪歪。

上周大家应该都被 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 层代理、不懂你的流量混淆,也笑他们连个复杂点的密码都记不住。

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

0

评论区