[Security] Server-Side Request Forgery (SSRF) via Insecure JDBC Connection Testing

#900 · open · 0 comments

View on GitHub ↗

AnalogyC0de

# [Security] Server-Side Request Forgery (SSRF) via Insecure JDBC Connection Testing ## Identification - **Affected Version/Commit:** <= v2.7 (2026.04.21) ## CVE Description A Server-Side Request Forgery (SSRF) vulnerability exists in the database connection testing feature of elunez_eladmin. While connecting to remote databases is an intended business function, the application fails to implement proper network boundaries or strictly sanitize the JDBC URL. The application's weak blacklist filter (`sanitizeJdbcUrl`) attempts to block dangerous properties but can be bypassed. Consequently, an authenticated user with `database:testConnect` permissions can supply arbitrary internal IPs, restricted loopback addresses, or non-database ports. This abuses the application server as a confused deputy to probe internal network topologies, discover hidden services behind firewalls, and potentially trigger secondary vulnerabilities (like deserialization or arbitrary file read) via malicious JDBC parameters. ## Affected Component - **File(s):** - `me/zhengjie/modules/maint/rest/DatabaseController.java` - `me/zhengjie/modules/maint/utils/SqlUtils.java` - **Function / Method:** `DatabaseController.testConnect()`, `SqlUtils.testConnection()`, `SqlUtils.sanitizeJdbcUrl()` - **Entry Point:** POST `/api/database/testConnect` (JSON field: `jdbcUrl`) ## Reproduction Summary 1. Authenticate to the application with a user account having `database:testConnect` permissions. 2. Send a POST request to `/api/database/testConnect` with a payload specifying a restricted internal IP address, port, or malicious JDBC property that circumvents the weak blacklist (e.g., `jdbc:mysql://127.0.0.1:6379/test` to probe local Redis, or probing internal subnets `192.168.x.x`). 3. Observe the application's responses (success, timeout, or authentication error) which act as an oracle to enumerate internal network topology, proving the server can be abused to bypass network segmentation. ## Technical Details ```java // me/zhengjie/modules/maint/rest/DatabaseController.java (Line 101) @ApiOperation(value = "测试数据库链接") @PostMapping("/testConnect") @PreAuthorize("@el.check('database:testConnect')") public ResponseEntity<Object> testConnect(@Validated @RequestBody Database resources){ return new ResponseEntity<>(databaseService.testConnection(resources), HttpStatus.CREATED); } ``` ```java private static DataSource getDataSource(String jdbcUrl, String userName, String password) { DruidDataSource druidDataSource = new DruidDataSource(); String className; try { className = DriverManager.getDriver(jdbcUrl.trim()).getClass().getName(); // 第53行 } catch (SQLException e) { throw new RuntimeException("Get class name error: =" + jdbcUrl); } // ... jdbcUrl = sanitizeJdbcUrl(jdbcUrl); // 第68行 — 消毒在此处才执行 druidDataSource.setUrl(jdbcUrl); // ... } ``` ```java // me/zhengjie/modules/mrest/utils/SqlUtils.java (Line 211) // Proof of failed intended security: Only filters known parameters via weak blacklist, no host/port/loopback restrictions private static String sanitizeJdbcUrl(String jdbcUrl) { String[][] unsafeParams = { {"allowLoadLocalInfile", "false"}, {"allowUrlInLocalInfile", "false"}, {"autoDeserialize", "false"}, {"allowNanAndInf", "false"}, {"allowMultiQueries", "false"}, {"allowPublicKeyRetrieval", "false"} }; for (String[] param : unsafeParams) { jdbcUrl = jdbcUrl.replaceAll("(?i)" + param[0] + "=true", param[0] + "=" + param[1]); } return jdbcUrl; } ``` ```java // me/zhengjie/modules/mrest/utils/SqlUtils.java (Line 195) // The unsanitized/partially sanitized URL reaches the sink [SqlUtils.testConnection()] -> [DriverManager.getConnection(jdbcUrl, user, pass)] ``` ## Validation Notes - **Endpoint:** Verified at `DatabaseController.java:101`. - **Sink:** Verified at `SqlUtils.testConnection()` -> `DriverManager.getConnection()`. - **Validation Defect:** Verified at `SqlUtils.java:211-232`. `sanitizeJdbcUrl()` explicitly attempts to filter dangerous JDBC properties but uses a bypassable blacklist and lacks any destination scope restrictions (no protection against internal network/loopback access). ```

Comments