
Exploit für CVE-2026-17544: PHP-bcmath-OOB-Write, umgewandelt in eine rein speicherbasierte RCE, die disable_functions und open_basedir mithilfe eines zur Laufzeit offsetfreien Resolvers umgeht.
Ein ausgereifter Proof-of-Concept für CVE-2026-17544, einen Out-of-Bounds-Write in der
neu geschriebenen bcmath-Erweiterung von PHP (bc_str2num). Dies verwandelt den öffentlich
bekannten DoS-only-Crash in eine vollständige, universelle, Memory-only-RCE-Primitive,
die gleichzeitig disable_functions und open_basedir umgeht.
Nur für autorisierte Forschung / zu Bildungszwecken. Führen Sie dies nur gegen Systeme aus, die Ihnen gehören oder für die Sie ausdrücklich autorisiert wurden.
![]()
bc_str2num kürzt einen Nachkommateil bei einem manuellen scale, entfernt erneut
nachgestellte Nullen, aktualisiert aber nicht. Der Puffer wird für die
erneut gekürzte Länge allokiert, während die Kopie die Länge vor dem Kürzen verwendet → kontrollierter
in den Zend-MM-Heap.fractional_endzend_string
(Länge bleibt erhalten) → Refcount-Desync-Use-after-Free → Riesen-String mit relativem R/W →
ausfallsicherer absoluter beliebiger Read → Laufzeit-Symbolauflösung → ein vollständig
Data-only-Aufruf einer nativen Funktion.zend_class_entry + eine Inline-function_table + eine gefälschte
zend_function{ handler = zif_shell_exec } und ruft sie als Methode auf. Die Befehlsausgabe
wird als String zurückgegeben und in die Antwort/Stdout geliefert..data und das Zielsymbol werden zur Laufzeit
durch Speicherscan aufgelöst — eine einzige Datei funktioniert daher über Builds und Distributionen hinweg.Dies ist eine Sandbox-Escape-/Post-Exploitation-Primitive, keine reine Remote-Input-RCE.
| Szenario | Ergebnis |
|---|---|
Angreifer kann bereits PHP ausführen (Webshell, Deserialisierung, eval-Senke), wird aber von disable_functions + open_basedir eingeschränkt | ✅ Native RCE (dieser PoC) |
Anwendung ruft lediglich eine bcmath-Funktion mit roher Benutzereingabe auf, z. B. bccomp($_POST['v']) | ❌ Nur DoS / Crash |
Ein einzelner bcmath-Aufruf mit Angreifer-Eingabe ergibt einen blinden OOB-Null-Write ohne Feedback. Vollständige RCE erfordert beliebige PHP-Ausführung, um den Heap zu präparieren, die R/W-Primitiven zu bauen und den Resolver auszuführen — nichts davon ist als Funktionsargument ausdrückbar. Die realistische Obergrenze für eine reine Input-Exposition ist also ein Remote-Denial-of-Service; Codeausführung erfordert einen bestehenden PHP-Ausführungskontext, den dieser PoC dann aus der Sandbox befreit.
Der Bug existiert nur in der neu geschriebenen bcmath (PHP-8.4/8.5-Linie):
| PHP-Zweig | Verwundbar |
|---|---|
| 7.x, 8.0 – 8.3 | Nein (altes libbcmath, anderes bc_str2num) |
| 8.4.0 – 8.4.23 | Ja |
| 8.5.0 – 8.5.8 | Ja |
| ≥ 8.4.24 / ≥ 8.5.9 | Gepatcht |
End-to-End verifiziert (uid=0, Ausgabe erfasst) auf PHP 8.4.23 und PHP 8.5.8, amd64,
mit derselben unveränderten Datei — das Zend-Struct-Layout ist über 8.4 / 8.5 identisch.
bcmath..text abwärts zum ELF-Header; dies ist bei jedem
kontinuierlich gemappten Binary sicher. Nur künstliche -z separate-code-Builds mit nicht
gemappten 2-MB-Lücken können von einem blinden Scan nicht automatisch aufgelöst werden (in der Produktion nicht beobachtet).exit() pro Request den Server nicht tötet:
php-fpm, Apache mod_php oder der eingebaute Server mit PHP_CLI_SERVER_WORKERS>0.php exploit.php "id; uname -a"
Z. B. als shell.php bereitstellen, dann:
GET /shell.php?cmd=id
POST cmd=id
Die Befehlsausgabe wird über zif_shell_exec erfasst und in den Antwortbody geschrieben.
bccomp() ausführen, sodass der OOB-Null-Write nur auf den Refcount eines benachbarten
zend_string trifft (Länge bleibt erhalten).zend_reference (über Indirektion) ergibt einen ausfallsicheren absoluten
beliebigen Read, der den Refcount-Header des Ziels nie berührt..text-Zeiger aus: seitenweise abwärts zur ELF-Magie (Basis) gehen,
Programm-Header parsen, um .data zu finden, dann .data nach dem shell_exec-
zend_function_entry durchsuchen, dessen Handler in .text zeigt.zend_class_entry, eine Inline-function_table mit einem
einzelnen Bucket (korrekter zend_string-Hash, terminierte Kollisionskette) und eine gefälschte
zend_internal_function mit dem Handler zif_shell_exec konstruieren; den Klassenzeiger des Probe-Objekts
korrumpieren und die Methode aufrufen. Die Ausgabe wird zurückgegeben und ausgegeben.exploit.php — der universelle Memory-only-Exploit (CLI + Web).Bereitgestellt für Sicherheitsforschung und Bildung. Der Autor ist nicht verantwortlich für Missbrauch. Nicht gegen Systeme einsetzen, für die Sie nicht autorisiert sind.