
إثبات مفهوم الاختراق لـ CVE-2026-9256، وهو ثغرة تجاوز سعة المخزن المؤقت في الكومة في الوحدة النمطية `ngx_http_rewrite_module` في NGINX. يثبت تعطل العامل البعيد عبر URI مصمم بأحرف خاصة، مع فحص متعدد المراحل لاستمرارية الاتصال (keep-alive) لكشف موثوق.
نطاق التطبيق: يُستخدم فقط في البيئات المحلية المصرح بها، وبيئات إعادة إنتاج الثغرات المعتمدة، والتحقق من الثغرات، وتحليل قواعد الحماية. لا تستخدمه ضد أهداف غير مصرح بها. تفترض فكرة PoC في هذه المقالة فقط التحقق من سلوك تعطل عامل NGINX المرئي عن بعد، ولا تتضمن RCE أو تجاوز ASLR أو سلسلة استغلال مستقرة.
CVE-2026-9256 هي ثغرة في تجاوز سعة المخزن المؤقت في كومة الذاكرة (heap buffer overflow) في وحدة ngx_http_rewrite_module في NGINX. لا يتم تشغيل الثغرة بمجرد الوصول إلى URI ثابت معين، بل تعتمد على نمط تكوين rewrite معين: وجود مجموعات التقاط PCRE متداخلة في التعبير المنتظم للـ rewrite، وإشارة جزء الاستبدال (replacement) إلى متغيرات التقاط متعددة، مثل $1، $2.
عندما يقوم المهاجم ببناء URI خاص بحيث يدخل منطق rewrite في المسار ذي الصلة، قد يحدث عدم تطابق بين حساب الطول والكتابة الفعلية أثناء معالجة المحتوى الملتقط، أو ربط نتائج rewrite، أو ترميز URI / المعاملات، مما يؤدي في النهاية إلى تدمير ذاكرة كومة عملية العامل (worker process).
لذلك، لا يكمن مفتاح هذه الثغرة في المسار /api نفسه، بل في ما إذا كان هناك قاعدة rewrite ضعيفة في تكوين NGINX الهدف يمكن أن تتأثر بالطلب. المسار /api المستخدم افتراضيًا في PoC هو مجرد مسار مثال في بيئة إعادة الإنتاج الحالية؛ عند الاختبار الفعلي، يجب ضبط مسار الطلب وفقًا لقاعدة rewrite الموجودة في تكوين NGINX والتي تحتوي على مجموعات التقاط متداخلة وتشير إلى متغيرات التقاط متعددة.
الهدف الحالي لـ PoC هو التحقق من سلوك تعطل العامل (worker crash) / رفض الخدمة (denial of service). لا يحاول بناء تخطيط دقيق للكومة، ولا يحاول الكتابة فوق عنوان الإرجاع أو مؤشرات الدوال، ولا يثبت تنفيذ التعليمات البرمجية عن بُعد. الدليل المستقر الذي يمكن ملاحظته عن بُعد هو بشكل أساسي: قطع اتصال الطلب المُشغّل بشكل غير طبيعي، ثم استئناف استجابة خدمة NGINX، وانقطاع اتصال keep-alive بعد التشغيل بسبب تعطل العامل.
بعد تشغيل هذه الثغرة، لا يظهر بالضرورة كرمز حالة HTTP ثابت مثل 500 أو 502 أو 400. السبب هو أن نموذج master-worker في NGINX يتسبب في انهيار عملية العامل ثم يقوم master بإعادة تشغيل عامل جديد. ما يراه المهاجم عن بُعد ليس عادةً عدم توفر الخدمة بالكامل، بل قطع اتصال مفاجئ، أو انتهاء مهلة القراءة، أو إعادة تعيين الاتصال (reset)، ثم عند زيارة / مرة أخرى، يحصل على استجابة طبيعية.
لذلك، لا يمكن لـ PoC أن يحكم على وجود الثغرة بناءً على رمز حالة HTTP لطلب واحد فقط. إذا تم إرسال URI طويل مرة واحدة، ثم رؤية قطع الاتصال، والحكم مباشرةً بـ "الثغرة موجودة"، فإن خطر النتائج الإيجابية الخاطئة مرتفع. قد يحدث قطع الاتصال أيضًا بسبب اضطراب الشبكة، أو انتهاء مهلة الوكيل، أو اعتراض الطلب بواسطة جهاز وسيط، أو تحديد معدل من جانب الخادم، أو قفل الاتصال من جانب الخادم.
لذلك، يجب تصميم PoC كتحقق متعدد المراحل:
فقط عندما يحدث "قطع اتصال غير طبيعي + استئناف الخدمة لاحقًا + انقطاع متعدد الجولات في keep-alive" في نفس الوقت، يمكن الحكم بشكل أكثر أمانًا على وجود سلوك تعطل العامل على غرار CVE-2026-9256.
المسار الأساسي للتشغيل في PoC الحالي هو:
GET /api/++++++++++++++++++++++++++++++++... HTTP/1.1
Host: 127.0.0.1:19321
حيث /api/ هو المسار المثال في بيئة الهدف لضرب قواعد rewrite، وبعده يتم إلحاق عدد كبير من أحرف +. العدد الافتراضي هو 4096 حرفًا.
هناك ثلاثة أسباب رئيسية لاختيار +.
أولاً، + هو حرف URI قانوني، وعادةً لا يتم قطعه أو تغييره قسرًا مثل المسافات أو # عند استخدام عميل HTTP عادي. لذلك لا يحتاج PoC الحالي إلى استخدام raw socket لبناء سطر طلب غير قانوني كما في بعض ثغرات تجاوز request-target.
ثانيًا، توفر الأحرف المتكررة بكثافة إدخالًا طويلًا لمجموعات التقاط rewrite، مما يوسع نطاق إخراج التوصيل أو الترميز اللاحق لـ replacement، مما يسهل تشغيل عدم التطابق بين حساب الطول والكتابة الفعلية.
ثالثًا، بنية حمولة + المتكررة بسيطة، مما يسهل ملاحظتها في التقاط الحزم والسجلات وقواعد IDS، ويسهل ضبط الطول لاختبار العتبات.
ومع ذلك، تجدر الإشارة إلى أن + ليس الحرف الوحيد النظري لتشغيل الثغرة. الشرط الحقيقي للتشغيل لا يزال هو "ضرب تكوين rewrite ضعيف + إدخال يمكنه دخول مجموعات التقاط ذات الصلة + معالجة إخراج rewrite تؤدي إلى تجاوز سعة الكومة". في بيئات مختلفة، قد يحتاج مسار التشغيل ونوع الحرف وعتبة الطول إلى التعديل.
يختار PoC الحالي افتراضيًا عددًا كبيرًا من + كحرف تشغيل، لكن هذا لا يعني أن + فقط هو القادر على تشغيل المشكلة. + هو فقط أفضل حرف لكتابته في PoC عام، لأنه مستقر نسبيًا في URI، ويسهل إرساله بواسطة عميل HTTP عادي، ويكون واضحًا في التقاط الحزم.
من منظور مبدأ الثغرة، طالما أن الحرف يدخل في منطق الهروب NGX_ESCAPE_ARGS أثناء معالجة rewrite في NGINX، ويتوسع من 1 بايت إلى 3 بايت في شكل %XX، فقد يتسبب في اختلاف "قيمة حساب الطول أقل من قيمة الكتابة الفعلية". أي أن نقطة التشغيل ليست + بحد ذاتها، بل "ظهور كثيف للأحرف التي يمكن هروبها بواسطة نمط args".
بالإضافة إلى +، تشمل الأحرف التي يجب النظر فيها نظريًا:
المسافة: 0x20
#: 0x23
%: 0x25
&: 0x26
?: 0x3F
أحرف التحكم: 0x00-0x1F
البايتات العالية: 0x7F-0xFF
إذا دخلت هذه الأحرف في الالتقاط ذي الصلة وتمت معالجتها كهروب في محتوى args أثناء استبدال replacement، فسينتج تأثير توسع مماثل. على سبيل المثال:
+ -> %2B
& -> %26
% -> %25
# -> %23
? -> %3F
مسافة -> %20
كلما ظهر حرف من هذا النوع، من الناحية النظرية سيتوسع من 1 بايت إلى 3 بايت، مما يزيد طول الكتابة الفعلية بمقدار 2 بايت. إذا كان الإدخال يحتوي على عدد كبير من هذه الأحرف، فقد يتجاوز طول الكتابة الفعلية بشكل كبير طول المخزن المؤقت المحسوب بشكل خاطئ مسبقًا، مما يسهل تشغيل تجاوز سعة كومة الذاكرة.
ومع ذلك، فإن قابلية استخدام الأحرف المختلفة في PoC ليست متساوية تمامًا.
+ هو الأكثر استقرارًا. يمكن أن يظهر عادةً مباشرةً في request-target لـ HTTP، ولا يتم قطعه بسهولة بواسطة المتصفح أو أدوات سطر الأوامر، ولا يغير بنية مسار/استعلام URI بشكل طبيعي. لذلك يستخدم PoC الحالي 4096 حرفًا من + كحمولة افتراضية.
& يمكن أيضًا أن يكون حرفًا مرشحًا، لأنه في نمط args سيتم هربه إلى %26. لكن في shell، & له معنى تنفيذ الخلفية، وفي URL يُستخدم غالبًا كفاصل معاملات الاستعلام، لذا يجب الانتباه إلى الاقتباس والموضع عند الاختبار، وإلا فقد لا يتم إرسال الطلب كما هو متوقع.
% يمكن أيضًا أن يكون حرفًا مرشحًا، حيث سيتم هربه إلى %25. لكن % بحد ذاته هو بادئة ترميز URL، وقد تحاول بعض العملاء أو الوسطاء أو الأطر تفسير تسلسل %XX. إذا لم يتم إنشاؤه بشكل صحيح، فقد لا يستقبل الهدف الحرف % الأصلي، بل محتوى معالج مسبقًا من قبل العميل.
? نظريًا هو أيضًا حرف قابل للهروب، لكنه في request-target لـ HTTP يفصل بين المسار والاستعلام. إذا تم وضعه مباشرةً في المسار، فقد يتم تحليل المحتوى اللاحق كسلسلة استعلام، مما يغير نطاق التقاط rewrite. لذلك هو أكثر ملاءمة كحرف اختبار تكميلي، وليس كحرف رئيسي افتراضي في PoC.
# نظريًا يمكن أن يشغل الهروب، لكن المتصفح لا يرسل # وما بعده (جزء fragment) إلى الخادم، والعديد من عملاء HTTP المتقدمين سيقومون بترميزه أو قطعه. لذلك لاختبار حرف # حرفيًا، عادةً ما تحتاج إلى raw socket أو Burp Repeater أو أداة يمكنها الاحتفاظ بـ request-target الأصلي، ولا يمكن الاعتماد مباشرةً على شريط عنوان المتصفح.
المسافة 0x20 هي أيضًا حرف هروب، لكن في سطر طلب HTTP/1.1 العادي، المسافة نفسها هي فاصل، ووضعها مباشرةً في request-target سيدمر بنية سطر الطلب. أثناء الاختبار الفعلي، إذا كتبت كـ %20، فإن ما يراه الخادم في مرحلة المعالجة يعتمد على ما إذا كان قد تم فك ترميزه أو لا، وكذلك على موقعه في rewrite. لذلك المسافة أكثر ملاءمة لشرح المبدأ والاختبار المساعد، وليس كحمولة افتراضية.
أحرف التحكم 0x00-0x1F والبايتات العالية 0x7F-0xFF تقع أيضًا ضمن نطاق الهروب، لكنها في سلسلة HTTP الحقيقية更容易被 العملاء أو الوسطاء أو WAF أو محلل HTTP في NGINX اعتراضها أو تطبيعها أو رفضها. يمكن استخدامها كشرح لكائنات الهروب على مستوى المصدر، لكن لا ينصح باستخدامها كأحرف تشغيل افتراضية في PoC العادي.
لذلك، سبب استخدام PoC الحالي لـ + ليس أن الثغرة لا يمكن تشغيلها إلا بواسطة +، بل أن + يفي بثلاثة شروط في نفس الوقت: يمكنه تشغيل توسع هروب args، وسهل الإرسال بشكل مستقر، ولا يغير بنية URI بشكل واضح. عند وضع قواعد الحماية أو تحليل حركة المرور، لا يمكن فقط مطابقة + المتتالي، بل يجب أيضًا النظر في المجموعات عالية الكثافة من الأحرف الأخرى القابلة للهروب، خاصةً ظهور عدد كبير من الأحرف مثل +، &، %، ?، # في URI الطويل.
من منظور الكشف، فإن التعميم الأكثر منطقية ليس:
ظهور عدد كبير من + بعد /api/
بل:
ظهور عدد كبير من الأحرف الخاصة في URI الطويل التي ستتوسع إلى %XX في وضع NGX_ESCAPE_ARGS
إذا تم كشف ++++ فقط، فإن القاعدة ستغطي فقط الكتابة الافتراضية لـ PoC الحالي؛ إذا قام المهاجم بتغيير الحمولة إلى &&&&، %%%%، ????، أو مزج +%&?#، فقد تؤدي ميزة + الواحدة إلى تفويت الكشف. فكرة الكشف الأكثر أمانًا هي الجمع بين طول URI، كثافة الأحرف الخاصة، عدد مرات التكرار المتتالي، مسار rewrite الخطير، وسطح تعرض NGINX لتحديد الحكم.
تتعامل دالة normalize_target في PoC مع إدخال سطر الأوامر، وتدعم ثلاثة أشكال:
python3 CVE-2026-9256-poc.py 127.0.0.1:19321
python3 CVE-2026-9256-poc.py 127.0.0.1 19321
python3 CVE-2026-9256-poc.py http://127.0.0.1:19321
إذا أدخل المستخدم host:port فقط دون كتابة scheme، فإن البرنامج النصي يضيف تلقائيًا http://host:port. ثم يستخدم urllib.parse.urlparse لتحليل hostname و port، ويولد base، على سبيل المثال:
host = 127.0.0.1
port = 19321
base = http://127.0.0.1:19321
التنفيذ الحالي موجه أساسًا للبيئات المحلية بنص HTTP العادي. على الرغم من أن normalize_target يقبل شكل https://، إلا أن كشف keep-alive اللاحق يستخدم socket TCP عاديًا بدون طبقة TLS، لذلك في سيناريو HTTPS، سيكون فحص التعطل (crash probe) غير دقيق. لدعم HTTPS، تحتاج إلى إضافة ssl.wrap_socket أو ssl.create_default_context().wrap_socket() إلى socket.
أولاً، يستدعي PoC check_alive(base) لزيارة المسار الجذر /:
GET /
إذا تمكن الهدف من إرجاع أي رمز حالة HTTP، فهذا يعني أن الخدمة حية بشكل أساسي، ويمكن متابعة الاختبار. إذا فشل الاتصال، فإنه يخرج مباشرةً، لتجنب اعتبار الأهداف غير القابلة للوصول كفشل في تشغيل الثغرة.
ثم يستدعي check_rewrite(base) لزيارة:
GET /api/test
يُستخدم هذا الطلب لملاحظة ما إذا كان /api/* قد يضرب منطق rewrite في البيئة الحالية. إذا تم إرجاع رمز حالة إعادة توجيه مثل 301، 302، 303، 307، 308، فهذا يعني أن سلوك إعادة توجيه rewrite واضح، ويطبع PoC رأس Location كدليل مساعد.
لكن هذه الخطوة ليست شرط نجاح إلزاميًا. لأنه في بعض تكوينات إعادة الإنتاج، قد يدخل /api/* نفسه إلى مسار rewrite المشكل، وحتى الطلبات الاستكشافية العادية قد تنتهي مهلة أو تتم معالجتها بشكل غير طبيعي. لذلك حتى إذا لم يحصل البرنامج النصي على استجابة rewrite طبيعية، فإنه يستمر في مرحلة التشغيل.
دالة التشغيل هي send_trigger(base, plus_count=4096)، المنطق الأساسي هو الربط:
payload = "/api/" + ("+" * plus_count)
الطلب النهائي الافتراضي يشبه:
/api/++++++++++++++++++++++++++++++++... إجمالي 4096 حرف +
ثم يتم إرسال الطلب عبر requests.get(base + payload, timeout=10, allow_redirects=False).
يتم تعطيل إعادة التوجيه التلقائي لسببين.
أولاً، قد يعيد rewrite نفسه توجيهًا. إذا قام عميل HTTP بمتابعة التوجيه تلقائيًا، فسيختلط الطلب الأصلي وطلبات التوجيه اللاحقة، مما يجعل من الصعب الحكم على ما حدث بالضبط في الطلب الأول.
ثانيًا، يركز PoC على حالة الاتصال في مرحلة التشغيل، وليس على الصفحة التجارية بعد التوجيه. الاحتفاظ بالاستجابة الأصلية يسهل التحليل.
يتم تصنيف نتائج التشغيل إلى عدة فئات:
إذا تم اكتشاف ConnectionError، فهذا يعني أن الاتصال قد أغلق بشكل غير طبيعي أثناء طلب التشغيل، وقد يكون هذا مظهرًا عن بُعد لتعطل العامل.
إذا تم اكتشاف ReadTimeout، فهذا يعني أن الطلب لم يحصل على استجابة طبيعية لفترة طويلة، وقد يكون العامل عالقًا أو انهار دون إرجاع طبيعي، أو أن بيئة الشبكة تسببت في انتهاء المهلة.
إذا تم تلقي استجابة HTTP طبيعية، تتم طباعة رمز الحالة وطول جسم الاستجابة، لكن لا يمكن إنكار الثغرة بناءً على استجابة طبيعية فقط، لأنه في بعض البيئات قد لا تتحقق شروط التشغيل بالكامل، أو أن طول الحمولة غير كافٍ.
بعد طلب التشغيل، ينتظر PoC لمدة ثانية واحدة، ثم يستدعي follow_up(base) لزيارة المسار الجذر / مرة أخرى.
الغرض من هذه الخطوة ليس إثبات الفائض نفسه، بل الحكم على ما إذا كانت NGINX تظهر ميزة "تعطل العامل ثم إعادة تشغيله بواسطة master".
إذا تم قطع اتصال طلب التشغيل بشكل غير طبيعي، ولكن زيارة / لاحقًا أعادت 200 أو رمز حالة HTTP طبيعي آخر، فهذا يعني أن الخدمة لم تنهار بالكامل، بل على الأرجح أن عملية عامل واحدة انهارت ثم تعافت.
إذا كانت الخدمة غير قابلة للوصول لفترة طويلة بعد التشغيل، فقد يكون ذلك بسبب توقف الخدمة بالكامل، أو انهيار الحاوية، أو خلل في الشبكة، وهذه النتيجة لا يمكن أن تعادل تشغيل CVE-2026-9256 بنجاح.
لذلك، معيار الحكم في PoC الحالي هو: تعطل العامل المرئي عن بُعد، وليس مجرد "عدم توفر الخدمة".
أهم تحقق للاستقرار في PoC هو keepalive_probe(host, port, rounds=5, plus_count=4096).
لا يستخدم requests، بل يستخدم مباشرةً socket.create_connection لإنشاء اتصال TCP، ويرسل ثلاثة طلبات متتالية على نفس اتصال keep-alive.
الطلب الأول هو طلب عادي:
GET / HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
يستخدم هذا الطلب لتأكيد أن الاتصال الحالي متاح، ومحاولة جعل طلب التشغيل اللاحق يقع على نفس الاتصال.
الطلب الثاني هو طلب التشغيل:
GET /api/++++++++++++++++++++++++++++++++... HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
إذا تسبب هذا الطلب في تعطل العامل، فمن المحتمل أن يتم قطع اتصال keep-alive الذي يحتفظ به ذلك العامل مباشرةً.
الطلب الثالث لا يزال طلبًا عاديًا:
GET / HTTP/1.1
Host: 127.0.0.1
Connection: close
إذا كان لا يزال بالإمكان تلقي استجابة للطلب الثالث، فهذا يعني أن الاتصال لم ينقطع بسبب طلب التشغيل، ولا تعتبر هذه الجولة تعطلًا للعامل.
إذا فشل إرسال الطلب الثالث، أو تعذرت قراءة البيانات، أو تم إغلاق الاتصال بالفعل، فسيتم تسجيل:
keepalive connection dropped
يكرر PoC افتراضيًا 5 جولات. معنى التكرار المتعدد هو تقليل النتائج الإيجابية الخاطئة من أخطاء الشبكة العشوائية. إذا حدث انقطاع keep-alive عدة مرات في 5 جولات، وكانت الخدمة لا تزال قادرة على استئناف الاستجابة لاحقًا، فإن الدليل عن بُعد يكون أكثر اكتمالاً.
ينقسم الحكم النهائي لـ PoC إلى ثلاث فئات.
الفئة الأولى: تأكيد الثغرة.
الشرط هو:
crash_count > 0 and recovered == True
أي أن فحص keep-alive اكتشف على الأقل جولة واحدة انقطع فيها الاتصال، وأثبت طلب المتابعة العادي أن الخدمة قد استأنفت الاستجابة. يخرج البرنامج النصي:
VULNERABILITY CONFIRMED - CVE-2026-9256 style crash behavior
Impact confirmed: worker crash / denial of service
RCE is not proven by this script
هذا يعني أن البيئة الحالية تظهر سلوك تعطل العامل على غرار CVE-2026-9256، لكنه لا يثبت تنفيذ التعليمات البرمجية عن بُعد.
الفئة الثانية: مشتبه به.
الشرط هو:
kind == "connection_error" and recovered == True
أي أن طلب التشغيل الرئيسي حدث له قطع اتصال، واستؤنفت الخدمة لاحقًا، لكن فحص keep-alive لم يؤكد بشكل مستقر تعطل العامل. يخرج البرنامج النصي VULNERABILITY SUSPECTED.
هذا الموقف يشير إلى وجود ظاهرة غير طبيعية، لكن الدليل غير مستقر بدرجة كافية، ويتطلب تأكيدًا إضافيًا من خلال error.log من جانب الخادم، أو core dump، أو سجلات الحاوية، أو مصحح الأخطاء.
الفئة الثالثة: غير مؤكد.
إذا لم يكن هناك انقطاع موثوق لـ keep-alive، ولا مجموعة قطع اتصال التشغيل + استرداد الخدمة، يخرج البرنامج النصي:
VULNERABILITY NOT CONFIRMED
هذا لا يعني بالضرورة أن الهدف خالٍ تمامًا من الثغرة، بل قد يكون المسار لم يضرب rewrite، أو طول الحمولة غير كافٍ، أو اختيار الحرف غير مناسب، أو أن إصدار الهدف قد تم إصلاحه، أو أن الوكيل الوسيط قام بتغيير URI، أو أن البرنامج النصي الحالي لم يتكيف مع HTTPS.
## 10. تدفق التنفيذ الكامل لـ PoC الحالي
يمكن تلخيص تدفق تنفيذ البرنامج النصي على النحو التالي:
1. تحليل عنوان الهدف، إنشاء host و port و base.
2. طباعة المعلومات الأساسية لـ PoC، وتوضيح أنه يتحقق فقط من تعطل العامل، ولا ينفذ RCE.
3. طلب `/` لتأكيد بقاء خدمة الهدف.
4. طلب `/api/test` لمحاولة الحكم على ما إذا كان مسار rewrite المثال نشطًا.
5. إرسال طلب URI طويل `/api/` + 4096 حرف `+`.
6. تسجيل نتيجة التشغيل الأولى بناءً على قطع الاتصال أو انتهاء المهلة أو استجابة HTTP.
7. الانتظار لمدة ثانية واحدة ثم طلب `/` مرة أخرى لتأكيد ما إذا كان العامل قد تعافى.
8. استخدام socket لإنشاء اتصال keep-alive، وإرسال طلب عادي، طلب تشغيل، طلب عادي بالتتابع.
9. تكرار فحص keep-alive لـ 5 جولات، وحساب عدد مرات انقطاع الاتصال.
10. إخراج confirmed أو suspected أو not confirmed بناءً على crash_count وحالة اتصال التشغيل وحالة استرداد المتابعة.
## 11. مثال على الاستخدام
مثال للبيئة المحلية:
```bash
python3 CVE-2026-9256-poc.py http://127.0.0.1:19321
أو:
python3 CVE-2026-9256-poc.py 127.0.0.1 19321
عند التشغيل الناجح، سيظهر الإخراج النموذجي كما يلي:
[+] Connection dropped during trigger request
[+] Worker is responding after trigger (HTTP 200)
round 1: worker likely crashed (keepalive connection dropped)
round 2: worker likely crashed (keepalive connection dropped)
...
[+] VULNERABILITY CONFIRMED - CVE-2026-9256 style crash behavior
[+] Impact confirmed: worker crash / denial of service
[*] RCE is not proven by this script
هذا النوع من الإخراج يشير إلى أن الجانب البعيد لاحظ دليلاً مستقرًا على تعطل العامل.
الحدود الأمنية لـ PoC هذا واضحة نسبيًا:
أولاً، يتحقق فقط من التعطل (crash)، ولا يستغل لـ RCE.
ثانيًا، لا يبني heap spray أو ROP أو تجاوز ASLR أو shellcode أو منطق تنفيذ أوامر.
ثالثًا، معيار نجاحه هو انقطاع اتصال العامل واسترداد الخدمة، وليس الحصول على شل أو قراءة ملفات.
رابعًا، مناسب للاستخدام في إعادة الإنتاج المحلية، والتحقق من الثغرات، وبناء قواعد IDS/IPS، واختبار المقارنة قبل وبعد الإصلاح.
لتعزيز الأمان بشكل أكبر، يمكن إضافة القيود التالية:
127.0.0.1، localhost، أو العناوين الخاصة، أو شرائح الشبكة المصرح بها صراحةً.--plus-count لتجنب إرسال حمولة كبيرة جدًا افتراضيًا.--route للسماح للمستخدم بتحديد مسار التشغيل صراحةً، بدلاً من كتابة /api/ بشكل ثابت.--rounds للتحكم في عدد مرات فحص keep-alive.--print-request لطباعة طلب HTTP الفعلي المرسل، لتسهيل المقارنة مع نتائج التقاط الحزم.من منظور اشتقاق PoC، لا يمكن أن تركز قواعد الكشف على /api/ فقط، لأن /api ليس مسارًا ثابتًا للثغرة، بل مجرد مثال في البيئة الحالية. نقاط الكشف الأكثر قيمة حقًا هي:
+، أو مزيج من الأحرف الخاصة مثل +، &، %، ?، #.إذا كانت القاعدة مكتوبة بشكل ثابت /api/++++، فستغطي فقط PoC الحالي والبيئة الحالية؛ لتغطية حركة هجوم أكثر عمومية، يجب استخراج الميزات حول "URI طويل + ظهور كثيف للأحرف الخاصة + اتجاه طلب HTTP + مسار rewrite خطر في NGINX".
في الوقت نفسه، نظرًا لوجود عناوين URL طويلة أو أحرف ترميز كثيرة في الأعمال المشروعة، يجب أن تقلل القواعد من النتائج الإيجابية الخاطئة من خلال عتبات الطول، وكثافة الأحرف، وعدد التكرارات، وسياق المسار. اتجاه الكشف الأكثر أمانًا هو:
URI طويل
+
عدد كبير من الأحرف الخاصة التي يمكن هروبها وتوسيعها بواسطة NGX_ESCAPE_ARGS
+
اتجاه الطلب to_server
+
سطح تعرض NGINX rewrite
بدلاً من الكشف البسيط:
/api/++++
بالنسبة لقواعد Suricata / Snort، إذا كان الهدف فقط تغطية PoC العام الحالي، يمكن استخدام + المتتالي كإحدى الميزات القوية؛ إذا كان الهدف تغطية المتغيرات، فيجب تضمين نطاق الأحرف الخاصة في PCRE، مثل +، %، #، &، ?، وغيرها من الأحرف التي قد يتم هروبها وتوسيعها. لكن هذه القواعد أكثر عرضة للنتائج الإيجابية الخاطئة، وتحتاج إلى استخدامها مع urilen، وعتبة تكرار الأحرف، وقيود المسار، ونطاق أصول NGINX.
التركيز في اشتقاق PoC لـ CVE-2026-9256 ليس البحث عن مسار ثغرة ثابت، بل فهم شروط تشغيل الثغرة أولاً: تكوين rewrite ضعيف، مجموعات التقاط متداخلة، إشارة إلى متغيرات التقاط متعددة، وإدخال URI خاص يمكنه جعل نتائج معالجة rewrite تتوسع بشكل غير طبيعي.
يختار البرنامج النصي الحالي /api/ + 4096 حرف +، لأن هذا المسار يمكنه ضرب قواعد rewrite في بيئة إعادة الإنتاج الحالية، وعدد كبير من + يمكنه خلق ضغط إدخال طويل بشكل مستقر. لم ينفذ البرنامج النصي RCE، بل يثبت تعطل العامل من خلال قطع الاتصال، واسترداد الخدمة، وانقطاع multiple rounds في keep-alive.
في الوقت نفسه، + هو فقط الحرف الافتراضي الأكثر استقرارًا وسهولة في الإرسال، وليس الحرف الوحيد الذي يمكنه تشغيل الثغرة. أي حرف سيتوسع إلى %XX في وضع NGX_ESCAPE_ARGS يجب أن يُدرج في نطاق التحليل المبدئي وقواعد الحماية. الفهم الأكثر دقة يجب أن يكون: ظهور كثيف للأحرف القابلة للهروب والتوسع في URI طويل، وعند دخولها في التقاط ضعيف ومعالجة replacement، يؤدي إلى عدم تطابق بين حساب الطول والكتابة الفعلية، مما يسبب في النهاية تعطل العامل أو تدمير ذاكرة أكثر خطورة.