chennbnbnb opened a new issue, #12215:
URL: https://github.com/apache/inlong/issues/12215

   ### What happened
   
   
   INLONG-11731 / PR #11732 hardened `MySQLSensitiveUrlUtils` (case-insensitive 
matching and the `yeſ` long-s variant) for the **MySQL** sink entry. However, 
the **OceanBase** sink entry never passes the JDBC URL through any 
sensitive-parameter filter at all, and the URL is forwarded verbatim to the 
Flink JDBC connector. A tenant user who creates/updates an OceanBase sink can 
therefore transport `autoDeserialize=true` (and other dangerous Connector/J 
parameters) end-to-end and trigger Java deserialization in the Sort runtime.
   
   Root cause chain (all verified against released artifacts):
   
   1. `inlong-manager/manager-pojo/.../sink/oceanbase/OceanBaseSinkDTO.java`
      `getFromRequest(...)` never calls `filterSensitive(...)` — although its
      `@apiNote` explicitly says "filter sensitive params before saving". The 
raw
      attacker-controlled URL is stored in the sink config.
   2. `inlong-sort/sort-common/.../node/load/OceanBaseLoadNode.java`
      `tableOptions()` does `options.put("url", url)` verbatim (line ~89).
   3. `jdbc-inlong` connector (Flink 1.15/1.18) `JdbcDynamicTableFactory`
      passes the URL to Connector/J without any runtime scrubbing
      (`JdbcUrlUtils.replaceInvalidUrlProperty` exists only in the 1.13 module,
      and even that only replaces the exact string `autoDeserialize=true`;
      `autoDeserialize=yes` survives it).
   4. With `autoDeserialize=true`, Connector/J auto-deserializes Java-serialized
      BLOB values on `ResultSet.getObject()`. If the Sort classpath contains a
      usable gadget chain, this is RCE in the Flink TaskManager.
   
   The Manager-side MySQL entry (`MySQLSinkDTO.getFromRequest`) does call
   `filterSensitive`, so the OceanBase entry is the gap left by PR #11732 —
   `OceanBaseJdbcUtils.establishDatabaseConnection` (Manager-side connectivity
   check) filters, but that is not the path that feeds Sort.
   
   
   ### What you expected to happen
   
   
   OceanBase sink creation should apply the same sensitive-parameter filtering 
as
   the MySQL sink does after INLONG-11731, i.e.
   
   ```
   OceanBaseSinkDTO.getFromRequest(request, extParams)
   ```
   
   should neutralize `autoDeserialize` / `allowLoadLocalInfile` / 
`allowUrlInLocalInfile`
   / `allowLoadLocalInfileInPath` (and ideally reject `queryInterceptors` /
   `statementInterceptors`) before the config is saved — so that what reaches
   `OceanBaseLoadNode.tableOptions()` and eventually Connector/J is incapable of
   enabling auto-deserialization.
   
   Current actual behaviour (verified): URL containing `autoDeserialize=true`
   submitted via the OceanBase sink request passes unchanged through
   `OceanBaseSinkDTO.getFromRequest` -> `OceanBaseLoadNode.tableOptions()` ->
   Flink `jdbc-inlong` connector -> Connector/J, and deserialization is executed
   during `ResultSet.getObject()`.
   
   ### How to reproduce
   
   
   Minimal end-to-end reproduction using released InLong 2.2.0 artifacts and a
   real MySQL server (Docker):
   
   1. Start MySQL:
   
   ```
   docker run -d --name ob-poc -e MYSQL_ROOT_PASSWORD=root123 \
       -e MYSQL_DATABASE=testdb -p 3307:3306 mysql:5.7
   ```
   
   2. Prepare the "attacker-controlled" table: write one row whose BLOB column
      contains a Java-serialized object of a class whose `readObject()` has a
      visible side effect (e.g., creates a marker file). Any real-world exploit
      would use a public gadget chain (e.g., CommonsCollections) instead of the
      marker class.
   
   3. Run the chain with the official released classes (manager-pojo 2.2.0,
      sort-common 2.2.0, mysql-connector-j 8.0.33):
   
   ```java
   // 1) Manager entry: exactly what OceanBaseSinkDTO.getFromRequest does with
   //    an OceanBaseSinkRequest carrying the attacker URL.
   OceanBaseSinkDTO dto = OceanBaseSinkDTO.getFromRequest(request, null);
   System.out.println("after getFromRequest url = " + dto.getJdbcUrl());
   // -> jdbc:mysql://127.0.0.1:3307/testdb?autoDeserialize=true   (NOT 
filtered)
   
   // 2) Sort layer: what OceanBaseLoadNode emits for the connector
   Map<String, String> opts = new OceanBaseLoadNode(dto.getJdbcUrl(), 
...).tableOptions();
   System.out.println("tableOptions url = " + opts.get("url"));
   // -> jdbc:mysql://127.0.0.1:3307/testdb?autoDeserialize=true   (verbatim)
   
   // 3) Runtime: what the jdbc-inlong connector ultimately does
   Connection conn = DriverManager.getConnection(opts.get("url"), "root", 
"root123");
   ResultSet rs = conn.createStatement().executeQuery("SELECT blob_col FROM 
loot").get(1), ...
   Object o = rs.getObject(1);   // triggers deserialization
   // -> marker file PWNED.txt created by the serialized object's readObject()
   ```
   
   Negative control: the identical query with `autoDeserialize` absent returns
   `byte[]` instead and creates no marker file — the behaviour difference is
   caused solely by this one parameter.
   
   Also reproducible: with the 1.13 `JdbcUrlUtils.replaceInvalidUrlProperty`,
   `jdbc:mysql://...?autoDeserialize=yes` is NOT neutralized (only the exact
   string `autoDeserialize=true` is replaced), and Connector/J parses
   `autoDeserialize=yes` as true.
   
   ### Environment
   
   - OS: Linux x86_64
   - JDK: OpenJDK 1.8.0_452
   - MySQL Server: 5.7 (Docker `mysql:5.7`)
   - Connector/J: com.mysql:mysql-connector-j 8.0.33 (also verified with 
mysql:mysql-connector-java 8.0.28)
   - Apache Spark/Flink runtime: not required – the invocation was exercised 
with the released InLong jars directly
   
   ### InLong version
   
   master
   
   ### InLong Component
   
   InLong Manager, InLong Sort
   
   ### Are you willing to submit PR?
   
   - [ ] Yes, I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [x] I agree to follow this project's [Code of 
Conduct](https://www.apache.org/foundation/policies/conduct)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to