
إثبات المفهوم (POC) لثغرة CVE-2026-39816 والتي تسمح لمستخدمي NiFi دون صلاحيات تنفيذ التعليمات البرمجية بتشغيل نصوص برمجية عشوائية
إثبات مفهوم لـ CVE-2026-39816، وهو تجاوز لصلاحية EXECUTE_CODE
في Apache NiFi 2.8.0 يسمح لمصمم التدفق الذي تم
حرمانه عمدًا من صلاحيات تنفيذ التعليمات البرمجية بتشغيل أكواد Groovy
عشوائية في JVM الخاص بـ NiFi عبر معالج ExecuteGraphQuery من حزمة الرسم البياني.
@Restricted على TinkerpopClientService (CVE-2026-39816, CWE-95)يقوم NiFi بتقييد المعالجات التي تنفذ التعليمات البرمجية خلف صلاحية EXECUTE_CODE
عبر تعليق @Restricted(requiredPermission = RequiredPermission.EXECUTE_CODE).
جميع المكونات البرمجية الـ 16 المخصصة في NiFi —
ExecuteScript, InvokeScriptedProcessor, ExecuteGroovyScript,
ScriptedTransformRecord, إلخ. — تحمل هذا التعليق، لذا يجب
منح مصمم التدفق صلاحية EXECUTE_CODE الصريحة قبل
أن تسمح له طبقة التفويض بإنشاء أو تكوين هذه
المعالجات.
حزمة الرسم البياني (nifi-graph-nar + nifi-other-graph-services-nar)
تتضمن مسارًا ثالثًا لتنفيذ التعليمات البرمجية يفتقد هذا التعليق:
// nifi-extension-bundles/nifi-graph-bundle/nifi-other-graph-services/
// src/main/java/org/apache/nifi/graph/TinkerpopClientService.java:451
protected Map<String, String> bytecodeSubmission(
String s, Map<String, Object> map, GraphQueryResultCallback cb) {
...
compiled = groovyShell.parse(s); // line 463 — compile attacker string
compiledCode.put(s, compiled);
...
compiled.setBinding(bindings);
Object result = compiled.run(); // line 477 — execute in NiFi JVM
المعامل s هو سلسلة الاستعلام من خاصية "Graph Query" الخاصة بمعالج
ExecuteGraphQuery، ويتم تمريرها دون تغيير. لا يوجد
تعقيم، ولا قائمة بيضاء، ولا صندوق حماية — أي كود Groovy صالح يتم
تجميعه وتنفيذه بصلاحيات كاملة لعملية NiFi.
لا يحمل كل من TinkerpopClientService ولا معالجات ExecuteGraphQuery /
ExecuteGraphQueryRecord التي تشغّله تعليق
@Restricted. لذلك تتعامل طبقة التفويض في NiFi معها
كمكونات عادية، ويمكن لمصمم التدفق الذي تم
حرمانه صراحةً من EXECUTE_CODE إنشاءها.
يكون خادم NiFi 2.8.0 قابلاً للاستغلال عندما يكون كلاهما مما يلي صحيحًا:
حزمة الرسم البياني الاختيارية مثبتة. تحديدًا
nifi-other-graph-services-nar — هذه هي الحزمة التي توفر
TinkerpopClientService. الخوادم التي لا تحتوي على هذه الحزمة غير متأثرة.
لدى مستخدم واحد على الأقل صلاحيات مصمم التدفق
(read/write على مجموعة العمليات وعلى /controller) بدون
EXECUTE_CODE. هذا شكل سياسة شائع: مؤسسة
تريد أن يتمكن المستخدمون من بناء وتعديل خطوط الأنابيب، ولكن ليس تشغيل
تعليمات برمجية عشوائية. صلاحية EXECUTE_CODE هي بالضبط
الحد الأمني الذي تهدف السياسة إلى فرضه.
إذا تحقق الشرطان، يمكن للمستخدم تكوين
TinkerpopClientService في وضع "ByteCode Submission"، وتوجيهه إلى أي
خادم Gremlin يمكن الوصول إليه (خادم Gremlin يُستخدم فقط لتهيئة
الخدمة — التنفيذ يحدث محليًا)، وإنشاء
معالج ExecuteGraphQuery مع كود Groovy في خاصية "Graph Query".
بدء تشغيل المعالج يقوم بتجميع وتشغيل كود Groovy في
JVM الخاص بـ NiFi.
تنفيذ تعليمات برمجية عشوائية بحساب خدمة NiFi. من هناك:
flow.json.gz، أو إسقاط NAR
في دليل التحميل التلقائي، أو تعديل خدمة تحكم.يتجاوز الاستغلال صلاحية EXECUTE_CODE، لذا يعمل هذا حتى
عندما يقوم المشغل بإزالة حقوق تنفيذ التعليمات البرمجية صراحةً من
المستخدم — بالضبط السيناريو الذي توجد الصلاحية لمنعه.
يحتوي هذا المستودع على واحد POC، يغطي المشغل الأكثر مباشرة:
كود Groovy المتحكم فيه من المهاجم يوضع مباشرة في خاصية معالج Graph Query.
لا حاجة لاتصال علوي، ولا لغة تعبير، ولا محتوى FlowFile — فقط المعالج يعمل على
مؤقته الخاص.
يوجد مساران إضافيان للتعليمات البرمجية (محتوى جسم FlowFile يُستخدم كاستعلام
عندما تكون Graph Query فارغة، واستيفاء لغة التعبير
لسمات FlowFile المتأثرة بالمهاجم في قالب الاستعلام).
لا يتم عرضهما هنا لأنهما يصلان إلى نفس الهدف بشروط مسبقة إضافية؛ المسار المباشر كافٍ
لإثبات تجاوز EXECUTE_CODE.
setup/ — بيئة Docker Compose. تقوم بتشغيل مثيل NiFi 2.8.0
(صورة apache/nifi:2.8.0 الرسمية) مع تحميل NARs حزمة الرسم البياني
تلقائيًا، وخادم LDAP يوفر مستخدمين للاختبار (admin
وflow_designer)، وخادم Gremlin لـ
TinkerpopClientService لتوجيهه إليه. يقوم setup.sh بتهيئة
السياسات بحيث يكون لدى flow_designer حقوق تحرير التدفق ولكن
ليس EXECUTE_CODE، ثم يتحقق من التكوين.
pocs/flow_designer_groovy_rce.py — استغلال مستقل بذاته.
يصادق كـ flow_designer، ويوضح أن ExecuteScript
مرفوض (بوابة EXECUTE_CODE تعمل)، ثم ينشئ
TinkerpopClientService + مع حمولة Groovy
تشغّل قشرة عكسية bash إلى مستمع يبدأه POC
محليًا. بمجرد إنشاء الاتصال، يقوم POC
بترقية القشرة إلى bash تفاعلي كامل مدعوم بـ PTY عبر
أداة من util-linux، مع جسر stdio بالوضع الخام وتغيير حجم
النافذة المباشر — يحصل المشغل على طرفية حقيقية داخل حاوية NiFi.
المتطلبات الأساسية: Docker، Python 3.10+، و uv.
cd setup
./setup.sh
التشغيل الأول يقوم بتنزيل NARs حزمة الرسم البياني من Maven Central و سحب صور Docker (~2-3 دقائق). عند اكتمال الإعداد، يطبع استدعاء POC الجاهز للصق.
تشغيل POC:
uv run --no-project --with requests \
pocs/flow_designer_groovy_rce.py \
--base-url https://localhost:8443 \
--username flow_designer \
--password 'flowDesigner123!' \
--gremlin-host gremlin-server
يقوم POC بإسقاط المشغل في جلسة bash تفاعلية داخل
حاوية NiFi تعمل بحساب خدمة nifi. اكتب exit أو اضغط
Ctrl-D لفصل الاتصال — سيقوم POC بعد ذلك بتنظيف المعالج
وخدمة التحكم التي أنشأها.
على Docker لنظام Linux (حيث لا يتم حل host.docker.internal بشكل
افتراضي)، مرر --shell-host <host-bridge-ip> أو أضف
extra_hosts: ["host.docker.internal:host-gateway"] إلى خدمة nifi
في setup/docker-compose.yml.
الإيقاف:
cd setup
./teardown.sh
ExecuteGraphQueryscript