Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
page_inject — CVE-2026-31431-killed استغلال page-cache — تنفيذ كود داخل الحاويات التي تشترك في نفس طبقة الصورة | Kitploit
أدوات/GitHubGitHub/sgkdev/page_inject
تحليل الثغرات الأمنيةالاستغلالما بعد الاستغلالاختبار الاختراقالفريق الأحمرالهروب من الحاويةاستغلال الملفات الثنائية
GitHubsgkdev/page_inject

page_inject

CVE-2026-31431-killed استغلال page-cache — تنفيذ كود داخل الحاويات التي تشترك في نفس طبقة الصورة

عرض المستودع
7414منذ 3 أشهرتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

page_inject - AF_ALG aead الهروب عبر الحاويات

استغلال AF_ALG aead للهروب عبر الحاويات -- الانتقال من حاوية مخترَقة إلى كل حاوية شقيقة تتشارك طبقة الصورة libc.so.6 نفسها.

هذه بدائية هروب: تعمل من داخل حاوية غير مميَّزة سبق للمهاجم اختراقها، وتستغل خطأ الكتابة الاعتباطية لأربعة بايتات في تدوير ESN الخاص بـ authencesn في AF_ALG (CVE-2026-31431) لزرع خطاف read() دائم في صفحات مخبأ صفحات libc.so.6. ولأن Docker/containerd تُسنِد ملفات الطبقة السفلية في overlayfs إلى inodes مشتركة، فإن تلك الصفحات تكون مرئية لكل حاوية شقيقة أُنشئت من الصورة نفسها -- يشتعل الخطاف في عملياتها أيضًا، ويحصل المهاجم على تنفيذ أوامر داخل كل واحدة منها.

نموذج التهديد

  • المهاجم لديه وصول shell إلى حاوية واحدة (لنسمِّها victim) على مضيف يشغّل حاويات أخرى (siblings) من نفس الصورة التي يعمل بها victim.
  • تعمل victim بوضع Docker/k8s الافتراضي: uid غير مميَّز داخل مساحة أسماء المستخدمين للحاوية، وملف تعريف seccomp افتراضي، وملف تعريف AppArmor افتراضي، وبلا أي قدرات خاصة، وبلا تحميلات bind من المضيف.
  • تمتلك victim فقط:
    • وصول قراءة إلى libc الخاصة بها (/usr/lib/x86_64-linux-gnu/libc.so.6 أو أيًا كان المسار الذي تثبّته فيه التوزيعة)
    • عائلة استدعاءات النظام القياسية socket(AF_ALG, ...)
    • استدعاءَي النظام القياسيين splice / vmsplice
    • وصول كتابة إلى دليل يمكنها تنفيذ chmod +x عليه (مثل /tmp)
  • يجب أن تكون النواة قابلة للاستغلال بـ CVE-2026-31431 (أي بناء algif_aead + authencesn أقدم من إصلاح التراجع في upstream).

هذا كل شيء. لا قدرات CAP_* خاصة، ولا وصول إلى نظام ملفات المضيف. يضع المهاجم ملفًا ثنائيًا مكتفيًا بذاته ومرتبطًا بشكل ثابت داخل الحاوية، ويشغّله، فيصبح إفساد مخبأ الصفحات -- وبالتالي الخطاف -- مرئيًا لكل حاوية شقيقة.

كيف تتسلسل خطوات الاستغلال معًا

  1. هوية صفحة مخبأ الصفحات. داخل حاوية overlayfs، يُقدَّم /usr/lib/.../libc.so.6 من inode ext4 الخاص بطبقة الصورة السفلية. كل حاوية أُطلقت من الصورة نفسها تتشارك ذلك الـ inode الداعم، ويكون مخبأ صفحات النواة مفتاحه هو الـ inode الأساسي -- لا overlay ولا مساحة الأسماء. لذا فإن كتابة واحدة من 4 بايتات داخل صفحة من مخبأ الصفحات تكون مرئية لعمليات جميع الحاويات الشقيقة التي لديها تلك الصفحة مُخطَّطة عبر mmap.

  2. ثغرة AF_ALG aead تحوّل كتابة واحدة كهذه إلى كتابات كثيرة. يربط algif_aead بين iovec الخاص بمستخدم RX وبايتات authsize اللاحقة من SGL الخاص بـ TX المُوصَل عبر splice، ويودع تدوير ESN في authencesn 4 بايتات من حقل seq_high الخاص بـ AAD عند dst[assoclen + cryptlen] -- وهو أول بايت في ذلك الذيل الأجنبي المربوط. الصفحة المُوصَلة هي صفحة من مخبأ الصفحات لملف لا يملك المهاجم سوى وصول قراءة إليه، لكن الشفرة cipher تنسخ البايتات إليها على أي حال، دون أي تسجيل للصفحات كمعدَّلة (dirty). (انظر crypto/algif_aead.c و crypto/authencesn.c لفهم الآليات الكامنة.)

  3. التمهيد لبدائية قابلة للاستدعاء. أول ما يفعله page_inject هو تمهيد المنطقة A -- إعادة تنفيذ مشفّرة بلغة التجميع لرقصة AF_ALG نفسها (write_cache.asm)، موضوعة داخل كهف الخاص بـ libc. وهذا يجعل كتابة الـ 4 بايتات استدعاء عاديًا من داخل أي حمولة خطاف مستقبلية، دون الحاجة إلى إعداد socket عند كل استدعاء.

البناء

يُبنى الحاقن خارج حاوية الضحية -- عادةً على جهاز التطوير الخاص بالمهاجم -- لأن معظم صور الحاويات الإنتاجية لا تتضمن مترجمًا. تكفي بيئة تطوير Linux x86_64 قياسية مع gcc (بدعم الربط -static) وnasm.

root@kitploit:~
make            # assembles .asm sources via gen_arrays.sh, links static page_inject
make shellcode  # also produces inspectable .bin flat binaries
make clean      # removes generated files and the binary

الناتج هو ملف ELF واحد مرتبط بشكل ثابت (./page_inject) يعمل على أي نواة Linux حديثة بمعمارية x86_64.

التسليم والاستخدام (من داخل حاوية الضحية)

بمجرد حصول المهاجم على shell على victim، يرفع الملف الثنائي إلى دليل قابل للكتابة (عادةً /tmp):

root@kitploit:~
# inside the compromised container, attacker session
victim$ ./page_inject

عند عدم تمرير أي وسائط، يعتمد page_inject على المسار الافتراضي /usr/lib/x86_64-linux-gnu/libc.so.6 (موقع Debian/Ubuntu بعد دمج /usr). أما في التوزيعات الأخرى فموضع libc مختلف؛ إمّا أن تمرّره صراحةً أو تستخدم --root / لمسح جدول البحث المدمج انطلاقًا من جذر الحاوية:

root@kitploit:~
# Fedora / Rocky / CentOS
victim$ ./page_inject /usr/lib64/libc.so.6

# Arch
victim$ ./page_inject /usr/lib/libc.so.6

# Auto-detect, regardless of distro:
victim$ ./page_inject --root /

أيٌّ من الاستدعاءين يفعل الأمر نفسه: تحليل libc داخل الحاوية بصيغة ELF، وتثبيت الخطاف في مخبأ صفحاتها، ومراقبة جدول الخانات لنحو 30 ثانية بينما تسجّل الحاويات الشقيقة، وتنفيذ id لمرة واحدة على أول حاوية شقيقة سجّلت بوصفه فحص سلامة.

بعد التمهيد، ادخل إلى صدفة الأوامر للتحكم في أي حاوية شقيقة مسجَّلة:

root@kitploit:~
victim$ ./page_inject --shell --no-bootstrap
=== page-cache shell ===
Containers (3):
  [0] 0x0018598d  <- target
  [1] 0x001859ab
  [2] 0x001859cd

inject:0018598d> exec id
uid=0(root) gid=0(root) groups=0(root)
inject:0018598d> target 0x001859ab
inject:001859ab> exec hostname
1ccd66abee9d
inject:001859ab> exec cat /etc/shadow
root:$6$.....
inject:001859ab> unhook
... read() prologue restored, slot table zeroed ...

يزيل unhook الخطاف من كل حاوية شقيقة دفعة واحدة ويتيح لعمليات الخطاف الفرعية إنهاء نفسها.

root@kitploit:~
Usage: page_inject [OPTIONS] [LIBC_PATH]

Options:
  --root <prefix>   Auto-resolve libc.so.6 under <prefix> using the
                    built-in fixed-path lookup table. Inside the
                    victim container that's normally --root / .
  --shell [0xKEY]   Drop into interactive command shell after
                    injection. Optional KEY pre-selects the target.
  --no-bootstrap    Skip injection (shell-only; hook must already
                    be live in the page cache).
  --timeout SEC     Slot monitoring timeout in --shell mode
                    (default 30 s).
  --help, -h        Show help.

Default libc (when no --root and no LIBC_PATH given):
  /usr/lib/x86_64-linux-gnu/libc.so.6

مسار الحقن المزدوج

تترك بنيات glibc المختلفة مقادير متباينة من مساحة كهف .text بين مقطع LOAD القابل للتنفيذ ومقطع LOAD التالي للقراءة فقط. يختار page_inject بين تخطيطين عند وقت الحقن:

  • المسار A -- libc فقط (افتراضي). تعيش كلٌّ من المنطقة C والمنطقة A في كهف .text الخاص بـ libc. وتعيش مناطق جدول الخانات + CMD + OUTPUT في قسم .hash الخاص بـ libc -- بيانات تجزئة SysV القديمة التي لا يقرؤها ld.so وقت التشغيل لأنه يستخدم .gnu.hash بدلًا منها. عندما يكون .hash غائبًا (سلسلة أدوات Arch الحديثة)، ينحت page_inject نطاق الخانات من ذيل .eh_frame_hdr بدلًا من ذلك، بعد أن يقلّص أولًا حقل fde_count بحيث لا يعود unwinder يعتبر البايتات المحرَّرة جزءًا من فهرس البحث الثنائي لـ FDE (يسقط unwinder بشفافية إلى مسح خطّي لـ .eh_frame لأي IP كانت FDE الخاص به ضمن النطاق المبتور -- سلوك تفرضه LSB).

  • المسار B -- قفزة libc العابرة + حمولة ld.so. تصغّر بعض بنيات glibc كهف libc إلى ما دون الحجم المطلوب لحمولة المنطقة C + المنطقة A الكاملة (تأتي Ubuntu 24.04 / glibc 2.39 بكهف حجمه 711 بايتًا). في هذه الحالة يكتب page_inject قفزة عابرة (trampoline) بحجم 36 بايتًا في كهف libc -- وهي تؤدي بوابة مفتاح .bss الخاصة بالمسار السريع داخل libc ذاتها -- وفي المسار البطيء تحسب العنوان الأساسي لـ ld.so وقت التشغيل من خانة GOT في libc الخاصة بالرمز _rtld_global (رمز من جانب ld.so تستورده كل glibc بشكل خاص) وتقفز إلى نسخة من المنطقة C تعتمد سجل العنوان الأساسي في كهف الخاص بـ . تبقى مناطق جدول الخانات + CMD + OUTPUT + مفتاح كلها في libc؛ وتصل إليها المنطقة C من جانب ld.so عبر بعد أن تهيّئ القفزة العابرة .

إذا لم يناسب أيٌّ من التخطيطين، يرفض page_inject رفضًا نظيفًا دون أن يكتب أي شيء إلى libc أو ld.so سواء على القرص أو في مخبأ الصفحات.

معالجة مقدمة read()

تُصدر إصدارات glibc المختلفة تسلسلات افتتاحية مختلفة في read(). يتعرّف الحاقن على كل واحدة منها، ويعيد قراءة البايتات التي يزيحها الخطاف، ويحاكيها في المسار السريع للمنطقة C بحيث يستأنف read() أحادي الخيط عمله بشكل صحيح عند read+N:

خانة المحاكاة في المسار السريع للمنطقة C مصمَّمة بحجم أطول مقدمة معروفة (8 بايتات) بالإضافة إلى قفزة rel32 ذات الخمسة بايتات؛ أما المقدمات الأقصر فتملأ البايت الأخير من الخانة بحشو NOP ليظل الطول الكلي للخانة ثابتًا.

تخطيط الملفات

root@kitploit:~
page_inject/
  page_inject.c           Main injector: ELF parsing, vuln primitive,
                          dual-path layout selection, inject + unhook.
  zone_c.asm              Path-A hook dispatcher shellcode.
  zone_c_ld.asm           Path-B hook dispatcher (rbp-base variant).
  trampoline.asm          Path-B 36-byte libc-side stub.
  write_cache.asm         Zone A (vuln write primitive shellcode).
  gen_arrays.sh           Assemble .asm -> asm_bytecode.c.
  asm_bytecode.c          [generated] shellcode byte arrays.
  Makefile                Build system.

مصفوفة الاختبار والدعم

تم التحقق من الاستغلال من البداية إلى النهاية على توزيعات الحاويات التالية. في كل إدخال، حُقن page_inject من داخل حاوية واحدة ورُصد إطلاق خطافه في حاوية شقيقة أُطلقت من الصورة نفسها؛ ونُفذت الأوامر بشكل صحيح عبر قناة مخبأ الصفحات؛ وأعاد unhook حالة صفحات libc إلى نظافتها.

ملاحظات تشغيلية

  • page_inject مرتبط بشكل ثابت عن قصد بحيث لا تتأثر عملية المهاجم نفسها بالخطاف الذي يثبّته.
  • يتعرّف page_inject على libc "المُخطَّفة بالفعل" (أي E9 + nops عند مقدمة read()) ويرفض إعادة الحقن. إذا كنت في بيئة اختبار وكان مخبأ صفحاتك عالقًا في تلك الحالة، أوقف كل الحاويات التي تستخدم الصورة ونفّذ drop_caches لإعادة التعيين.
تنزيل الأداة
.text
call
  • تثبيت الخطاف. يكتب الحاقن بعد ذلك المنطقة C (zone_c.asm) داخل كهف .text في libc، ويُرقِّع أول 7-12 بايتًا من read() بقفزة E9 disp32 إليها. تُحاكى البايتات المُزاحة من المقدمة بأمانة في المسار السريع للمنطقة C (يتم التعرّف على ثلاث مقدمات مختلفة من glibc -- انظر "معالجة المقدمة" أدناه). أصبح الخطاف الآن نشطًا في مخبأ صفحات libc.

  • انتشار الخطاف. كل حاوية شقيقة تشغّل عمليات تستدعي read() باستمرار (خفيّات التسجيل، فحوصات الصحة، cat /etc/hostname، أي شيء). عند أول استدعاء من هذا القبيل داخل حاوية شقيقة، تقفز المقدمة المختطفة إلى المنطقة C، التي:

    • تنفّذ stat("/") على inode جذر الحاوية (معرّف مستقر لكل مساحة أسماء) وتستخدمه كمفتاح لخانة الحاوية،
    • تفحص جدول الخانات بحثًا عن إدخال موجود بهذا المفتاح،
    • إذا كان غائبًا، تسجّل المفتاح وتُنشئ عبر fork() عملية فرعية لحلقة أوامر طويلة العمر تستقصي منطقة CMD عن الأوامر،
    • تعود إلى read()+N فلا يدري المتصل شيئًا. تبقى عملية الحاوية الشقيقة الأصلية مستمرة. ومن هذه اللحظة يملك المهاجم خفيّة (daemon) داخل تلك الحاوية.
  • قناة الأوامر. يستخدم المهاجم ملف page_inject نفسه في وضع --shell لكتابة الأوامر في منطقة CMD داخل نطاق الخانات. تستقصي عملية الخطاف الفرعية في كل حاوية شقيقة مسجَّلة، وتُنشئ عبر fork() عملية /bin/sh -c <cmd>، وتلتقط stdout/stderr في منطقة OUTPUT، وتشير إلى الاكتمال، ثم تعود إلى الاستقصاء. تعرض الصدفة الناتج. ولأن كل كتابة إلى CMD/OUTPUT تمر أيضًا عبر بدائية الثغرة، فلا حاجة إلى أي امتياز خاص.

  • إزالة الخطاف. عند الانتهاء، يستعيد unhook بايتات مقدمة read() الأصلية ويصفّر جدول الخانات؛ فترى عمليات الخطاف الفرعية خانة فارغة في تكرارها التالي وتُنهي نفسها. تعديلات مخبأ الصفحات نفسها نظيفة (إذ لم تُعلِم النواة الصفحات المعدَّلة كـ dirty أبدًا)، لذا ما إن تتوقف كل حاوية لديها libc مُخطَّط عبر mmap حتى يعيد drop_caches المخبأ بالكامل -- دون أن يبقى أي أثر على القرص.

  • .text
    ld.so
    .bss
    rbp + offset
    rbp = libc_base
    نطاق glibcالمقدمة (بعد endbr64 الاختياري)ملاحظات
    2.36 / 2.39cmpb $0x0, __libc_single_threaded(%rip)7 بايتات؛ cmpb المُحاكى يضبط ZF من أجل jne .Lthreaded الأصلية.
    2.43push rbp; movsxd rdi,edi; xor r9d,r9d7 بايتات؛ محاكاة بايت ببايت.
    2.31 / 2.35mov eax, fs:[0x18]8 بايتات؛ محاكاة بايت ببايت ([disp32] المسبوق بـ FS مطلق وليس نسبيًا إلى RIP، لذا فالنسخ البايتي أمين).
    الصورةglibcمسار الحقنمقدمة read()نطاق الخانة
    debian:bookworm2.36Acmpb.hash
    ubuntu:24.042.39Bcmpb.hash (من جانب libc، يُعنوَن عبر rbp من ld.so)
    ubuntu:22.042.35ATLS-fs.hash
    fedora:402.39Acmpb.hash
    archlinux:latest2.43Apush-rbp.eh_frame_hdr (ذيل مبتور)