
إثبات مفهوم يعيد إنتاج CVE-2026-8932، وهو خلل في مطابقة إعدادات mTLS غير المكتملة في إعادة استخدام اتصالات libcurl، مع خادم مختبري محلي وإثبات مفهوم بلغة C.
إثبات مفهوم لإعادة إنتاج CVE-2026-8932، وهو خلل في مطابقة إعدادات mTLS غير المكتملة في إعادة استخدام اتصالات libcurl.
يؤثر CVE-2026-8932 على منطق إعادة استخدام الاتصالات في libcurl عندما تتغير إعدادات المصادقة المتبادلة TLS (mTLS) بين الطلبات.
في الظروف القابلة للاستغلال، يمكن لـ libcurl إعادة استخدام اتصال TLS موجود على الرغم من تغيّر أحد خيارات الإعدادات المتعلقة بـ mTLS والذي كان ينبغي أن يمنع إعادة استخدام ذلك الاتصال.
يوضح هذا الـ PoC المشكلة عبر تغيير كلمة مرور المفتاح الخاص بين طلبين مع استخدام نفس شهادة العميل والمفتاح الخاص.
يستخدم الطلب الأول كلمة المرور الصحيحة:
correct-password
ويستخدم الطلب الثاني عمدًا كلمة مرور غير صالحة:
WRONG-PASSWORD
إذا أعاد libcurl استخدام اتصال TLS الموجود بشكل غير صحيح، فلن يتطلب الطلب الثاني إجراء مصافحة TLS أخرى. وبالتالي، لن تكون هناك حاجة إلى كلمة مرور المفتاح الخاص غير الصالحة لإنشاء اتصال TLS جديد، وسينجح الطلب.
لذلك يوضح الـ PoC حالة إعادة استخدام الاتصال المرتبطة بـ CVE-2026-8932.
| Property | Value |
|---|
| CVE | CVE-2026-8932 |
| Component | libcurl |
| Vulnerability Type | Incomplete mTLS configuration matching |
| CWE | CWE-305 — Authentication Bypass by Primary Weakness |
| Affected Area | TLS connection reuse |
| Protocol | HTTPS / mTLS |
| Client | libcurl API |
| curl CLI | Not affected |
| PoC Scope | Local laboratory environment |
الثغرة هي مشكلة منطقية/في مطابقة الإعدادات، وليست ثغرة تقليدية متعلقة بسلامة الذاكرة مثل تجاوز سعة المخزن المؤقت أو الاستخدام بعد التحرير.
يحتفظ libcurl بمعلومات الاتصال ويمكنه إعادة استخدام اتصال موجود عندما يُعتبر طلب لاحق متوافقًا مع إعدادات ذلك الاتصال.
بالنسبة لاتصالات TLS، يجب بالتالي مقارنة إعدادات الاتصال بعناية قبل إعادة الاستخدام.
لم يتضمن التنفيذ المصاب جميع حقول إعدادات mTLS ذات الصلة في منطق مطابقة الاتصال.
من بين الإعدادات المتأثرة:
cert_type
key
key_type
key_passwd
key_blob
الإعداد المهم المستخدم في هذا الـ PoC هو:
key_passwd
ينشئ الـ PoC اتصال TLS باستخدام مفتاح خاص مشفّر للعميل وكلمة المرور الصحيحة:
correct-password
ثم ينفذ طلبًا آخر باستخدام نفس الشهادة والمفتاح لكن مع تغيير كلمة المرور إلى:
WRONG-PASSWORD
قد يعتبر تنفيذ مطابقة الاتصال المصاب الاتصال الموجود قابلاً لإعادة الاستخدام رغم ذلك.
يتكون الاختبار من طلبي HTTP.
ينشئ الطلب الأول اتصال TLS:
URL:
https://server.test:8443/A
Client certificate:
client.crt
Private key:
client.key
Key password:
correct-password
يبقى اتصال TLS مستمرًا لأن الخادم يدعم HTTP keep-alive.
يستخدم الطلب الثاني نفس الشهادة والمفتاح الخاص لكن مع تغيير كلمة مرور المفتاح:
URL:
https://server.test:8443/B
Client certificate:
client.crt
Private key:
client.key
Key password:
WRONG-PASSWORD
إذا أنشأ libcurl اتصال TLS جديدًا، فينبغي أن يفشل تحميل المفتاح الخاص المشفّر بكلمة المرور الخاطئة.
لكن إذا أعاد libcurl استخدام الاتصال الموجود بشكل غير صحيح، فلن تكون هناك حاجة إلى مصافحة TLS جديدة.
وبالتالي لن تمنع كلمة المرور غير الصالحة نجاح طلب HTTP.
تتكون بيئة المختبر من:
localhost
|
v
+---------------------+
| Python mTLS Server |
| 127.0.0.1:8443 |
+----------+----------+
|
| HTTPS / TLS 1.3
|
+--------+--------+
| |
/A /B
\ /
\ /
v v
Same TLS Connection
|
v
libcurl
PoC (C)
الملاحظة المهمة هي أنه يجب أن يصل /A و /B عبر نفس اتصال TLS.
CVE-2026-8932-PoC/
├── README.md
├── LICENSE
├── .gitignore
│
├── certs/
│ └── .gitkeep
│
├── poc/
│ └── poc.c
│
├── server/
│ └── server.py
│
└── docs/
├── CVE-2026-8932-POC.jpg
├── CVE-2026-8932-server-POC.jpg
├── poc-output.txt
└── server-output.txt
يُترك دليل certs/ فارغًا عمدًا في المستودع. يجب إنشاء الشهادات والمفاتيح الخاصة محليًا.
تم اختبار الـ PoC في البيئة التالية:
OS:
Debian GNU/Linux 13 (trixie)
Architecture:
x86_64
libcurl:
8.14.1
OpenSSL:
3.5.7
GCC:
14.2.0
كان إصدار libcurl المصاب المستخدم لإعادة الإنتاج:
libcurl/8.14.1
تحقق من الإصدار المثبّت:
curl --version
و:
pkg-config --modversion libcurl
mkdir -p ~/cve-2026-8932-lab/{certs,poc,server,docs}
cd ~/cve-2026-8932-lab
cd ~/cve-2026-8932-lab/certs
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes \
-key ca.key \
-sha256 \
-days 3650 \
-subj "/CN=CVE-2026-8932-CA" \
-out ca.crt
أنشئ المفتاح الخاص للخادم:
openssl genrsa -out server.key 2048
أنشئ CSR:
openssl req -new \
-key server.key \
-subj "/CN=server.test" \
-out server.csr
أنشئ امتدادات الشهادة:
printf "subjectAltName=DNS:server.test\nextendedKeyUsage=serverAuth\n" \
> server.ext
وقّع الشهادة باستخدام CA الاختباري:
openssl x509 -req \
-in server.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out server.crt \
-days 3650 \
-sha256 \
-extfile server.ext
أنشئ المفتاح الخاص للعميل:
openssl genrsa -out client.key.tmp 2048
أنشئ CSR:
openssl req -new \
-key client.key.tmp \
-subj "/CN=Client-A" \
-out client.csr
حوّل المفتاح الخاص إلى صيغة PKCS#8 المشفّرة:
openssl pkcs8 \
-topk8 \
-in client.key.tmp \
-out client.key \
-v2 aes-256-cbc \
-passout pass:correct-password
يُشفَّر المفتاح الخاص الناتج باستخدام:
correct-password
أنشئ امتدادات شهادة العميل:
printf "extendedKeyUsage=clientAuth\n" \
> client.ext
وقّع شهادة العميل:
openssl x509 -req \
-in client.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out client.crt \
-days 3650 \
-sha256 \
-extfile client.ext
في هذه المرحلة يجب أن تكون الملفات المطلوبة موجودة:
certs/
├── ca.crt
├── ca.key
├── client.crt
├── client.key
├── server.crt
└── server.key
انتقل إلى دليل الخادم:
cd ~/cve-2026-8932-lab/server
شغّل الخادم:
python3 server.py
يستمع الخادم على:
0.0.0.0:8443
مصادقة شهادة العميل مطلوبة.
كما يحافظ الخادم على اتصالات HTTP/1.1 حيّة حتى يتمكن libcurl من إعادة استخدام اتصال TLS.
افتح طرفية أخرى:
cd ~/cve-2026-8932-lab/poc
ترجم:
gcc -Wall -Wextra -O0 -g \
poc.c \
$(pkg-config --cflags --libs libcurl) \
-o poc
نفّذ:
./poc
يستخدم الـ PoC:
Client certificate : client.crt
Private key : client.key
Request A password : correct-password
Request B password : WRONG-PASSWORD
أهم دليل من جهة العميل هو:
[+] STEP 2: Request using modified mTLS configuration
[+] Key password = WRONG-PASSWORD
* Re-using existing https: connection with host server.test
> GET /B HTTP/1.1
ثم يتلقى الطلب:
< HTTP/1.1 200 OK
ويُبلّغ الـ PoC:
[!!!] B REQUEST SUCCEEDED
هذا مهم لأن /B يستخدم كلمة مرور مفتاح خاص غير صالحة عمدًا.
الملاحظة الأساسية ليست مجرد نجاح /B.
الدليل الحاسم هو أن libcurl يُبلّغ صراحةً:
Re-using existing https: connection
لذلك لا يحتاج الطلب الثاني إلى إجراء مصافحة TLS أخرى باستخدام إعدادات المفتاح المعدّلة.
يوفر مخرجات الخادم تأكيدًا مستقلًا لإعادة استخدام الاتصال.
المخرجات ذات الصلة هي:
[+] TLS connection #2
Client CN : Client-A
[+] Connection #2 Client=Client-A Request=GET /A HTTP/1.1
[+] Connection #2 Client=Client-A Request=GET /B HTTP/1.1
الملاحظة المهمة هي:
/A -> Connection #2
/B -> Connection #2
وبالتالي تم استقبال طلبي HTTP عبر نفس اتصال TLS.
كما يُبلّغ الخادم عن نفس هوية العميل:
Client-A
لكلا الطلبين.
المفتاح الخاص المستخدم في الـ PoC مشفّر.
يستخدم الطلب الأول:
correct-password
مما يسمح لـ libcurl/OpenSSL بالوصول إلى المفتاح الخاص وإنشاء اتصال TLS.
يغيّر الطلب الثاني الإعدادات إلى:
WRONG-PASSWORD
إذا كان لا بد من إنشاء اتصال TLS جديد، فسيحتاج libcurl إلى معالجة المفتاح الخاص المشفّر مرة أخرى، وينبغي أن تتسبب كلمة المرور غير الصحيحة في فشل العملية.
لكن عند إعادة استخدام اتصال TLS الموجود، تكون جلسة TLS قد أُنشئت بالفعل.
لا حاجة إلى عملية مصادقة عميل جديدة لـ /B.
من الناحية المفاهيمية:
Request A
|
| correct-password
v
TLS handshake
|
v
Established TLS connection
|
+----------------------+
| |
v v
/A /B
|
WRONG-PASSWORD
|
X
No new TLS handshake
|
v
HTTP succeeds
يوضح هذا الـ PoC إعادة استخدام الاتصال، وليس استئناف جلسة TLS.
الآليتان مختلفتان.
يبقى اتصال TLS المُنشأ مسبقًا مفتوحًا ويُستخدم لطلب HTTP آخر:
TLS connection #2
|
+-- GET /A
|
+-- GET /B
لا حاجة إلى مصافحة TLS ثانية.
يُنشأ اتصال TCP/TLS جديد، لكن تُستخدم معلومات الجلسة التشفيرية من اتصال سابق لتقصير مصافحة TLS الجديدة.
هذا ليس ما يعتمد عليه هذا الـ PoC.
يتشارك الـ PoC عمدًا:
CURL_LOCK_DATA_CONNECT
بين المقبضين السهلين دون مشاركة:
CURL_LOCK_DATA_SSL_SESSION
وهذا يُبقي العرض مركّزًا على إعادة استخدام الاتصال.
يحتوي المستودع على المخرجات الملتقطة من إعادة الإنتاج الناجحة.

تُظهر المخرجات الملتقطة:
/ARe-using existing https: connection/Bالمخرجات الكاملة للطرفية متاحة أيضًا في:
docs/poc-output.txt

يُظهر الدليل من جهة الخادم أن:
/A -> TLS connection #2
/B -> TLS connection #2
مخرجات الخادم الكاملة متاحة في:
docs/server-output.txt
إذا أُجري اختبار curl يدوي قبل تشغيل الـ PoC، فقد يعرض الخادم اتصالًا سابقًا:
TLS connection #1
هذا الاتصال غير مرتبط بتنفيذ الـ PoC الفعلي.
على سبيل المثال، طلب التحقق اليدوي:
curl \
--resolve server.test:8443:127.0.0.1 \
--cacert ~/cve-2026-8932-lab/certs/ca.crt \
--cert ~/cve-2026-8932-lab/certs/client.crt \
--key ~/cve-2026-8932-lab/certs/client.key \
--pass correct-password \
https://server.test:8443/A
قد ينشئ الاتصال #1.
ثم قد ينشئ الـ PoC الفعلي الاتصال #2.
لذلك فإن الشرط ذا الصلة ليس رقم الاتصال المطلق، بل أن:
/A and /B
يظهران على نفس اتصال TLS أثناء تنفيذ الـ PoC.
الإصلاح في المنبع هو:
7541ae569d82fb308a5e2d94916027da4fa3ba3e
الـ commit:
tls: fix incomplete mTLS config in conn reuse and session cache
يضيف الإصلاح مقارنات إعدادات mTLS المفقودة إلى منطق مطابقة الاتصال.
من الناحية المفاهيمية، يأخذ منطق المطابقة الآن في الاعتبار قيمًا تشمل:
blobcmp(c1->key_blob, c2->key_blob) &&
curl_strequal(c1->cert_type, c2->cert_type) &&
Curl_safecmp(c1->key, c2->key) &&
curl_strequal(c1->key_type, c2->key_type) &&
!Curl_timestrcmp(c1->key_passwd, c2->key_passwd)
التغيير المهم لهذا الـ PoC هو مقارنة:
key_passwd
لذلك ينبغي أن يمنع أي تغيير في كلمة مرور المفتاح الخاص اعتبار الاتصال الموجود متوافقًا لإعادة الاستخدام.
قدّم الإصلاح في المنبع أيضًا تغطية اختبار انحدار لسلوك مطابقة إعدادات TLS.
الاختبار ذو الصلة مرتبط بـ:
test 3303
تغطي اختبارات الانحدار الاختلافات في إعدادات mTLS بما في ذلك:
key_passwd
key
key_type
cert_type
على سبيل المثال، ينبغي أن تتطابق الإعدادات المتطابقة:
config A == config B
بينما لا ينبغي أن يتطابق تغيير كلمة مرور المفتاح:
config A key_passwd = password-A
config B key_passwd = password-B
↓
connection match = false
هذا هو نفس بُعد الإعدادات الذي يمارسه هذا الـ PoC.
/Bإذا فشل /B، فتحقق أولًا مما إذا كان libcurl قد أعاد استخدام الاتصال فعلاً.
يجب أن تحتوي المخرجات المطوّلة على:
Re-using existing https: connection
إذا لم يظهر هذا السطر، فلم تُثبَت حالة الثغرة.
/A و /B على اتصالات TLS مختلفةيجب أن يعرض الخادم:
Connection #X -> /A
Connection #X -> /B
إذا رأيت بدلاً من ذلك:
Connection #X -> /A
Connection #Y -> /B
فقد أنشأ الطلب الثاني اتصال TLS جديدًا ولم تُعَد إنتاج الحالة المقصودة.
تحقق من أن:
CURL_LOCK_DATA_CONNECT مشترك.CURLOPT_FORBID_REUSE غير مفعّل.CURLOPT_FRESH_CONNECT غير مفعّل.Connection: keep-alive.يجب إنشاء المفتاح الخاص للعميل باستخدام:
correct-password
ثم يستخدم الـ PoC عمدًا:
WRONG-PASSWORD
لا تغيّر كلمة المرور المضمّنة في أمر إنشاء المفتاح الخاص إلا إذا تم تغيير قيمة الـ PoC المقابلة أيضًا.
هذا المستودع مخصص لأبحاث الأمن الخاضعة للرقابة وإعادة إنتاج الثغرات.
صُمم الـ PoC للعمل ضد خادم اختبار مستضاف محليًا:
127.0.0.1:8443
لا تستخدم الـ PoC ضد أنظمة دون تصريح.
يجب أن تبقى المفاتيح الخاصة والشهادات المُنشأة خارج التحكم في الإصدارات.
يجب أن يحتوي المستودع فقط على:
certs/.gitkeep
بدلاً من المفاتيح الخاصة المُنشأة.
تم تطوير تصميم الـ PoC، ومنهجية المختبر، والتنفيذ، والتحليل التقني بواسطة AliReza بمساعدة من OpenAI ChatGPT (GPT-5.6 Luna).
تم إجراء التحقق البشري والتنفيذ والاختبار وإعادة الإنتاج بواسطة مؤلف المستودع.
يُقدَّم هذا المستودع لأغراض أبحاث الأمن وتحليل الثغرات والأغراض التعليمية.
استخدمه فقط في الأنظمة والبيئات التي لديك تصريح صريح بها.