## https://sploitus.com/exploit?id=631F51D0-6C44-5F72-989F-53FC65E75426
# CVE-2026-32710
**Heap buffer overflow in MariaDB `JSON_SCHEMA_VALID()` β persistent privilege escalation**
| | |
|---|---|
| **Affected** | MariaDB 11.4.x (confirmed on 11.4.9) |
| **Bug** | OOB write in `json_get_normalized_string()` β `strncpy` into 128-byte `DYNAMIC_STRING` with no bounds check |
| **Impact** | `SELECT`-only user β `ALL PRIVILEGES WITH GRANT OPTION`, persistent across server restart |
| **Source** | `sql/json_schema_helper.cc:91` |
> **Lab-assisted.** The script uses Docker / root introspection to read
> `/proc/1/mem` and discover heap layout and `Security_context` addresses.
> A weaponized exploit would need an info-leak primitive to replace this step.
## Before
`lowpriv` can only `SELECT` on the `test` database. System tables are denied.

## Exploit
A single Python script performs heap grooming, a two-hop arbitrary write
through user-variable metadata, and persists the escalation via `GRANT ALL`.
```
python3 exploit.py
```

## After
`lowpriv` now has `ALL PRIVILEGES WITH GRANT OPTION`, can read system tables,
read/write arbitrary files, and the grant survives server restart.

Full exploit output

## How it works
```
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SELECT json_schema_valid(overflow), β
β @ccc...c := hop1, β
β @aaa...a := hop2 β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββ ββββββββββββββββ ββββββββββββββββ
β 192-byte β β Write to @c β β Write to @a β
β overflow β β through the β β through the β
β corrupts β β corrupted β β redirected β
β entry_c's β β pointer: β β pointer: β
β value ptr β β β β β
β (2-byte β β entry_a β β β master_accessβ
β partial β β .value = β β = 0xFFFF.. β
β overwrite)β β &master_ β β (ALL PRIVS) β
β β β access β β β
βββββββββββββ β .length= 9 β ββββββββββββββββ
ββββββββββββββββ
```
1. **Heap groom** β 100+ user variables exhaust tcache, forcing
`Entry_a β Value_a β Entry_b β Value_b β Entry_c β Value_c` to be
allocated consecutively.
2. **Overflow** β `JSON_SCHEMA_VALID` triggers a 192-byte `strncpy` past
the 128-byte buffer, corrupting `entry_cβvalue` (2-byte partial pointer
overwrite within the same 64 KB page) to point at `entry_a + 32`.
3. **Hop 1** β Assigning to `@c` writes 126 bytes through the corrupted
pointer into `entry_a`'s metadata, setting:
- `entry_aβvalue = &Security_context::master_access`
- `entry_aβlength = 9`
4. **Hop 2** β Assigning to `@a` writes 8 bytes of `0xFF` through the
redirected `entry_aβvalue` pointer β `master_access = ALL PRIVILEGES`.
5. **Persist** β The session now holds all privileges. `GRANT ALL` commits
the escalation to the Aria-backed `mysql.global_priv` table. The session
eventually crashes during cleanup (residual heap corruption), but the
GRANT is already checkpointed and survives the restart.
### Key constraints solved
| Constraint | Solution |
|---|---|
| `STRING_RESULT` does `length++` before realloc check | Payload is Nβ1 bytes so Nβ1+1 = N matches stored length β no realloc on corrupted pointer |
| 126-byte hop2 corrupts THD fields past `Security_context` | Set `entry_aβlength = 9` in hop1 so hop2 writes only 8 bytes (master_access) + 1 NUL |
| `master_access` offset in `Security_context` | 1712 bytes from struct base (`priv_user[384]` + `proxy_user[645]` + `priv_host[256]` + `priv_role[384]` + padding + pointers) |
| Aria crash recovery rolls back uncommitted writes | `GRANT ALL` + 10 s `SLEEP` allows Aria checkpoint before session cleanup crash |
## Lab setup
```bash
# 1. Build and start the container
./setup.sh
# 2. Disable ASLR on the Docker host
sudo sh -c 'echo 0 > /proc/sys/kernel/randomize_va_space'
# 3. Run the exploit
python3 exploit.py
```
### Requirements
- Docker
- Python 3
- ASLR disabled on the Docker **host** (`/proc/sys/kernel/randomize_va_space = 0`)
- Container runs with `--cap-add SYS_PTRACE` (for `/proc/1/mem` access)
### What the lab assistance provides
The exploit script shells into the container as root to read `/proc/1/mem`.
This is used for two things:
1. **Heap layout discovery** β locating the three sentinel `user_var_entry`
structs and verifying they are adjacent.
2. **`Security_context` address** β finding the `master_access` field to
target with the two-hop write.
In a real-world scenario, an attacker would need a separate info-leak
vulnerability (or a side-channel) to obtain these addresses. The heap
overflow and write primitive are fully reachable from a low-privilege
SQL session without any special access.
## Files
| File | Description |
|---|---|
| `exploit.py` | Two-hop chain exploit (Python 3) |
| `Dockerfile` | Lab container image |
| `init.sql` | Creates the `lowpriv` user |
| `setup.sh` | Builds and starts the lab |
| `screenshots/` | `freeze`-generated terminal screenshots |