
Proof-of-Concept-Lab zur Reproduktion von CVE-2026-19553, bei dem CPython ssl.SSLContext.wrap_bio() die TLS-Hostnamenüberprüfung stillschweigend überspringt, wenn server_hostname None ist.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cve-2026-19553-wrap-bio
CPython ssl – Python Software Foundation
ssl.SSLContext.wrap_bio() verlangte nicht, dass server_hostname nicht-None ist, wenn check_hostname gesetzt ist. SSLObject überspringt stillschweigend die Hostnamen-Verifikation. Das Programm sieht so aus, als wäre es mit check_hostname=True erfolgreich gewesen. Kein ValueError. Die Zertifikatskette wird verifiziert. Der Name des Peers nicht. wrap_socket() hat bereits einen Fehler ausgelöst. asyncio SSLProtocol / start_tls / open_connection verwandeln "" in None und rufen dann wrap_bio auf.
Ein MITM mit einem CA-gültigen Zertifikat für einen anderen Hostnamen schließt den Handshake gegen einen wrap_bio-/asyncio-Client ab, der vergessen hat, server_hostname zu übergeben.
| ID | CVE-2026-19553 |
| CWE | CWE-297 |
| CVSS | High: 7.6 CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N |
| Produkt | CPython ssl |
| Betroffen | < 3.12.15, 3.13.0-3.13.15, 3.14.0-3.14.7, 3.15.0a1 vor 3.15.0 |
| Auth | MITM / angreifender TLS-Server; Opfer ist ein Python-TLS-Client, der wrap_bio oder asyncio ohne Hostnamen verwendet |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1 |
Sich auf dem Pfad befinden (oder der Server sein, den der Client erreichen wollte). Ein Zertifikat präsentieren, dem der Client für einen Namen vertraut, der nicht der vom Client beabsichtigte ist. Wenn der Client wrap_bio(..., server_hostname=None) oder asyncio mit server_hostname="" verwendet hat, während check_hostname=True und CERT_REQUIRED gesetzt sind, gelingt der Handshake. Die Identität wurde nie geprüft. wrap_socket auf demselben Kontext löst ValueError aus, bevor irgendwelche Bytes übertragen werden. Wird ein nicht-leerer Hostname an wrap_bio übergeben, wird eine Abweichung weiterhin abgelehnt.
Gleiches Produkt, verwandtes Überbleibsel: SNI SSLContext UAF. Entgegengesetzte TLS-Seite. Sie lassen sich nicht kombinieren.
Die PSF hat CVE-2026-19553 veröffentlicht. Issue python/cpython#156793, PR 158503, Commit 6dc0069a. _check_sslobject_params lief bereits für wrap_socket. SSLObject._create übersprang dies. NEWS: Abschluss eines Handshakes, der die Zertifikatskette verifizierte, ohne die Identität des Peers zu verifizieren, ohne jeden Hinweis darauf, dass die Prüfung übersprungen wurde. Nach dem Patch löst wrap_bio mit check_hostname=True und server_hostname=None/"" ValueError("check_hostname requires server_hostname") aus. Der 3.12-Backport löst stattdessen eine DeprecationWarning aus.
Ich habe python:3.14.7-slim-bookworm bereitgestellt. Gleiche Lab-CA, zwei Leaf-Zertifikate: victim.lab und evil.lab. Client check_hostname=True, CERT_REQUIRED.
INJECT: wrap_bio(server_hostname=None) gegen evil.lab akzeptiert. Peer-SAN evil.lab. SNI None. TLS_AES_256_GCM_SHA384. CONTROL A: wrap_socket(server_hostname=None) löste ValueError: check_hostname requires server_hostname aus. CONTROL B: wrap_bio(server_hostname="victim.lab") gegen evil.lab löste SSLCertVerificationError Hostname-Mismatch aus. NEGATIVE: derselbe Aufruf gegen victim.lab akzeptiert. Zusätzlich: asyncio.open_connection(..., server_hostname="") auf 127.0.0.1:18510 akzeptiert ("" wird zu None, dann wrap_bio).
Falsche Züge bereits protokolliert: Der erste asyncio-start_server-Entwurf ließ eine schließende Klammer weg; die Host-Kompilierung fing dies vor compose ab. Host 3.14.7 (Clang, OpenSSL 3.6.4) reproduzierte dieselben vier Orakel; der Laborbericht ist die Container-Pin (GCC, OpenSSL 3.0.22). Theater: eine Reverse Shell. Das Orakel ist accept-wrong-name plus wrap_socket, das weiterhin eine Ausnahme auslöst.
cd lab
./run.sh
Image python:3.14.7-slim-bookworm. Compose-Projekt cve-2026-19553. Loopback 127.0.0.1:18510 ist das asyncio-Extra. MemoryBIO benötigt keinen Port.
INJECT wrap_bio_none vs evil.lab: accept peer=evil.lab
CONTROL_A wrap_socket_none: ValueError:check_hostname requires server_hostname
CONTROL_B wrap_bio_name='victim.lab' vs evil.lab: mismatch-reject
SUCCESS CVE-2026-19553 wrap_bio_none=accept wrap_socket_none=ValueError wrap_bio_name=mismatch-reject CVE-2026-19553-WRAPBIO-HOST-WITNESS
Übergeben Sie einen nicht leeren server_hostname an wrap_bio(), asyncio.create_connection() oder loop.start_tls(). Aktualisieren Sie auf 3.12.15 / 3.13.16 / 3.14.8 / 3.15.0. Der Patch ändert lediglich das stille Überspringen in denselben ValueError, den wrap_socket bereits ausgelöst hat.