
ثغرة تنفيذ التعليمات البرمجية عن بُعد عبر حقن AST في Handlebars.js
هذا المنشور عبارة عن مقال بحثي منشور بواسطة EQSTLab.
PoC المُشار إليه: dinhvaren/cve-2026-33937
★ CVE-2026-33937 حقن AST في Handlebars.js وتنفيذ الأوامر عن بُعد — PoC ★
https://github.com/user-attachments/assets/99e383e7-e71f-4e10-8c62-f50abff8b4f5
CVE-2026-33937 : ثغرة حقن AST وتنفيذ الأوامر عن بُعد في Handlebars.js
| الإصدارات المتأثرة | 4.0.0 – 4.7.8 |
| الإصدار المُصحَّح | 4.7.9 |
| درجة CVSS | 9.8 (حرجة) |
تنشأ ثغرة الالتباس النوعي (Type Confusion) في Handlebars.js من حقيقة أن Handlebars.compile() لا يقبل سلسلة القالب فقط، بل يقبل أيضًا كائن AST محلَّل مسبقًا (JSON) كمدخل. يمكن للمهاجم الذي يتحكم في القيمة المُمرَّرة إلى compile() توفير كائن AST مُصمَّم بعناية يتم فيه استبدال حقل value لعقدة NumberLiteral بسلسلة JavaScript عشوائية. ولأن مولد الأكواد الداخلي يُدرج هذا الحقل مباشرةً في نص دالة JavaScript المُولَّدة دون أي تعقيم، فإن الدالة الناتجة تنفّذ كودًا يتحكم به المهاجم عند العرض — مما يحقق تنفيذ الأوامر عن بُعد على الخادم.
قم ببناء وتشغيل البيئة القابلة للاستغلال باستخدام Docker:
بناء الصورة
docker build -t cve-2026-33937-server .
تشغيل الحاوية
docker run --name cve-2026-33937 -p 12701:12701 -p 9229:9229 cve-2026-33937-server
أو استخدم سكربتات npm المرفقة:
npm run docker:up # build + run in one step
يتم تقديم التطبيق على http://localhost:12701.
واجهة الويب
افتح http://localhost:12701 في المتصفح. تعرض الصفحة واجهة منشئ قوالب بريد إلكتروني من نوع B2B. يتم إقحام قيم الحقول التي يقدمها المستخدم في سلسلة قالب Handlebars من جهة العميل ثم إرسالها إلى الخادم لعرضها. قم بحقن حمولة Handlebars خبيثة عبر حقول الإدخال أو مباشرة عبر الـ API.
الـ API المباشر
# POST crafted template to the vulnerable endpoint
curl -s -X POST http://localhost:12701/api/email/preview \
-H "Content-Type: application/json" \
-d '{"subject":"test","editorTemplateData":"<PAYLOAD>"}'
استبدل <PAYLOAD> بحمولة حقن AST تستهدف Handlebars.compile().
POST /api/email/preview
يقبل الخادم نص JSON يحتوي على editorTemplateData ويمرره مباشرةً إلى Handlebars.compile() دون أي تعقيم أو فرض لقائمة مسموحة:
// app.js
const renderEmail = Handlebars.compile(editorTemplateData);
توثيق Handlebars.compile() ينص على أنه يقبل سلسلة قالب، لكن الفحص النوعي الداخلي يسمح أيضًا بتمرير كائن AST محلَّل مسبقًا مباشرةً. داخل javascript-compiler.js، يقوم زائر NumberLiteral() بإدراج حقل value الخاص بالعقدة حرفيًا في كود JavaScript المُولَّد دون أي تحقق من النوع أو تعقيم:
// javascript-compiler.js (simplified)
NumberLiteral(number) {
this.pushStackLiteral(number.value); // value inserted as-is into emitted JS
}
إذا وفّر المهاجم كائن AST مُصمَّمًا بحيث تكون number.value سلسلة تحتوي على JavaScript عشوائي (مثل: "1; require('child_process').execSync(...)") بدلًا من قيمة رقمية، فإن نص الدالة المُولَّد سيحتوي على ذلك الكود وينفذه عند العرض.
النمط الخطير في التطبيق القابل للاستغلال هو:
const render = Handlebars.compile(userInput); // userInput may be a crafted AST object
render(safeContextData); // attacker code runs here
ملاحظة حول أسلوب الاستغلال: تُحقّق الـ PoCs العامة الموجودة (بما في ذلك تلك المُشار إليها) الحقن عبر عقدة
NumberLiteralمقترنة بمساعدlookup. يؤكد هذا الـ PoC نفس بدائية RCE باستخدام عقدةBooleanLiteralمقترنة بالمساعد المدمجlog، مما يُظهر أن الالتباس النوعي لا يقتصر على نوع عقدة واحد أو دالة مساعد واحدة.
/api/email/preview بقيمة editorTemplateData مُصمَّمة بعناية.Handlebars.compile() على كائن AST الذي يتحكم به المهاجم.render() يؤدي إلى تنفيذ JavaScript عشوائي في عملية الخادم.عندما يتم تنفيذ Handlebars في بيئة خلفية Node.js، تؤدي هذه الثغرة إلى مسار تنفيذ أكواد على جانب الخادم، على عكس XSS المعتاد من جهة العميل. لا يتطلب الهجوم أي انعكاس للمخرجات إلى المستخدم؛ فالحمولة تُنفَّذ داخل عملية Node.js بنفس صلاحيات التطبيق. اعتمادًا على بيئة النشر:
/etc/passwd) وتسريبها.+-------------------------------------------+
| Attacker |
+-------------------------------------------+
|
| POST /api/email/preview
| {"editorTemplateData": "<malicious payload>"}
v
+-------------------------------------------+
| Handlebars.compile(editorTemplateData) |
| (No sanitization — app.js:17) |
+-------------------------------------------+
|
| AST node injection
| breaks template sandbox
v
+-------------------------------------------+
| Arbitrary JS Execution (Server Process) |
+-------------------------------------------+
|
| Read sensitive files, spawn shell,
| exfiltrate secrets, etc.
v
+-------------------------------------------+
| Remote Code Execution (RCE) |
+-------------------------------------------+
قم بترقية Handlebars.js إلى 4.7.9 أو أحدث.
يضيف الإصدار 4.7.9 تحققًا صارمًا من نوع الإدخال في compile()، بحيث يرفض الوسائط غير النصية قبل بدء توليد الأكواد.
فرض فحص النوع قبل استدعاء compile().
إذا لم يكن الترقية الفورية ممكنة، تحقق دائمًا من أن الوسيطة هي string في موقع الاستدعاء:
if (typeof templateInput !== 'string') throw new TypeError('Template must be a string');
const render = Handlebars.compile(templateInput);
استخدم handlebars/runtime للترجمة المسبقة في وقت البناء.
قم بترجمة القوالب مسبقًا في وقت البناء باستخدام واجهة الأوامر الخاصة بـ Handlebars وشحن حزمة التشغيل (runtime bundle) فقط. لا تتضمن نسخة التشغيل compile()، مما يلغي سطح الهجوم تمامًا في بيئات الإنتاج.
هذا المستودع مخصص حصريًا لأغراض البحث الأمني والتعليم والعرض المتحكم به للثغرات. يجب عدم استخدامه لاختبار أو استغلال الأنظمة دون إذن كتابي صريح من مالك النظام. الغرض من هذا المشروع هو مساعدة الباحثين الأمنيين والمدافعين والمطورين على فهم الثغرة والتحقق من التعرض في بيئات مختبرية خاضعة للسيطرة وتطبيق إجراءات التخفيف الفعالة.