
إثبات مفهوم يوضح الهروب من الحاوية على Kubernetes عبر CVE-2026-31431 المتعلق بتلف ذاكرة التخزين المؤقت للصفحات في النواة، مما يحقق تنفيذ كود على مستوى العقدة من حاوية غير مميزة.
إثبات مفهوم يوضح كيف يمكن لحاوية غير مميزة تمامًا تحقيق تنفيذ كود على مستوى العقدة في Kubernetes من خلال استغلال ثغرة CVE-2026-31431 في نواة Linux المتعلقة بتلف ذاكرة التخزين المؤقت للصفحات عبر طبقات صور الحاويات المشتركة.
إخلاء مسؤولية: هذا المستودع منشور لأغراض تعليمية ودفاعية فقط. استخدمه حصريًا على أنظمة تملكها أو لديك إذن صريح لاختبارها.
CVE-2026-31431 ("Copy Fail") هي ثغرة في نواة Linux في مسار النسخ عند الكتابة (CoW) لذاكرة التخزين المؤقت للصفحات. تسمح حالة سباق في AF_ALG splice لعملية غير مميزة بتلف صفحات ذاكرة التخزين المؤقت لملف للقراءة فقط. يستمر التلف في ذاكرة التخزين المؤقت للصفحات في النواة ويكون مرئيًا لكل عملية تقرأ أو تنفذ الملف لاحقًا — بما في ذلك العمليات في حاويات أخرى أو على المضيف.
للحصول على تفاصيل كاملة حول الثغرة الأصلية، راجع copy.fail.
تتكون سلسلة الهجوم من ثلاث مراحل: تلف ذاكرة التخزين المؤقت للصفحات، الانتشار عبر الحاويات، والتنفيذ المميز.
يكشف نظام AF_ALG الفرعي (التشفير) في النواة عن واجهة قائمة على المقابس (sockets) لعمليات التشفير في مساحة المستخدم. يستغل الاستغلال حالة سباق في كيفية تعامل النواة مع splice() من ملف إلى مقبس AF_ALG:
/usr/sbin/ipset) للقراءة فقط.authencesn(hmac(sha256),cbc(aes)).MSG_MORE، لإخبار النواة بتوقع المزيد من البيانات.splice() لمحتوى الملف الهدف من fd → أنبوب (pipe) → مقبس AF_ALG.يكرر الاستغلال هذا لكل نافذة من 4 بايتات حتى تتم الكتابة فوق جميع الصفحات المخزنة مؤقتًا للملف الهدف الثنائي بالكامل بحمولة مخصصة.
لا حاجة لأذونات الكتابة على الملف. الملف على القرص يبقى دون تغيير — فقط ذاكرة التخزين المؤقت للصفحات في الذاكرة يتم تلفها.
تستخدم بيئات تشغيل الحاويات (containerd، CRI-O) أنظمة ملفات overlay. عندما تشترك حاويتان في نفس طبقة الصورة، تخدم النواة قراءات الملفات الخاصة بهما من نفس صفحات ذاكرة التخزين المؤقت.
تم بناء صورة إثبات المفهوم هذه من FROM registry.k8s.io/kube-proxy:v1.35.2. يستخدم DaemonSet الخاص بـ kube-proxy على كل عقدة Kubernetes نفس الطبقة الأساسية تمامًا. نتيجة لذلك، يتوافق /usr/sbin/ipset في كلا الحاويتين مع نفس مجموعة صفحات ذاكرة التخزين المؤقت.
عندما تقوم حاوية إثبات المفهوم غير المميزة بتلف ذاكرة التخزين المؤقت لـ ipset، يكون التلف مرئيًا فورًا لحاوية kube-proxy المميزة على نفس العقدة — بدون أي اتصال بين الحاويات.
يعمل kube-proxy كـ DaemonSet مميز مع hostNetwork: true. يستدعي بشكل دوري /usr/sbin/ipset لإدارة قواعد iptables/ipset. عندما ينفذ ipset في المرة التالية، تقوم النواة بتحميل صفحات ذاكرة التخزين المؤقت التالفة، وتنفيذ حمولة المهاجم بصلاحيات kube-proxy الكاملة:
الحمولة في إثبات المفهوم هذا (payload/payload.c) تقوم ببساطة بتركيب نظام ملفات الجذر للمضيف وكتابة ملف علامة إلى /root/res كدليل على تنفيذ كود على مستوى العقدة.
┌──────────────────────────┐ ┌──────────────────────────┐
│ حاوية إثبات المفهوم │ │ حاوية kube-proxy │
│ (غير مميزة) │ │ (مميزة) │
│ │ │ │
│ 1. فتح /usr/sbin/ipset │ │ │
│ (للقراءة فقط) │ │ │
│ │ │ │
│ 2. حالة سباق AF_ALG │ │ │
│ splice تتلف ذاكرة │ │ │
│ التخزين المؤقت │ │ │
│ │ │ │ │
└──────────┼───────────────┘ └──────────────────────────┘
│ │
▼ │
┌─────────────────────┐ │
│ ذاكرة التخزين │ │
│ المؤقت للصفحات │ │
│ /usr/sbin/ipset │◄────────────────────┘
│ (تالفة) │ 3. kube-proxy ينفذ ipset
│ تحتوي على بايتات │ → تحميل الصفحات التالفة
│ حمولة المهاجم │ → الحمولة تعمل كـ root
└─────────────────────┘ على المضيف
.
├── cmd/copyfail/main.go # نقطة الدخول؛ يضم الحمولة المترجمة
├── internal/
│ ├── exploit/
│ │ ├── exploit.go # الاستغلال الأساسي: حلقة حالة سباق AF_ALG splice
│ │ └── patch.go # تقسيم الحمولة إلى نوافذ تصحيح من 4 بايتات
│ └── alg/
│ └── alg.go # تجريد مقبس AF_ALG AEAD
├── payload/
│ ├── payload.c # حمولة التحقق (تركيب نظام ملفات المضيف، كتابة علامة)
│ └── nolibc/ # مكتبة libc المصغرة من النواة لحمولات ثابتة بدون تبعيات
├── deploy/
│ └── poc.yaml # بيان نشر Kubernetes
├── Dockerfile # مبني من kube-proxy لمشاركة طبقات الصور
├── Makefile # تنسيق البناء
└── docs/ # أدلة التحقق من ACK (Alibaba Cloud)
x86_64-linux-gnu-gcc)imagePullPolicy: IfNotPresent (الافتراضي)# بناء الحمولة + ثنائي Go
make build
# بناء صورة Docker
make docker-build
# البناء والدفع إلى GHCR
make docker-push IMAGE=ghcr.io/<you>/copy-fail-poc TAG=latest
لأهداف arm64:
make build CC=aarch64-linux-gnu-gcc GOARCH=arm64
kubectl apply -f deploy/poc.yaml
ينشئ Deployment بودًا واحدًا غير مميز. يقوم بـ:
/bin/copyfail -target /usr/sbin/ipset لتلف ذاكرة التخزين المؤقت للصفحات.بعد أن ينفذ kube-proxy ipset في المرة التالية (يحدث هذا عادةً خلال ثوانٍ بسبب حلقة المزامنة الخاصة به، أو عند إعادة تشغيله التالية)، تحقق من العقدة:
# الاتصال عبر SSH بالعقدة، أو استخدام بود تصحيح مميز
cat /root/res
# الإخراج المتوقع: [*] success
وجود /root/res على نظام ملفات المضيف يثبت أن الكود المقدم من المهاجم تم تنفيذه بصلاحيات على مستوى العقدة — مكتوب من داخل سياق حاوية kube-proxy المميزة.
kubectl delete -f deploy/poc.yaml
# على العقد (العقد) المتأثرة، قم بإزالة العلامة وإعادة تشغيل kube-proxy:
rm -f /root/res
systemctl restart kubelet # أو حذف بود kube-proxy لفرض إعادة السحب
kube-proxy هدف مثالي لأنه:
privileged: true، hostNetwork: true.imagePullPolicy: IfNotPresent — بمجرد سحب صورة المهاجم ومشاركتها نفس الطبقة الأساسية، تتم مشاركة صفحات الطبقة السفلية من overlay.يمكن استهداف أي DaemonSet مميز تحتوي صورته على ثنائي يمكن التنبؤ به بنفس الطريقة.
الحمولة الافتراضية (payload/payload.c) هي برنامج تحقق فقط يكتب ملف علامة. لبناء حمولة مخصصة:
payload/payload.c. البرنامج مبني ضد nolibc (مكتبة C المصغرة من النواة) لثنائي ثابت بدون تبعيات.make payload للترجمة المتقاطعة.//go:embed.tools/include/nolibc/)كود استغلال Go في هذا المستودع مقدم كما هو لأغراض البحث.
الحمولة (payload/payload.c) مشتقة من copy-fail-c ومرخصة بموجب ترخيص مزدوج LGPL-2.1-or-later أو MIT. راجع LICENSE-LGPL و LICENSE-MIT.