
إثبات مفهوم الاستغلال لـ CVE_2026_31431
كاشف وإثبات مفهوم لـ LPE لثغرة الكتابة الخدشية في ذاكرة التخزين المؤقت للصفحات لنواة لينكس algif_aead /
authencesn، والتي تم الإفصاح عنها في 2026-04-29.
التقرير الفني للإفصاح: https://xint.io/blog/copy-fail-linux-distributions
لا تستخدم هذه الأدوات إلا على أجهزة تملكها أو لديك تكليف صريح بتقييمها. يعدّل LPE حالة في الذاكرة (ذاكرة التخزين المؤقت للصفحات) لكن الأسلوب يمثل تصعيدًا حقيقيًا للامتيازات — تشغيله على أنظمة دون إذن يعتبر غير قانوني في معظم الولايات القضائية.
تنفّذ algif_aead عمليات AEAD في مكانها (req->src == req->dst). عندما يتم إدخال البيانات المصدر عبر splice() من ملف عادي، تحتوي قائمة التبعثر (scatterlist) الوجهة على مراجع لصفحات ذاكرة التخزين المؤقت للملف — أي أن النواة ستكتب إليها. بعد ذلك، تقوم خوارزمية authencesn(hmac(sha256), cbc(aes)) بكتابة خدشية (scratch) من 4 بايت لحقل seqno_lo الخاص بـ AAD (البايتات 4–7 من AAD المقدَّم عبر sendmsg) إلى تلك الوجهة، مما يُتلف نسخة الملف في ذاكرة التخزين المؤقت للصفحات.
نظرًا لأن الملف على القرص لا يتم تعديله أبدًا، فلا توجد بصمة على القرص؛ لا يلاحظ التلف سوى القرّاء الذين يشاركون ذاكرة التخزين المؤقت للصفحات. ملفّا /etc/passwd و /usr/bin/su قابلان للقراءة من الجميع، لذلك يمكن لمستخدم محلي غير ممتلّك أن يُتلف عرض النواة الحالي لأيٍّ منهما.
المتأثر: نوى لينكس التي تحمل الالتزام 72548b093ee3 (AEAD في المكان، 2017) دون التراجع المنبعث. أكّد الإفصاح تأثر Ubuntu 24.04 LTS وAmazon Linux 2023 وRHEL 14.3 وSUSE 16، لكن الآلية الأساسية تسبق هذا النطاق.
| الملف | الغرض |
|---|---|
test_cve_2026_31431.py | كاشف غير تدميري. يعمل على ملف حارس في مجلد مؤقت؛ لا يلمس أبدًا ملفات النظام الثنائية. |
exploit_cve_2026_31431.py | LPE. يحوّل UID للمستخدم الحالي إلى 0 في ذاكرة التخزين المؤقت للصفحات لـ /etc/passwd، ثم يستدعي su للحصول على صدفة جذر. |
كلا السكربتين مكتوبان بلغة Python 3.10+ من المكتبة القياسية فقط.
# 1. Detect
python3 test_cve_2026_31431.py
# exit 0 = not vulnerable, 2 = vulnerable, 1 = test error
# 2. Exploit (interactive — su will prompt for your own password)
python3 exploit_cve_2026_31431.py --shell
python3 test_cve_2026_31431.py
ما يفعله:
AF_ALG وخوارزمية authencesn(hmac(sha256),cbc(aes)) متاحتان من عملية غير ممتلّكة.sendmsg+cmsg مع ضبط seqno_lo على العلامة PWND، ثم ينقل 32 بايت من صفحة ذاكرة التخزين المؤقت للملف الحارس إلى مقبس عملية AF_ALG عبر os.splice().recv() لتحفيز فك التشفير. يفشل فحص المصادقة مع الخطأ EBADMSG؛ ومع ذلك يتم تنفيذ الكتابة الخدشية.فئات المخرجات:
Precondition not met — AF_ALG أو authencesn غير متاحين. رمز الخروج 0.VULNERABLE to CVE-2026-31431 — استقرّت العلامة PWND في الصفحة المنقولة. رمز الخروج 2.Page cache MODIFIED via in-place AEAD splice path — تمت الكتابة إلى الصفحة لكن العلامة لم تستقر في الموضع المتوقع. عُاملها كثغرة. رمز الخروج 2.Page cache intact — تم التصحيح. رمز الخروج 0.لا يلمس الكاشف أبدًا /usr/bin/su أو /etc/passwd أو أي ملف آخر خارج المجلد المؤقت الذي ينشئه، ويتم حذف ذلك الملف عند الخروج.
python3 exploit_cve_2026_31431.py # patch only, print next steps
python3 exploit_cve_2026_31431.py --shell # patch and exec `su <user>`
ما يفعله:
/etc/passwd ويحدد إزاحة البايت لحقل UID المكوّن من 4 أحرف.write4 عند تلك الإزاحة، لاستبدال UID بالقيمة 0000.pwd.getpwnam(user) للتأكد من أن libc يُبلغ الآن بأن UID هو 0.--shell، يتم تنفيذ execvp("su", ["su", user]). أدخل كلمة المرور الخاصة بك. يتحقق PAM من /etc/shadow (غير معدّل)، ثم تصل setuid(getpwnam(user).pw_uid) إلى 0.write4 وفقًا لذلك.nscd أو sssd أو systemd-userdbd) يحجب قراءات /etc/passwd. إذا استمر getpwnam في إرجاع UID الحقيقي بعد التصحيح، أعد تشغيل المخبأ أو تجاوزه، أو اختر مستخدمًا مختلفًا./etc/passwd في المخبأ بين التصحيح وتنفيذ su. عمليًا، هذا مضمون على أي نظام بضغط ذاكرة طبيعي.ملف /etc/passwd على القرص لم يتغير.
التشغيل التجريبي (exploit_cve_2026_31431.py بدون --shell) يقوم تلقائيًا بإخلاء الصفحة المتضررة عند الخروج عبر POSIX_FADV_DONTNEED، لذا تعود عمليات البحث من UID إلى الاسم إلى طبيعتها فورًا.
بعد --shell، تبقى الصفحة متضررة حتى تقوم بمسحها. وطالما كانت متضررة، فإن أي شيء يحوّل UID 1000 إلى اسم (مثل ls ومديري الملفات وفحوصات ملكية scp/sftp) سيفشل أو يعرض معرّفات رقمية. للمسح:
# unprivileged - request page-cache eviction for /etc/passwd:
python3 -c "import os; fd=os.open('/etc/passwd', os.O_RDONLY); \
os.posix_fadvise(fd, 0, 0, os.POSIX_FADV_DONTNEED); os.close(fd)"
# from the root shell:
echo 3 > /proc/sys/vm/drop_caches
إعادة التشغيل تمسحها أيضًا.
write4sendmsg([8-byte AAD], cmsg=[ALG_SET_OP=DECRYPT, ALG_SET_IV, ALG_SET_AEAD_ASSOCLEN=8],
flags=MSG_MORE)
splice(target_fd, pipe_w, 32, offset_src=file_offset)
splice(pipe_r, op_fd, 32)
recv(op_fd) # EBADMSG; scratch write has already landed
تكتب authencesn البايتات الأربعة من المواضع 4–7 في AAD (seqno_lo) في قائمة التبعثر الوجهة، والتي هي في هذا المسار البرمجي صفحة ذاكرة التخزين المؤقت التي نقلناها من target_fd عبر splice(). الإزاحة التي تستقر عندها الكتابة داخل الصفحة تقابل offset_src الذي مررناه إلى splice().
إلى أن يصل kernel المصحّح إلى توزيعتك:
sudo tee /etc/modprobe.d/disable-algif-aead.conf <<<'install algif_aead /bin/false'
sudo rmmod algif_aead 2>/dev/null
بعد التطبيق، يجب أن يُبلغ test_cve_2026_31431.py بالرسالة Precondition not met ويخرج برمز 0.
الإصلاح المنبعث يعيد عمليات AEAD من التنفيذ في المكان إلى التنفيذ خارج المكان، مما يُبقي صفحات ذاكرة التخزين المؤقت بعيدة عن قوائم التبعثر القابلة للكتابة.