
MySQL Community Server 26.7.0 - High - JSON Duality DEFINER SQLi - NO_BACKSLASH_ESCAPES
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · mysql-jdv-definer-sqli
Class: SQLi Reach: Remote
MySQL Community Server mysqld 26.7.0 (06a5c1c) - Oracle
JSON Duality DML concatenates JSON string values with escape_string_for_mysql (backslash only), then parse_sql under the invoker sql_mode after swapping to the view DEFINER sctx. SET SESSION sql_mode='NO_BACKSLASH_ESCAPES' makes \' end the SQL literal. A JSON string containing ' injects a subquery / SET-list as DEFINER. Lab: invoker with only DML on the view reads secret.s into the projected name column.
Default CREATE VIEW is DEFINER. X Plugin already branches on that mode. JDV does not. Feature-gated: needs a JSON Duality View.
| ID | no CVE yet |
| Class | SQLi (DEFINER; not RCE) |
| Reach | Remote (authenticated SQL; needs DML on a JSON Duality View) |
| CWE | CWE-89 |
| CVSS | High: 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| Product | MySQL Community Server mysqld |
| Affected | 26.7.0 (06a5c1c99c377fc41b2eba1ea244e8b220bdc3c8) |
| Auth | authenticated; INSERT or UPDATE on a JSON Duality View |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 only. Witness in projected $.name. |
Hold DML on a SQL SECURITY DEFINER JSON Duality View. SET SESSION sql_mode='NO_BACKSLASH_ESCAPES'. UPDATE (etag from SELECT) a string field whose JSON value contains '. The generated _utf8mb4 '...' literal ends. The rest of the statement runs as DEFINER. Lab selects secret.s.note into the projected name column. Direct SELECT on secret.s is 1142.
Without that sql_mode the same JSON stores as a literal name. The quote stays data.
Same 26.7.0 hunt. Default daemon unpublished Crit/High was empty. JSON Duality DML still concatenates values.
sbuf.append("_utf8mb4 '");
escape_string_for_mysql(&my_charset_utf8mb4_bin, ...);
sbuf.append(1, '\'');
create_sctx_guard installs view_sctx before run_substmt. Invoker sql_mode is what parse_sql sees.
Wrong turns: SQL SECURITY DEFINER between the view name and AS is 1064 (default is already DEFINER). Same name as the current row is skipped (is_equal); inject against a different value. Etag is required.
cd lab
./run.sh
Image mysql:26.7.0. Published 127.0.0.1:18640. View app.dv DEFINER root@% over app.t. Secret in secret.s. Victim has SELECT/INSERT/UPDATE on the view only.
SUCCESS mysql-jdv-definer-sqli victim-secret=denied nbe-inject=yes view-has-witness=yes default-mode-inject=no dump=26.7.0 image=mysql:26.7.0 MYSQL-JDV-DEFINER-SQLI-WITNESS
Escape JDV DML strings with the same NO_BACKSLASH_ESCAPES branch X Plugin already has (escape_sql_quote vs escape_string_for_mysql). Parameterize the generated INSERT/UPDATE. Do not parse_sql concatenated values under a DEFINER sctx.
06a5c1c99c377fc41b2eba1ea244e8b220bdc3c8)append_json_dom / create_sctx_guard