
تقرير حول "Dirty Frag"، وهي سلسلة ثغرات تصعيد الامتيازات المحلية (LPE) في لينكس تسمح لمستخدم غير مميز بالحصول على صلاحيات الجذر.
مختبر إعادة إنتاج وكشف لسلسلة تصعيد صلاحيات محلية في نواة لينكس.
الحالة: تم التحقق. أكملت إعادة الإنتاج والتحقق بدون ملفات والكشف على مستوى استدعاءات النظام في المختبر (النواة 6.18.9+kali-amd64). هذه الوثيقة سجل مخبري. كل ادعاء أدناه تمت ملاحظته أثناء تشغيل إعادة الإنتاج. لقطات الشاشة والقطع الأثرية هي التقاطات حقيقية من الجهاز الافتراضي.
يجمع Dirty Frag بين خطأين منطقيين حتميين في نواة لينكس. تسمح هذه الأخطاء لمستخدم محلي غير مميز بالكتابة فوق ذاكرة التخزين المؤقت للصفحات (page cache) للملفات القابلة للقراءة فقط (مثل /usr/bin/su) والحصول على قشرة صلاحيات الجذر:
| المتغير | CVE | نقطة الاستغلال | مسار التشغيل | يتطلب مساحة أسماء مستخدمين غير مميزة |
|---|---|---|---|---|
| كتابة ذاكرة التخزين المؤقت للصفحات عبر xfrm‑ESP | CVE‑2026‑43284 | crypto_authenc_esn_decrypt() في esp_input() | socket(AF_INET) مع تغليف UDP، ثم xfrm_input() | نعم (CAP_NET_ADMIN) |
| كتابة ذاكرة التخزين المؤقت للصفحات عبر RxRPC | CVE‑2026‑43500 | rxkad_verify_packet_1() (pcbc(fcrypt)) | socket(AF_RXRPC) | لا |
يستخدم كلا المتغيرين نفس النمط الجذري مثل Dirty Pipe وCopy Fail. يضع استدعاء النظام splice(2) مرجعًا إلى صفحة من ذاكرة التخزين المؤقت للصفحات لملف في فتحة frag الخاصة بـ sk_buff على جانب المرسل. يمكن للمهاجم قراءة هذا الملف فقط. ثم يقوم كود النواة على جانب الاستقبال بتنفيذ عملية تخزين تشفيرية في المكان فوق هذا الجزء. يؤدي هذا إلى تغيير ذاكرة التخزين المؤقت للصفحات في الذاكرة العشوائية (RAM). لا يحدث أي كتابة على القرص، لذا لا يمكن لمراقبة سلامة الملفات (AIDE, Tripwire) رؤيتها. الهجوم حتمي. لا يحتوي على نافذة سباق ولا يسبب انهيار النواة عند الفشل.
cac2661c53f3 (2017‑01) إلى f4c50a4034e6 (تم التصحيح 2026‑05‑05)2dc334f1a63a (2023‑06) إلى aa54b1d27fe0 (تم التصحيح 2026‑05‑10)CVE-2026-43284 = 8.8 (عالية)، CVE-2026-43500 = 7.8 (عالية)Dirty Frag هو تصعيد صلاحيات محلي بدون ملفات. يفسد ذاكرة التخزين المؤقت للصفحات في الذاكرة، وليس الملف على القرص. لا يمكن لمراقبة سلامة الملفات التقليدية رؤيته. يجب أن يحدث الكشف على طبقة استدعاءات النظام. تستخدم السلسلة بدائيات استدعاءات النظام التالية: socket(AF_ALG)/socket(AF_RXRPC)، وsplice، وunshare(CLONE_NEWUSER|CLONE_NEWNET). ينشئ مسار ESP أيضًا مقابس UDP من نوع AF_INET ومقابس netlink. هذه الطبقة هي محور هندسة الكشف في هذا المستودع.
يستخدم كلا المتغيرين نفس نقطة الاستغلال: تشفير في المكان يقوم بتخزين بايتات على صفحة من ذاكرة التخزين المؤقت للصفحات يضعها المهاجم باستخدام splice(2).
UDP_ENCAP_ESPINUDP.vmsplice، ثم 16 بايت من /usr/bin/su عند إزاحة الملف المستهدفة باستخدام splice.splice واحدة تدفع الأنبوب إلى مقبس الإرسال. يضبط splice_to_socket() علامة MSG_SPLICE_PAGES. يضع هذا صفحة ذاكرة التخزين المؤقت لـ /usr/bin/su مباشرة في skb->frags[0].xfrm4_udp_encap_rcv، ثم xfrm_input، ثم esp_input(). يتجاوز فرع skip_cow الضعيف (!skb_cloned() && !skb_has_frag_list()) دالة skb_cow_data(). يقوم بتنفيذ فك تشفير AEAD في المكان مع استخدام صفحة ذاكرة التخزين المؤقت كمصدر ووجهة معًا.crypto_authenc_esn_decrypt() عملية تخزين للبتات الـ 32 العليا من ESN. تلك القيمة هي replay_esn->seq_hi. يختار المهاجم هذه القيمة عند تسجيل SA باستخدام سمة netlink XFRMA_REPLAY_ESN_VAL.يتحكم المهاجم في كل من الموقع (إزاحة splice) والقيمة (4 بايتات). يعمل التحقق من المصادقة بعد عملية التخزين، لذا لا تكتشف طبقة التشفير الكتابة أبدًا. يتطلب هذا المتغير CAP_NET_ADMIN ويستخدم unshare(CLONE_NEWUSER|CLONE_NEWNET).
تنفذ rxkad_verify_packet_1() فك تشفير كتلة واحدة pcbc(fcrypt) مباشرة على جزء skb المثبت بـ splice. لا تنسخ البيانات أولاً. يختار المهاجم مفتاح جلسة (add_key("rxrpc", …)) بحيث يساوي decrypt(ciphertext) قيمة desired_plaintext. ينتج عن هذا تخزين 8 بايتات. يستهدف هذا المتغير /etc/passwd. لا يحتاج إلى مساحة أسماء مستخدمين. يتطلب وحدة rxrpc.ko (محملة افتراضيًا على Ubuntu).
يستهدف إثبات المفهوم العام /usr/bin/su. يكتب 48 عملية تخزين ESP بحجم 4 بايتات لكل منها (192 بايتًا عند إزاحة الملف 0). يستبدل أول بايتات ذاكرة التخزين المؤقت للصفحات بملف ELF ثابت لقشرة الجذر. نقطة دخول ELF تنفذ setgid(0); setuid(0); setgroups(0,NULL); execve("/bin/sh", …). ثم يعطي تنفيذ واحد لـ execve("/usr/bin/su") قشرة صلاحيات الجذر.
تصحيح ESP (الرئيسي f4c50a4034e6) يضع علامة على أجزاء الصفحات التي تصل عبر splice() بعلامة SKBFL_SHARED_FRAG. يتحقق فرع skip_cow في esp_input() الآن أيضًا من هذه العلامة. تمر مقابس skb ذات الأجزاء المشتركة عبر skb_cow_data() قبل فك تشفير AEAD في المكان.
تصحيح RxRPC (الرئيسي aa54b1d27fe0) يضيف فحص skb->data_len بجوار فحص skb_cloned() الموجود. تنسخ النواة مقبس skb غير الخطي مع بيانات مقسمة إلى صفحات قبل فك تشفير pcbc(fcrypt) في المكان.
| المكوّن | التفاصيل |
|---|---|
| برنامج المحاكاة الافتراضية | VirtualBox |
| الجهاز الافتراضي المستهدف | Kali Linux 2026.1 (تمت استعادة لقطة إلى حالة ضعيفة) |
| النواة | 6.18.9+kali‑amd64 (أقدم من إصلاحات مايو 2026) |
| إثبات المفهوم | V4bel/dirtyfrag (ملف C واحد) |
| الكشف | auditd (القواعد في detection/dirtyfrag.rules) |
لقطة شاشة لإعداد مختبر VirtualBox:

.
├── README.md # سجل المختبر هذا
├── detection/
│ ├── dirtyfrag.rules # قواعد كشف على مستوى استدعاءات النظام لـ auditd
│ ├── ausearch_dirtyfrag_observed.txt # مخرجات كشف الاستغلال الحقيقية
│ ├── sigma/
│ │ └── dirty_frag_exploit.yml # قاعدة Sigma لكشف SIEM
│ └── yara/
│ └── dirty_frag_exploit.yar # قاعدة YARA لكود إثبات المفهوم على القرص/الذاكرة
├── mitigation/
│ └── dirtyfrag_mitigation.sh # قائمة حظر الوحدات + مسح ذاكرة التخزين المؤقت للصفحات
├── poc/
│ └── check_vulnerable.py # فاحص أولي غير مدمر
├── reports/
│ └── incident-dirtyfrag.md # دليل الاستجابة للحوادث
└── screenshots/ # التقاطات حقيقية من الجهاز الافتراضي للمختبر
poc/check_vulnerable.py وتأكيد النواة/الوحدات/مساحة أسماء المستخدمينtestuser غير مميز/usr/bin/su التالفة والمستعادةdrop_caches أو إعادة التشغيل)detection/dirtyfrag.rules والتحقق من تنبيهات auditdreports/incident-dirtyfrag.md)