
هل مضيف Linux الخاص بك معرّض لـ CVE-2026-98432؟
يتحقق مما إذا كان مضيف Linux قد يكون معرّضًا لـ CVE-2026-98432، وهو استخدام بعد التحرير (use-after-free) في مصافحة TCP عبر IPv4 في النواة. جزء من shouldipanic.ch.
حزمة SYN تحمل خيارات IPv4 (Record Route، Timestamp) تصل إلى شيفرة تقرأ الخيارات بعد أن تكون قد حُرّرت بالفعل. يكفي أي منفذ TCP مفتوح عبر IPv4، دون الحاجة إلى تسجيل دخول. وهو موجود في كل نواة منذ 4.4 (2016) حتى الإصدار المُصلح من كل فرع: 5.10.272، 5.15.223، 6.1.190، 6.6.159، 6.12.113، 6.18.56، 7.2.10، 7.3. يمنحه CNA الخاص بالنواة تقييم 9.8؛ وقد أُبلغ عن استغلال عملي عن بُعد للحصول على صلاحيات الجذر ضد خوادم لديها مستمعو MPTCP (لم يُنشر). الإصلاح غير مرئي على مستوى الشبكة: النواة المُصلحة ترد تمامًا كما ترد النواة غير المُرقّعة.
وهذا يحدد ما يمكن أن يقوله كل وضع:
--on-host يقرأ النواة قيد التشغيل على الجهاز نفسه: إصدارها،
وسجل تغييرات الحزمة، وما إذا كانت هناك نواة أحدث تنتظر إعادة التشغيل.Server ويعرض ما إذا كانت تلك التوزيعة
قد أصدرت نواة مُصلحة بعد. هذا تلميح قوي، وليس حكمًا نهائيًا: خلف
وكيل عكسي أو داخل حاوية، تكون النواة تابعة لجهاز آخر.يتوفر kernel98scan بصيغتين:
kernel98scan.py: ملف Python واحد بلا أي تبعيات. على المضيف،
يمنح --on-host الحكم الحقيقي؛ وعند توجيهه إلى عناوين، فإنه يجري تحديد بصمة التوزيعة
عبر نطاقات IP، مع فحص للمنافذ واكتشاف vhost.
curl -LO https://github.com/akaihigurashi/kernel98scan/releases/latest/download/kernel98scan.py
python3 kernel98scan.py --on-host # real verdict for THIS machine
Python 3.8 أو أحدث، لا شيء لتثبيته. أمثلة:
python3 kernel98scan.py --on-host # read the running kernel
python3 kernel98scan.py 203.0.113.10 # outside: distribution + fix status
python3 kernel98scan.py 203.0.113.0/24 # a whole range from outside
python3 kernel98scan.py 203.0.113.10 --ip-options # + do IP-options packets get through?
python3 kernel98scan.py 203.0.113.10 -o out.csv # CSV output
python3 kernel98scan.py -h # all options
على المضيف (--on-host، رمز الخروج 2 / 1 / 0 / 3):
| الحالة | المعنى |
|---|---|
VULNERABLE | لا شيء يُظهر الإصلاح في النواة قيد التشغيل |
CHECK | نواة مُصلحة مثبّتة، لكن القديمة لا تزال قيد التشغيل: أعد التشغيل |
FIXED | سجل تغييرات النواة يذكر CVE، أو نواة upstream عادية عند الإصدار المُصلح |
نوى المورّدين (Ubuntu وRHEL وProxmox) تُرجع الإصلاحات إلى أرقام إصدارات قديمة، لذا
بالنسبة لها يُحتسب سجل التغييرات فقط. كما يُظهر ما إذا كان MPTCP مُفعّلًا (فالثغرة
المُبلّغ عنها تمر عبر مستمعات MPTCP) وtcp_migrate_req.
من الخارج:
| الحالة | المعنى |
|---|---|
POSSIBLY VULNERABLE | تُظهر اللافتة توزيعة Linux: إما أنه لا توجد لديها نواة مُصلحة بعد (Ubuntu وRHEL وإعادة البناء اليوم) أو توجد لديها واحدة، يجب تثبيتها وتشغيلها |
UNKNOWN | التوزيعة غير ظاهرة، أو يجيب وكيل/شبكة CDN |
NOT LINUX | يشير ترويسة Server إلى مضيف غير Linux |
لا يُبلّغ أبدًا عن VULNERABLE وPATCHED من الخارج. حالة الإصلاح لكل
توزيعة هي جدول في check.py (FIX_STATUS، FIXED_TABLE)،
يُحدَّث مع كل إصدار من المورّد.
| الخيار | ما يفعله |
|---|---|
--on-host | يقرأ النواة قيد التشغيل على هذا الجهاز ويعطي حكمًا حقيقيًا |
--ip-options | اتصال واحد يحمل SYN الخاص به خيار IP من نوع Record-Route (انظر أدناه) |
-o FILE | يكتب أيضًا جميع النتائج إلى CSV |
-a / -v | إظهار النتائج المخفية / إظهار الأدلة |
-d | تصحيح: كل طلب وترويسة ومطابقة |
-q | بلا لافتة (للسكربتات) |
-V | طباعة الإصدار |
-h | جميع الخيارات |
--ip-options (اختياري، من سطر الأوامر فقط)يفتح اتصالًا عاديًا وآخر يحمل SYN الخاص به خيار IP فارغًا من نوع Record-Route،
ويُبلّغ عمّا إذا كانت هذه الحزم تصل إلى المضيف (reach)، أو تُسقَط
في الطريق (filtered)، أو أن المنفذ مغلق (noport). هذا هو شكل الحزمة
التي يُوصَل إلى الثغرة عبرها، لذا هو معطّل افتراضيًا ولا يعمل أبدًا على
صفحة الويب: استخدمه على مضيفيك، مثلًا للتأكد من أن جدار الحماية لديك
يُسقط خيارات IP. لا يمكن لاتصال واحد أن يفوز بالسباق الذي تحتاجه الثغرة، و
نتيجة filtered قد تكون أي شبكة في ما بينهما.
nft add table ip cve98432
nft add chain ip cve98432 pre '{ type filter hook prerouting priority -300; }'
nft add rule ip cve98432 pre meta l4proto tcp ip hdrlength != 5 drop
sysctl -w net.mptcp.enabled=0 # if you don't need MPTCP
يُسقط حزم IPv4 TCP التي تحمل أي خيارات IP. غير مستمر عبر عمليات إعادة التشغيل، وليس بديلاً عن النواة المُصلحة.
docker run -d --name kernel98scan --restart unless-stopped \
-p 127.0.0.1:8092:8092 \
-e PANIC_ORIGIN=https://kernel98scan.example.ch \
-v kernel98scan-data:/data \
ghcr.io/akaihigurashi/kernel98scan:latest
أو باستخدام Compose: نزّل docker-compose.yml، واضبط
PANIC_ORIGIN، ثم نفّذ docker compose up -d. يستمع الحاوية على localhost
فقط؛ ضع وكيلاً عكسياً مع TLS أمامه
(مثال nginx).
| المتغير | الافتراضي | الغرض |
|---|---|---|
PANIC_ORIGIN | – | العنوان العام. تُرفض الطلبات من أصول أخرى. اضبطه. |
PANIC_OPERATOR / PANIC_CONTACT | – | قسم اتصال اختياري أسفل الصفحة |
PANIC_IMPRINT_URL | – | رابط اختياري إلى بصمة موجودة |
PANIC_TRUSTED_PROXY | 127.0.0.1,::1 | الوكلاء الذين يُوثق بترويسة X-Real-IP الخاصة بهم |
PANIC_DENY_HOSTS / PANIC_DENY_IPS | – | لا تفحص هذه النطاقات / العناوين أبداً |
PANIC_AUDIT_DIR | /data/audit | ملفات سجل التدقيق اليومية |
PANIC_RETENTION_DAYS | 30 | تُحذف ملفات التدقيق الأقدم من هذا |
تحتوي الصفحة على نفس الحمايات الموجودة في php2scan: مربع اختيار الموافقة، وسجل التدقيق، ورفض عملاء VPN/Tor/مراكز البيانات، وحد المعدل، وذاكرة تخزين النتائج المؤقتة، والأسماء المضيفة العامة فقط مع تثبيت الاتصال على العنوان المفحوص، والمضيفات التي لا تُفحص أبداً (الخدمات المعروفة، وأكثر 100 موقع زيارةً، والمواقع الحكومية، والدول الخاضعة للعقوبات)، ومنع الوصول من الدول الخاضعة للعقوبات. لا تُحمّل صفحة الويب سوى صفحة البداية؛ ولا ترسل خيارات IP أبداً.
يعيش محرك الفحص (الجلب، والبصمات، وفحص المنافذ، واكتشاف vhost، وخادم الويب) في
panic-core.
كل ما يخص CVE-2026-98432 موجود في check.py.
يُولَّد kernel98scan.py وweb.py من كليهما:
git clone https://github.com/akaihigurashi/panic-core ../panic-core
python3 ../panic-core/bundle.py check.py
GPL-3.0، انظر LICENSE. الخطوط: Bricolage Grotesque وInstrument Sans وJetBrains Mono (رخصة SIL المفتوحة للخطوط).