
Vorhersagbares delete_code via rand() in PictShare < 3.7.1 (CWE-338). PoC + Advisory-Writeup.
delete_code durch rand() in PictShareAutorisierte Sicherheitsforschung. PoC nur für defensive und edukative Zwecke.
PictShare erzeugt das delete_code-
Autorisierungstoken mit getRandomString(), wobei jedes Zeichen aus PHPs
nicht-kryptografischem rand() gezogen wird. Da rand() kein CSPRNG ist — und derselbe
Generator den öffentlichen Datei-Hash erzeugt, der in jeder geteilten URL angezeigt wird —
ist der delete_code vorhersehbar statt geheim, was die unbefugte Löschung gehosteter Dateien
ermöglicht, ohne den Code jemals vom Info-Endpunkt auslesen zu müssen.
| CVE | CVE-2026-104356 |
| Produkt | PictShare (selbst gehosteter Bild-/Medienhost) |
| Betroffen | >= 2.0.0, < 3.7.1 |
| Behoben in | v3.7.1 |
| Schwachstelle | Verwendung eines kryptografisch schwachen PRNG (CWE-338) → vorhersehbares Auth-Token |
| Berechtigungen | Keine (nicht authentifiziert) |
| CVSS 3.1 | 5.9 MEDIUM — AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H |
| CVSS 4.0 | 8.2 HIGH — AV:N/AC:H/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H |
| Entdeckt von | Alisher Qarshibayev |
| Advisory | VulnCheck |
// src/inc/core.php (< 3.7.1)
function getRandomString($length=32, $keyspace='0123456789abcdefghijklmnopqrstuvwxyz')
{
$str = '';
$max = (function_exists('mb_strlen') ? mb_strlen($keyspace,'8bit') : strlen($keyspace)) - 1;
for ($i = 0; $i < $length; ++$i) {
$str .= $keyspace[rand(0, $max)]; // <-- rand() ist NICHT kryptografisch sicher
}
return $str;
}
Diese eine Funktion erzeugt beides:
delete_code, der die Löschung autorisiert.Da beide Token aus demselben Nicht-CSPRNG-Stream stammen, erlangt ein Angreifer, der den
öffentlichen Hash beobachtet, Informationen über den Zustand des Generators — der delete_code
hat nicht mehr die Entropie, die seine 32-Zeichen-Länge suggeriert. rand() bietet keine
kryptografische Unvorhersehbarkeitsgarantie, weshalb seine Verwendung für ein Sicherheitstoken
der Defekt ist (CWE-338), unabhängig von einer bestimmten Technik zur Zustandswiederherstellung.
random_int().rand() (aliasiert auf den Mersenne-Twister-Pfad) automatisch pro Prozess, sodass ein
schlüsselfertiger Remote-Prädiktor von der Bereitstellung abhängt (Prozesswiederverwendung,
Anzahl beobachtbarer Ausgaben, PHP-Build). Dieser PoC demonstriert daher das
Vorhersehbarkeitsprinzip deterministisch mit einem kontrollierten Seed, anstatt einen
universellen einmaligen Remote-Break zu behaupten. Das ist der ehrliche Umfang des Fundes —
und genau deshalb behandelte der Hersteller ihn dennoch als Schwachstelle und behob ihn.demo.php reproduziert die exakte getRandomString() des Herstellers und zeigt, dass, sobald
der PRNG-Zustand bekannt/wiederhergestellt ist, die erste Ausgabe (der öffentliche Hash) die
zweite Ausgabe (den delete_code) vollständig bestimmt — d. h. die Beobachtung des Hashes
sagt den Code voraus:
php demo.php
Erwartete Ausgabe:
[*] Reproducing PictShare getRandomString() with rand()
[*] Seed used by victim process : 1337 (unknown to attacker a priori)
public file hash (output #1): k3f9... (visible in the shared URL)
secret delete_code(output #2): 8a1c...
[*] Attacker recovers seed by matching the OBSERVED public hash:
[+] Seed recovered: 1337
[+] Predicted delete_code: 8a1c...
[+] MATCH — delete_code predicted from the public hash alone (no info API needed)
Siehe demo.php. Es ist eigenständig (kein Server, kein Netzwerk) und beweist die
Hash→Code-Determiniertheit, die rand() hier ungeeignet macht.
Aktualisieren Sie auf PictShare 3.7.1 (Fix-Commit ce5fc47),
der rand() durch random_int() (CSPRNG) ersetzt. Allgemeine Empfehlung: Erzeugen Sie jedes
Sicherheitstoken (Löschcodes, Reset-Token, API-Schlüssel, Salts) mit einem kryptografisch
sicheren RNG — random_int() / random_bytes() in PHP — niemals rand(), mt_rand() oder
uniqid().
Hinweis: Löschcodes, die vor dem Fix ausgestellt wurden, werden nicht rotiert, sodass Uploads vor dem Fix vorhersehbar bleiben, bis sie erneut hochgeladen werden.
| Datum | Ereignis |
|---|---|
| 2026-10-01 | Öffentliche Offenlegung, CVE reserviert & veröffentlicht (VulnCheck), behoben in v3.7.1 |
Verantwortungsvoll gegenüber dem Hersteller offengelegt und über VulnCheck koordiniert. Behoben, bevor dieser PoC veröffentlicht wurde. Veröffentlicht für defensive und edukative Zwecke.