
مختبر إثبات مفهوم لـ CVE-2026-19445، وهو ثغرة use-after-free في CPython ssl SNI SSLContext حيث يقوم عميل TLS بعيد بتحرير سياق الإرسال الخاص بالخادم أثناء المصافحة.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cve-2026-19445-sni-uaf
CPython ssl - Python Software Foundation
خادم TLS يُنشئ SSLContext لكل اتصال، ويضبط sni_callback، ويُسنِد sslobj.context = other_ctx يمكنه إسقاط آخر مرجع Python إلى السياق الأصلي بينما لا يزال OpenSSL يحتفظ بمؤشر مستعار إليه. رسالة ClientHello التالية (يكفي TLS 1.3 HelloRetryRequest) تستشير ذلك المؤشر. تستمر المصافحة. قد تنهار العملية لاحقًا. لا يتأثر العملاء. لا يتأثر التفاف طويل الأمد لمقبس الاستماع.
يمكن لعميل TLS بعيد تحرير SSLContext الخاص بالإرسال لدى الخادم بينما لا يزال رد نداء SNI بلغة C يشير إليه. تكتمل المصافحة رغم ذلك. نافذة انهيار وتلف ذاكرة. لا يوجد RCE في هذا المختبر.
| ID | CVE-2026-19445 |
| CWE | CWE-416 |
| CVSS | حرج: 9.2 CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:L |
| المنتج | CPython ssl |
| المتأثر | < 3.12.15، 3.13.0-3.13.15، 3.14.0-3.14.7، 3.15.0a1 قبل 3.15.0 |
| المصادقة | عميل TLS غير مُصادَق، يجب على الخادم التبديل عبر SNI وإسقاط السياق الأصلي |
| الترخيص | GNU Affero GPL v3.0 |
| المختبر | 127.0.0.1 فقط |
التحدث بـ TLS إلى خادم Python يُنشئ SSLContext جديدًا للاتصال، ويثبّت sni_callback، وفي ذلك الرد يُسنِد سياقًا مختلفًا ثم يترك السياق الأصلي يموت. أرسل SNI. افرض رسالة ClientHello ثانية (قيّد منحنى الخادم إلى P-384 حتى يحصل عميل X25519 الافتراضي على HelloRetryRequest). بعد GC، يختفي كائن Python. لا يزال رد نداء tlsext_servername بلغة C يحمل المؤشر المستعار args من SSL_CTX_set_tlsext_servername_arg. تكتمل المصافحة على هذا المؤشر. تحت ASan يُعد ذلك استخدامًا بعد التحرير. في الإنتاج يُعد نافذة انهيار / تلف في المرة التالية التي تُعاد فيها استخدام تلك الذاكرة.
الخوادم التي تُلفّ مقبس الاستماع مرة واحدة بسياق يدوم طوال عمر العملية تحتفظ بالمرجع. تلك خارج نطاق الخطأ. عملاء wrap_socket خارج نطاق الخطأ.
نفس المنتج، بقايا شقيقة: wrap_bio يتخطى التحقق من اسم المضيف. الجانب المقابل من TLS. لا يتكاملان.
نشرت PSF CVE-2026-19445. قضية الحجز هي python/cpython#156293. الخريطة الحقيقية هي PR 158504 / الالتزام 0f63c2aa. كان _servername_callback يستخدم وسيط OpenSSL المستعار. بعد أن يبدّل SNI قيمة sslobj.context ويُجمَع SSLContext الأصلي بواسطة GC، لا تزال رسالة ClientHello الثانية تستدعيه. تُحضر الترقعة السياق من SSL_get_app_data -> ssl->ctx وتمسح رد النداء في context_dealloc.
شغّلت اختبارات CPython الخاصة كمختبر ضد python:3.14.7-slim-bookworm (3.14.7 ضمن النطاق المتأثر؛ 3.14.8 هو الإصلاح). MemoryBIO، بدون TCP لمسار UAF.
dispatch_ctx.set_ecdh_curve("secp384r1")، الافتراضي للعميل هو X25519. يُسنِد sni_callback القيمة sslobj.context = leaf_ctx. بعد أول SNI، وثلاث استدعاءات لـ gc.collect()، تكون weakref.ref(dispatch_ctx) هي None. ومع ذلك تكتمل المصافحة (TLS_AES_256_GCM_SHA384). يوجد HRR في _msg_callback (قيمة ServerHello العشوائية عند الإزاحة 6). sni_calls=1: لم يصل ClientHello الثاني أبدًا إلى callback حيّ في Python.
المسار الثانوي (callback يبدّل، del ctx، يرفع LookupError) لم يُجهِض الإصدار 3.14.7. SSLError: CALLBACK_FAILED، وLookupError غير قابل للرفع. الحالة السلبية: سياق بعمر العملية يغلّف مقبس استماع على 127.0.0.1:18500. المصافحة تعمل. يبقى weakref حيًّا.
منعطفات خاطئة مسجّلة سلفًا: تثبيت P-384 على leaf وكذلك على dispatch، مع تقييد العميل بـ X25519 فقط، أنتج NO_SUITABLE_KEY_SHARE بدلًا من HRR. CPython يثبّت سياق dispatch فقط. سحر HRR عند الإزاحة 6 في ServerHello، وليس 2. أول فحص أخطأ HRR حتى عندما أُطلق. لا يزال dispatch_ctx حيًّا مباشرة بعد wrap_bio لأن server.context يحتفظ به. يصبح قابلًا للجمع فقط بعد تبديل SNI. مسرح: reverse shell. الأوراكل هو dispatch_ref is None بالإضافة إلى مصافحة مكتملة.
cd lab
./run.sh
صورة python:3.14.7-slim-bookworm. مشروع Compose cve-2026-19445. الواجهة الراجعة 127.0.0.1:18500 هي غلاف الاستماع السلبي. أوراكل الأساسي/الثانوي في الذاكرة MemoryBIO.
primary_dispatch_ref_after_sni_gc='none'
primary_hrr='yes'
primary_handshake='complete'
SUCCESS CVE-2026-19445 dispatch_ctx_gc=yes handshake=complete hrr=yes secondary_crash=no CVE-2026-19445-SNI-UAF-WITNESS
احتفظ بمرجع لكل SSLContext يقوم بتعيين sni_callback طوال فترة حياة الخادم. قم بالترقية إلى 3.12.15 / 3.13.16 / 3.14.8 / 3.15.0. تُوقف رقعة C استخدام وسيط OpenSSL المُستعار.