每次出现大规模漏洞,JNDI似乎都不会缺席。最近广为人知的Log4j2漏洞也与它有关,让人怀疑是不是作者开的后门。因为JNDI,别说用过,很多人连听都没听过。这么冰冷的东西,为什么要放在一个日志框架里呢?恐怕也只有笔者自己想得通了。数据库驱动很多人接触JNDI,都是从数据库的驱动开始的。当然,随着SpringBoot单一发布模式的流行,使用这种方式获取数据库配置的古董公司越来越少了。比如我们可以在tomcat的server.xml中配置一个名为xjjdogDB的资源。然后,我们只需要在SpringBoot中配置名称JNDI,它就可以加载正确的配置。前提是我们需要将SpringBoot服务打包成WAR包发布。像JBoss这样号称是企业级服务器的软件就喜欢干这个。spring:datasource:jndi-name:jdbc/xjjdogDB从这里可以看出。JNDI到底是什么?你可以把它想象成一个配置中心,或者一个命名服务。它的基本功能是让你通过一个简短的字符串获取一系列复杂的配置和初始化函数。这样我们就可以避免直接在项目中写这些配置。程序启动时,加载什么取决于运行环境中配置的内容。具体实现上,不就是一个根据key取值的HashMap吗。危险来自于这个关键是这个值,它不是一个String,它是一个Object。从字符串变成普通类,又要通用,就得靠反射。这张图是Oracle官方对JNDI的介绍。以上都不是关键。关键是JNDI可以通过SPI机制与LDAP、RMI等各种技术进行交互。任何不按规矩追求便利的轻松访问都会产生问题。SPI是为数不多的打破Java类加载机制的技术之一。与Unsafe类一样,它功能强大但不推荐使用。如上图,就是NamingManager类中的方法getObjectFactoryFromReference。当它从本地加载相应的类时,如果加载不出来,它就做了一件不该做但又不得不做的事情,那就是从网络上的代码构造对应的对象!现在,秀肌肉的同时,就结束了。如上所示,我们只需要在8000端口启动一个nginx即可。或者直接用python启动一个小web服务器。python-mhttp.server8000可以向外网发起请求的服务器,会乖乖自动从我们指定的服务器上取非法的类文件进行加载。制作这些攻击性有效载荷也非常容易。有marshalsec之类的工具,可以很方便的生成。根据java的类加载机制,在静态代码块中,可以做一些实际的代码执行逻辑。我们只需要把编译好的放上去。它应该放置的类,JNDI可以加载它。publicclassa{static{try{String[]cmd={"calc.exe"};java.lang.Runtime.getRuntime().exec(cmd).waitFor();}catch(Exceptione){e.printStackTrace();}}}上面的代码将在您部署的服务器上启动一个计算器。当然,它可以做得更多。END从上面可以看出,Java的反射很强大,但是也很危险。SPI函数继承了这个特性,也勇敢地暴露了它的弱点。我觉得这个功能很好,但是为什么会存在于日志框架中呢?这可能是因为音量。毕竟一个日志框架也有元宇宙的梦想!