
إثبات مفهوم وظيفي لـ CVE-2026-17106 (CopyEscape): سباق TOCTOU في docker cp يتيح الكتابة الاعتباطية على مضيف Docker. مختبر Docker + مراقب inotify + LD_PRELOAD. نسخة macOS غير ضارة ونسخة Linux مدمرة.
إثبات مفهوم تعليمي لـ CopyEscape (CVE-2026-17106)، ثغرة سباق TOCTOU في
docker cpتسمح لحاوية خبيثة بكتابة ملفات عشوائية على مضيف Docker. مستوحاة من العمل الأصلي لـ masasron، الذي اكتشف ووثّق الثغرة في مدونة "CopyEscape: Taking Over Docker Hosts with docker cp".
CVE-2026-17106 هو ثغرة سباق (TOCTOU) في استخراج ملف tar الذي يولّده برنامج Docker الخفي أثناء docker cp <contenedor>:<ruta> <destino>. تؤثر على Docker CLI 29.6.1 والإصدارات الأقدم؛ وتم إصلاحها بدءًا من 29.7.0. يقع الخلل في CLI (استخراج tar على المضيف)، وليس في البرنامج الخفي.
السلسلة المسماة CopyEscape تبيّن كيف يمكن لمهاجم، انطلاقًا فقط من حاوية قيد التشغيل دون صلاحيات إضافية، أن:
/watched/file.txt/ كملف عادي أمام أي عملية تفتحه داخل الحاوية، عبر مكتبة LD_PRELOAD تعترض open, openat, openat2, fopen, stat, lstat, fstatat, statx وإصدارات 64.aaa.txt بحجم 16 MiB يجبر البرنامج الخفي على التأخر بما يكفي في إنتاج tar ليتمكن المراقب من الفوز بالسباق.inotify، وفي نافذة السباق، يستبدل دليلًا فرعيًا escape/ باختصار رمزي (symlink) مطلق إلى هدف المضيف (/Users/<usuario> على macOS أو /usr/bin على Linux) عبر استدعاءَي rename(2) ذرّيين مع تراجع (rollback).escape متبوعًا بإدخال فرعي escape/<basename>؛ CLI المعيبة تنشئ الاختصار الرمزي على العميل وتستخرج الإدخال الفرعي من خلاله، فتُكتب خارج الوجهة التي اختارها المستخدم.النتيجة هي كتابة ملفات عشوائية على المضيف بصلاحيات العملية التي تنفّذ docker cp. بديل Linux يكتب فوق /usr/bin/runc ويحقق تنفيذ كود بصلاحيات root على المضيف عند أول docker run / exec لاحق.
يحتوي هذا المستودع على مواد تعليمية ودفاعية بشكل صارم.
runc على المضيف: استخدمه فقط في جهاز افتراضي (VM) قابل للتخلص مع نسخة احتياطية موثّقة.يُسلَّم إثبات المفهوم مع بديل macOS غير ضار (يكتب ~/pwnd كعلامة) هدفه الوحيد أن يكون بمثابة عرض توضيحي قابل لإعادة الإنتاج.
┌─────────────────────────────────────────────────────────────────────┐
│ 1. LD_PRELOAD camufla /watched/file.txt como archivo regular │
│ open/openat/openat2/fopen/stat/lstat/fstatat/statx → decoy │
│ docker exec ... cat /watched/file.txt → "top-level file" │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 2. Layout real dentro del contenedor │
│ /watched/file.txt/ │
│ ├── aaa.txt (16 MiB de 'B', cebo lento) │
│ ├── escape/ (directorio real inicial) │
│ ├── escape/<basename> (payload: runc o pwnd) │
│ └── .swap-escape (symlink → /Users/<usr> o /usr/bin) │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 3. docker cp pide tar al daemon │
│ daemon recorre /watched/file.txt/ y abre aaa.txt │
│ inotify detecta IN_OPEN sobre aaa.txt │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 4. Monitor pivot: dos rename(2) atomicos con rollback │
│ escape/ → .old-escape/ (backup) │
│ .swap-escape → escape/ (symlink al target del host) │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 5. Tar resultante contiene: │
│ escape → /Users/<usr> (symlink absoluto) │
│ escape/<basename> (entrada hija que atraviesa el symlink) │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 6. CLI vulnerable extrae symlink + hija │
│ crea escape → /Users/<usr> en el destino local │
│ extrae escape/<basename> A TRAVES del symlink │
│ escribe /Users/<usr>/<basename> en el host │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ macOS: ~/pwnd con "COPYESCAPE_MACOS_DEMO" (demo inocua) │
│ Linux: /usr/bin/runc sobrescrito (RCE como root) │
└─────────────────────────────────────────────────────────────────────┘
تم بناء إثبات المفهوم ليُشغَّل على macOS مع:
curl, tar, git و docker في PATH.alpine:3.21.HOME بالصيغة /Users/<usuario>.لا حاجة لصلاحيات root لبديل macOS. يتطلب بديل Linux صلاحيات root وجهازًا افتراضيًا (VM) قابلًا للتخلص.
يقوم المُشغِّل run-poc.sh بتنزيل ثنائي CLI المعيبة 29.6.1 تلقائيًا من الموقع الرسمي لـ Docker (download.docker.com). لا يعدّل تثبيت Docker Desktop على النظام: يستخدم البرنامج الخفي الحالي لكنه يستدعي الثنائي المُنزَّل لعملية docker cp.
POC CopyEscape (CVE-2026-17106)/
├── README.md ← Este archivo
├── LICENSE ← Licencia MIT
├── .gitignore
├── Dockerfile ← Dockerfile unificado (macos | linux)
├── entrypoint.sh ← Arranque del monitor sin LD_PRELOAD
├── monitor.c ← Monitor inotify unificado (una sola fuente)
├── watched_preload.c ← LD_PRELOAD con cobertura ampliada
└── run-poc.sh ← Runner robusto con reintentos
يتم استبعاد دليل
cli-vulnerable/(CLI 29.6.1 المُنزَّلة) من المستودع عبر.gitignore. يقوم المُشغِّل بتنزيلها تلقائيًا إذا لم تكن موجودة.
cd poc-v2
./run-poc.sh
يقوم المُشغِّل بـ: