
إثبات مفهوم يوضح الهروب من الحاوية على Amazon EKS من خلال استغلال Dirty Frag (CVE-2026-43284) لتلف ذاكرة التخزين المؤقت للصفحات في النواة عبر طبقات الصور المشتركة و DaemonSets ذات الامتيازات.
إثبات مفهوم يوضح كيف يمكن لـ Pod Kubernetes افتراضي غير مميز تحقيق تنفيذ كود على مستوى العقدة على Amazon EKS من خلال استغلال ثغرة Dirty Frag في تلف ذاكرة التخزين المؤقت لصفحات نواة Linux عبر طبقات صور الحاويات المشتركة.
البدائية الهجومية الأساسية هي: أي DaemonSet مميز يشارك طبقات الصور مع حاوية يتحكم فيها المهاجم يمكن تسليحه للهروب من الحاوية. يستخدم هذا الإثبات kube-proxy كمثال ملموس واحد، لكن التقنية تعمم على أي عبء عمل مميز على الكتلة.
تم التحقق على Amazon EKS (kernel 6.12.80) — يكتب Pod غير مميز [*] success إلى نظام ملفات المضيف عبر DaemonSet kube-proxy المميز:

إخلاء مسؤولية: يُنشر هذا المستودع لأغراض تعليمية ودفاعية فقط. استخدمه حصريًا على الأنظمة التي تمتلكها أو لديك إذن صريح لاختبارها.
Dirty Frag (CVE-2026-43284) هي ثغرة تلف في ذاكرة التخزين المؤقت لصفحات نواة Linux في مسار استقبال xfrm/ESP. في المسار المتأثر، يمكن لـ esp_input() تخطي skb_cow_data() لـ skb غير خطي بدون frag_list، مما يسمح لـ crypto_authenc_esn_decrypt() بتخزين 4 بايت من البيانات التي يتحكم فيها المهاجم في صفحة من ذاكرة التخزين المؤقت للصفحات يتم الوصول إليها عبر splice().
الملف على القرص لا يتم تعديله. البايتات التالفة موجودة في ذاكرة التخزين المؤقت للصفحات في النواة ويتم ملاحظتها من قبل القراء اللاحقين لنفس صفحة الملف المخزنة مؤقتًا.
للحصول على التفاصيل الكاملة حول الثغرة الأصلية، راجع V4bel/dirtyfrag.
يستغل الهجوم ثلاث خصائص تتعايش عادةً في مجموعات Kubernetes:
privileged: true, hostNetwork: true, قدرات واسعة، إلخ) تنفذ بشكل دوري ملفات ثنائية من صورها.عندما تتوافق هذه الشروط، يمكن لـ Pod غير مميز إتلاف ملف ثنائي في طبقة صورة مشتركة، وسيقوم DaemonSet مميز على نفس العقدة بتنفيذ الملف الثنائي التالف دون علم بصلاحياته المرتفعة — محققًا تنفيذ كود كامل على مستوى العقدة.
هدف الثغرة ليس محدودًا بـ kube-proxy. أي DaemonSet مميز (وكلاء مراقبة، إضافات CNI، جامعو السجلات، وكلاء أمان، إلخ) التي تشترك صور حاوياتها في طبقات مع صورة يتحكم فيها المهاجم هي هدف قابل للتطبيق.
هذا المشروع مستوحى من نموذج استغلال Kubernetes الموثق في Copy Fail Kubernetes PoC، لكنه يستخدم بدائية نواة مختلفة.
سلسلة الهجوم لها ثلاث مراحل: تلف ذاكرة التخزين المؤقت للصفحات، الانتشار عبر الحاويات، والتنفيذ المميز.
ينفذ الملف الثنائي للإثبات التسلسل التالي من حاوية غير مميزة:
unshare(CLONE_NEWUSER | CLONE_NEWNET).splice() ومدخلات ESP مصممة بعناية لتحفيز مسار النواة الضعيف.لا يلزم إذن كتابة للملف المستهدف. الملف على القرص لا يتغير — فقط ذاكرة التخزين المؤقت للصفحات في الذاكرة تتلف.
تخدم بيئات تشغيل الحاويات القراءات من الطبقات السفلية overlay عبر ذاكرة التخزين المؤقت للصفحات في النواة. إذا كانت حاوية الإثبات وkube-proxy تشتركان في نفس ملف الطبقة السفلية، فكلاهما يلاحظ نفس الصفحات المخزنة مؤقتًا.
صورة EKS في هذا المستودع مبنية من:
public.ecr.aws/eks-distro-build-tooling/eks-distro-minimal-base-iptables:2026-03-11-1773190710.2023
تم اختيار هذه القاعدة لتطابق طبقة سلسلة أدوات مساحة مستخدم kube-proxy في EKS المستخدمة في البيئة التي تم التحقق منها.
عندما ينفذ kube-proxy بعد ذلك ملفًا ثنائيًا مصححًا من عائلة iptables، تقوم النواة بتحميل الصفحات المخزنة مؤقتًا التالفة. تقوم حمولة الإثبات بتركيب جهاز الجذر للمضيف وتكتب ملف علامة إلى /root/res.
المحتوى المتوقع للعلامة هو:
[*] success
┌──────────────────────────────┐ ┌────────────────────────┐ ┌──────────────────────────┐
│ Pod الإثبات │ │ ذاكرة التخزين المؤقت │ │ DaemonSet kube-proxy │
│ حاوية غير مميزة │ │ لصفحات النواة │ │ حاوية مميزة │
│ │ │ │ │ │
│ 1. unshare user+net ns │ │ │ │ │
│ 2. تثبيت xfrm SAs │ │ │ │ │
│ 3. splice الملف الثنائي │────▶│ ملف ثنائي بطبقة │────▶│ ينفذ ملفًا ثنائيًا │
│ المستهدف عبر مسار ESP │ │ مشتركة تم تصحيح │ │ مصححًا، تعمل الحمولة │
│ │ │ ذاكرة التخزين المؤقت │ │ بصلاحيات مستوى العقدة │
└──────────────────────────────┘ └────────────────────────┘ └──────────────────────────┘
لقد اختبرت هذا على مجموعات GKE و ACK. جميعها فشلت.
بدائية Dirty Frag تتطلب إنشاء مساحة اسم مستخدم (CLONE_NEWUSER) للحصول على CAP_NET_ADMIN داخل مساحة اسم شبكة جديدة. كل من ACK و GKE يحظران هذا على مستوى العقدة عبر آليات مختلفة:
user.max_user_namespaces=0) يمنع تمامًا إنشاء مساحة اسم مستخدم غير مميزة.--seccomp-default) يحظر استدعاء نظام unshare بغض النظر عن حد مساحة الاسم.هذا فرق رئيسي عن Copy Fail (CVE-2026-31431)، الذي لا يتطلب مساحات أسماء مستخدمين ويستغل بنجاح جميع المنصات الثلاث.
يقوم متغير EKS المقدم بتصحيح الملفات الثنائية التالية عند وجودها:
/usr/sbin/xtables-legacy-multi
/usr/sbin/xtables-nft-multi
يتم استدعاء هذه الملفات الثنائية بواسطة سلسلة أدوات iptables المستخدمة بواسطة kube-proxy. يعتمد توقيت التحفيز الدقيق على نشاط مزامنة العقدة والخدمة. في البيئة التي تم التحقق منها، تم تحفيز الحمولة بواسطة مزامنة kube-proxy العادية.
تحذيرات مهمة:
ipset فقط عند تكوينه في وضع ipvs. الوضع الافتراضي (iptables) لا يستخدم ipset.xtables-legacy-multi, xtables-nft-multi) لتغطية أوضاع الوكيل المختلفة، لكن ما إذا تم استدعاؤها يعتمد على تكوين الكتلة.إذا لم يكن kube-proxy مميزًا في مجموعتك، فإن مبدأ الهجوم لا يزال صحيحًا — تحتاج فقط إلى تحديد DaemonSet مميز مختلف يشارك طبقات الصور مع صورة أساسية يمكنك البناء منها.
.
├── exploit/
│ └── dirtyfrag.c # كاتب ذاكرة التخزين المؤقت للصفحات xfrm/ESP
├── payload/
│ ├── payload-eks.c # حمولة nolibc تكتب /root/res على المضيف
│ └── nolibc/ # رؤوس Linux nolibc
├── deploy/
│ └── poc-eks.yaml # بيان Deployment EKS غير مميز
├── scripts/
│ ├── setup-eks.sh # نسخ وبناء واستيراد الصورة على عقدة EKS
│ ├── run-poc.sh # نشر والتحقق من العلامة
│ └── cleanup.sh # إزالة الـ pod والعلامة والصفحات المخزنة مؤقتًا والصورة المحلية
├── Dockerfile.eks # صورة EKS مبنية على eks-distro-minimal-base-iptables
├── Makefile # أهداف بناء الحمولة والإثبات وDocker وnerdctl
└── .github/workflows/
└── docker-publish.yml # سير عمل نشر GHCR
# بناء الحمولة + ملف الإثبات الثنائي
make build-eks CC=x86_64-linux-gnu-gcc
# بناء صورة Docker
make docker-build-eks
# النشر (pod غير مميز)
kubectl apply -f deploy/poc-eks.yaml
# التحقق من السجلات
kubectl logs deployment/dirtyfrag-poc-eks
# التحقق من الهروب على العقدة
ssh ec2-user@<node-ip> "sudo cat /root/res"
# المتوقع: [*] success
ينشر سير عمل GitHub Actions (.github/workflows/docker-publish.yml) الصورة إلى GHCR عند الدفع إلى main أو إنشاء علامة. استبدل <owner> في deploy/poc-eks.yaml بمستخدم أو مؤسسة GitHub التي تمتلك النسخة.
kubectl delete -f deploy/poc-eks.yaml --ignore-not-found
ssh ec2-user@<node-ip> "sudo rm -f /root/res"
kubectl delete pod -n kube-system -l k8s-app=kube-proxy --force
f4c50a4034e6).f4c50a4034e6 أو النقل الخلفي من البائع.esp4 و esp6 إذا لم يكن IPsec ESP مطلوبًا على عقد العمل.user.max_user_namespaces=0 يمنع هذا الإثبات من الحصول على CAP_NET_ADMIN في مساحة اسم شبكة جديدة (هذا بالفعل الافتراضي على ACK).privileged: true والوصول الواسع للمضيف إلا إذا كان مطلوبًا بشدة.مثال على حظر الوحدة:
printf 'install esp4 /bin/false\ninstall esp6 /bin/false\n' | sudo tee /etc/modprobe.d/dirtyfrag.conf
sudo rmmod esp4 esp6 2>/dev/null || true
كود الاستغلال مقتبس من V4bel/dirtyfrag بموجب ترخيص MIT.
كود الحمولة مشتق من tgies/copy-fail-c وهو مرخص بموجب LGPL-2.1-or-later أو MIT.
رؤوس nolibc من البنية التحتية لاختبار الذات لنواة Linux.
| الخاصية | Copy Fail | Dirty Frag |
|---|
| CVE | CVE-2026-31431 | CVE-2026-43284 |
| مسار النواة | AF_ALG + splice() | xfrm/ESP + splice() |
| متطلب مساحة الاسم | غير مطلوب | يتطلب مساحات أسماء المستخدمين |
| القدرة الرئيسية المستخدمة | لا شيء في الحاوية الأولية | CAP_NET_ADMIN داخل مساحة اسم الشبكة الجديدة |
| الوحدة ذات الصلة | algif_aead | esp4 |
| التمييز العملي | يفشل إذا تم حظر متجه AF_ALG | لا يزال ذا صلة عندما يكون AF_ALG غير متاح ولكن ESP ومساحات أسماء المستخدمين مفعلة |
| الخاصية | القيمة |
|---|
| المنصة | Amazon Elastic Kubernetes Service (EKS) |
| نواة العقدة | 6.12.80-106.156.amzn2023.x86_64 |
| حالة التصحيح | نواة قبل الإصلاح، تفتقد f4c50a4034e6 |
وحدة esp4 | محملة |
| مساحات أسماء المستخدمين | مفعلة (user.max_user_namespaces=15030) |
| SELinux | متساهل |
| Seccomp | غير مقيد في سياق الـ pod المختبر |
| DaemonSet المستهدف | kube-proxy |
| الصلاحيات المستهدفة | privileged: true, hostNetwork: true |
| وضع الوكيل | iptables |
| مسار العلامة | /root/res |
| المنصة | النتيجة | السبب |
|---|
| Alibaba Cloud ACK | فشل | user.max_user_namespaces مضبوط على 0 في صور العقد الافتراضية، لذا لا يمكن للمستخدمين غير المميزين استخدام CLONE_NEWUSER unshare. |
| Google GKE | فشل | user.max_user_namespaces هو 15426، لكن kubelet يفعل --seccomp-default. سياسة seccomp الافتراضية تعطل استدعاء نظام unshare. |