
أبحاث أمنية على Liferay CE 7.0.3 GA4: إعادة إنتاج كاملة لثغرة تنفيذ تعليمات برمجية عن بُعد (RCE) قبل المصادقة بصلاحيات الجذر (root) ضمن فئة CVE-2020-7961، بالإضافة إلى 16 اكتشافًا آخر — أكثر من 8 منها بدون CVE معروف. مطاردة حلقية وكيلة (Agentic loop-hunt): 25 مولّدًا، و22 محكّمًا، و9 أدوات تحقق حية على Docker. يتضمن سلسلة أدلة وفاحصًا شاملاً.
مراجعة أمنية لـ Liferay Portal CE 7.0.3 GA4 (وسم git 7.0.3-ga4، الالتزام
b2d7cc68a) نُفذت بمنهجية RAPTOR loop-hunt:
استطلاع حتمي → 25 وكيل توليد معزول يقرؤون المصدر الخام → 22 وكيل حكم مستقل
يدحضون من المصدر الخام → 9 مدقّقين مباشرين يهاجمون نسخة GA4 حقيقية في Docker.
العنوان الرئيسي: RCE غير مصادَق عليه بصلاحيات
rootأُعيد إنتاجه من البداية إلى النهاية (من فئة CVE-2020-7961)، بالإضافة إلى 8 ثغرات إضافية تم التحقق منها مباشرةً — عدة منها بدون CVE معروف.
⚠️ قانوني/أخلاقي: كل ما هو هنا يستهدف نسخة اختبار مستضافة ذاتيًا. Liferay CE 7.0 في نهاية العمر (آخر إصدار 7.0.6 GA7، 2018)؛ هذه المشكلات غير مُصححة من upstream. استخدم هذه المواد فقط ضد أنظمة تملكها أو صرّح لك باختبارها صراحةً.
الحالة: ✅ تم التحقق منها مباشرةً على نسخة Docker GA4 · 🔬 مؤكَّدة بالكود (وكيل حكم مستقل أعاد اشتقاق المسار الكامل من المصدر الخام) · 🧪 تتطلب إعدادات/مشروطة بالتهيئة.
القائمة الكاملة المنسقة مع حالات الرفض: FINDINGS.md · التقرير السردي: REPORT.md
كتالوج يضم ~50 مشكلة معروفة في Liferay 7.0.x استُخدم كأساس معرفي سابق: PRIOR-ART.md
(OSV [email protected]، مسح NVD، نصائح Code White / CERT-EU).
"جديد" = لا يوجد CVE مطابق في نصائح OSV/NVD/Liferay حتى تاريخ 2026-07؛ النتائج لم تُقدَّم لتعيين CVE (خط المنتج في نهاية العمر).
CVE-2020-15840 (التفاف على مرشح URL بترميز مزدوج)، CVE-2024-8980 + CVE-2025-43748
(CSRF → RCE في وحدة تحكم السكربت)، CVE-2021-33335 (الاستيلاء على حساب مدير الشركة — GA4 هو الحد
الأدنى للنطاق المتأثر)، CVE-2017-1000425 (XSS في flash.jsp)، CVE-2021-29040 (أخطاء JSONWS مفصلة)،
CVE-2022-41414 / CVE-2023-33949 (إعدادات التعداد/التسجيل الافتراضية)، CVE-2025-62261 (رموز
إعادة التعيين بنص صريح — NVD يسمي 7.0.3 GA4 مباشرةً). انظر PRIOR-ART.md.
السجل: TRIED.md (كل ما تمت محاولته، بما في ذلك 3 شرائح جافة موثقة) · INVENTORY.md (مقام التغطية) · البيئة/التجهيزات: ENV.md
لا توجد صورة رسمية liferay/portal:7.0.3-ga4، لذا ابنِ من الحزمة الرسمية:
# Dockerfile
FROM openjdk:8-jdk
RUN apt-get update && apt-get install -y --no-install-recommends unzip curl \
&& rm -rf /var/lib/apt/lists/*
RUN curl -sSL -o /tmp/liferay.zip \
"https://downloads.sourceforge.net/project/lportal/Liferay%20Portal/7.0.3%20GA4/liferay-ce-portal-tomcat-7.0-ga4-20170613175008905.zip" \
&& unzip -q /tmp/liferay.zip -d /opt \
&& mv /opt/liferay-ce-portal-7.0-ga4 /opt/liferay \
&& rm /tmp/liferay.zip
EXPOSE 8080 11311
CMD ["/opt/liferay/tomcat-8.0.32/bin/catalina.sh", "run"]
docker build -t liferay-ga4 .
docker run -d --name liferay-ga4 -p 8080:8080 liferay-ga4
# first boot takes several minutes — wait for it:
until [ "$(curl -s -o /dev/null -w '%{http_code}' http://localhost:8080/)" = 200 ]; do sleep 10; done
ثم أكمل معالج الإعداد لمرة واحدة في http://localhost:8080/ (قاعدة بيانات HSQL الافتراضية؛ المعالج
يضبط كلمة مرور المدير لـ [email protected]).
tools/liferay_ga4_check.py هو سكربت Python 3 من ملف واحد، يعتمد على المكتبة القياسية فقط —
وجّهه إلى أي نسخة GA4 وسيختبر كل اكتشاف تم التحقق منه مباشرةً:
# passive validation of all findings (safe, no payloads detonated)
python3 tools/liferay_ga4_check.py http://localhost:8080
# with an account (self-registration is on by default) for the poller sink test
python3 tools/liferay_ga4_check.py http://localhost:8080 --user [email protected] --password '***'
# full RCE proof (opt-in): drops a SELF-DELETING JSP via the deserialization file-write
# gadget and fetches the command output; adjust --web-root to your install
python3 tools/liferay_ga4_check.py http://localhost:8080 --rce \
--web-root /opt/liferay/tomcat-8.0.32/webapps/ROOT
المخرجات المتوقعة مقابل تثبيت GA4 افتراضي: 9 اكتشافات VULNERABLE
(F-1، F-1+RCE، F-2، F-4، F-5*، F-8، F-11، F-12، F-13*) بالإضافة إلى F-10 المؤكَّد أنه ليس
ضعيفًا (حاجز النفق يصمد). *F-5 و F-13 يحتاجان معاملات تجهيز (--leg-uuid/--version-id،
--wcd-page/--group-id/--article-id) — انظر --help.
أداة إلغاء التسلسل تُولَّد بلغة Python خالصة داخل السكربت (تم التحقق منها بايتًا-ببايت مقابل حمولة ysoserial AspectJWeaver المستخدمة في المهمة) — لا حاجة إلى Java أو jars أو ysoserial.
تذاكر إعادة تعيين كلمة المرور (UUID 128-بت، لمرة واحدة، 24 ساعة)، تجديد الجلسة عند الدخول
بالتذكرة، ملف تعريف الارتباط remember-me المشفر بـ AES-128 بمفتاح SecureRandom خاص بكل شركة،
التجزئة الافتراضية PBKDF2، حزمة XML على مستوى البوابة (الكيانات الخارجية معطلة افتراضيًا)، بوابات
digest في WebDAV/SharePoint، أقفال IP للمضيف المحلي في /api/axis|/api/liferay|/api/atom،
التحقق من مسار الرفع، حراسات اجتياز المسار في /combo /sprite، تقييد omni-admin لوحدة تحكم
السكربت وواجهة Gogo على الويب.
تم تتبع التغطية لكل مكوّن مقابل الجرد الكامل (TRIED.md).
غير مغطى: تحليل دالة-بدالة على مستوى الشجرة الكاملة البالغة 4 غيغابايت (نقاط ارتكاز Semgrep فقط)،
ومعظم modules/apps خارج foundation/web-experience على مستوى الملفات، والبحث في gadget الخاص
بـ F-2، والاختبارات المباشرة بإعدادات غير افتراضية (F-9/F-14)، وإمكانية الوصول إلى CVE التبعية
PDFBox 2.0.3. أُوقفت الحلقة لإعداد التقرير، وليس لأنها استنفدت.
| ID | الاكتشاف | الخطورة | المصادقة | الحالة | الدليل |
|---|
| F-1 | تجاوز النوع في JSONWS → إنشاء فئات عشوائي + setters → RCE بصلاحيات root (c3p0 HexAsciiSerializedMap → ObjectInputStream → كتابة ملف عبر AspectJWeaver → JSP) | حرجة | لا شيء | ✅ | verified/f1-jsonws-deser-rce.md |
| F-2 | تلميح javaClass في jabsorb عبر /poller/* → إنشاء فئات عشوائي + حقن حقول، قبل التحقق من userId | عالية (محتملة) | أي حساب (التسجيل الذاتي مفعّل افتراضيًا) | ✅ sink مؤكَّد / ذراع RCE مفتوح | verified/F-2-poller.md |
| F-4 | XML-RPC pingback.ping جلب-قبل-التحقق → SSRF أعمى + استشعار منافذ داخلي (وصل إلى Gogo shell على 127.0.0.1:11311) | متوسطة | لا شيء | ✅ | verified/f4-xmlrpc-pingback-ssrf.md |
| F-5 | SyncDownloadServlet versionId IDOR → قراءة أي إصدار من ملفات DL (cross-site، لا فحص VIEW على الكائن المُمرَّر) | عالية | لا شيء (عبر جزء قابل للعرض من الضيوف) | ✅ | verified/F-5.md |
| F-6 | محرك قوالب XSL يتجاهل العزل (secureProcessing=false، restricted مُسقَط) → document() SSRF وتنفيذ أوامر XSLTC rt:exec | حرجة | مؤلف قالب الموقع | ✅ | verified/F-6-F-7-template-engines.md |
| F-7 | قوالب Velocity و FreeMarker المقيدة تكشف propsUtil / saxReaderUtil الخام → كشف خصائص البوابة + ملفات file:// للضيوف | عالية | مؤلف القالب | ✅ | verified/F-6-F-7-template-engines.md |
| F-8 | IDOR في جدول Image_ عبر /image/*?img_id=N — لا رمز، فحوصات نطاق البادئة تُلتفت بتبديل البادئة، معرّفات تسلسلية قابلة للتعداد | متوسطة | لا شيء | ✅ | verified/f-8-image-idor.md |
| F-11 | SimpleCaptcha = PIN من 4 أرقام، لا يُبطل أبدًا عند التخمينات الخاطئة، عداد الضيوف لا يزداد أبدًا → كسر عند ~5k طلب | متوسطة | لا شيء | ✅ | verified/f11-f12-captcha-reminder.md |
| F-12 | نسيان كلمة المرور: تعداد مستخدمين + oracle لإجابة سؤال التذكير بدون كابتشا (التفاف بجلسة جديدة)؛ إجابة فارغة تُطلق تذكرة إعادة تعيين حقيقية للحسابات التي ليس لديها سؤال أمان | متوسطة-عالية | لا شيء | ✅ | verified/f11-f12-captcha-reminder.md |
| F-13 | تجاوز معاملات الطلب في Web Content Display (groupId/articleId/ddmTemplateKey) → قراءة cross-site لمقالات غير مخصصة للضيوف (الافتراضي journal.article.view.permission.check.enabled=false) | عالية | لا شيء (يتطلب وجود WCD على صفحة ضيف) | ✅ | verified/F-13-wcd-param-override.md |
| F-3 | موسّع OSGi axis يتخطى ServiceAccessPolicy / تعليم الوصول عن بُعد على خدمات SOAP للوحدات | متوسطة (عالية مع وحدة WSDD) | لا شيء | 🔬 | judge/axis-spring-remoting.md |
| F-9 | OpenID يربط حساب الضحية بهوية OpenID الخاصة بالمهاجم قبل التحقق من التأكيد → الاستيلاء على الحساب | عالية | لا شيء (OpenID مفعّل، غير افتراضي) | 🔬 🧪 | judge/sso-autologin.md |
| F-10 | TunnelServlet readObject محمي فقط بقائمة سوداء للفئات؛ أدوات ROME/JdbcRowSetImpl/c3p0/AspectJWeaver على classpath | حرجة محتملة | نظير موثوق (سر مشترك + مضيف مسموح) | ✅ الحواجز تصمد قبل المصادقة | verified/f10-f20-tunnel-auth-pipeline.md |
| F-14 | TokenAutoLogin يثق في ترويسة SM_USER مجردة (لا تحقق، لا قائمة سماح IP) | متوسطة | لا شيء (SSO بالرمز مفعّل، غير افتراضي) | 🔬 🧪 | judge/sso-autologin.md |
| F-15 | استيراد LAR من مدير الموقع يُهرب RolesAdminPortletDataHandler → حذف جماعي لأدوار الشركة / مسح الأذونات | متوسطة | مدير الموقع | 🔬 | judge/export-import-lar.md |
| F-16 | OpenSocial (ليس في الحزمة الافتراضية): makeRequest SSRF قبل المصادقة، /gadgets/ifr JavaScript على مستوى الأصل، رموز أمنية قابلة للتزوير → انتحال شخصية، XSS مخزّنة | عالية ×4 | لا شيء / عضو الموقع | 🔬 (مشروط بالنشر) | judge/opensocial-shindig.md |
| F-17 | WSRP (ليس في الحزمة الافتراضية): ProxyServlet SSRF قبل المصادقة؛ نقطة نهاية markup → عرض portlet عشوائي + استمرارية typeSettings للتخطيط | متوسطة | لا شيء | 🔬 (مشروط بالنشر) | judge/wsrp.md |
| الاكتشاف | CVE معروف؟ | العلاقة |
|---|
| F-1 إلغاء تسلسل JSONWS RCE | CVE-2020-7961 (CISA KEV، مستغَل في البرية) | إعادة إنتاج + إعادة اشتقاق مستقلة. مؤكَّد أنه غير مُصحح في GA4؛ السلسلة الكاملة مُثبتة بأداة كتابة ملفات AspectJWeaver (PoCs العامة تستخدم عادةً JdbcRowSetImpl JNDI). |
F-10 readObject في TunnelServlet | CVE-2020-15842 (تطابق الفئة) | فئة معروفة. حارس إلغاء التسلسل القائم على القائمة السوداء فقط مؤكَّد؛ حواجز ما قبل المصادقة تم التحقق منها مباشرةً (غير قابلة للاستغلال بدون سر مشترك/مضيف مسموح). |
F-7 هروب propsUtil في القوالب | CVE-2020-13445 (حقن قوالب، FreeMarker/Velocity) | نسخة مختلفة. نفس فئة الخطأ (واجهة برمجة القوالب تفشل في تقييد الكائنات الحساسة)، آلية مختلفة: كائنات PropsImpl/saxReaderUtil الخام مكشوفة داخل السياق المقيد. |
| F-12 (نصف التعداد) | CVE-2021-33321 (login.secure.forgot.password=false) | إعداد افتراضي غير آمن معروف — تم تأكيده مباشرةً بشكل مستقل. |
| F-12 (oracle + تذكرة إعادة تعيين بإجابة فارغة) | لم يُعثر على شيء | جديد. التفاف كابتشا عبر JSESSIONID جديدة في الخطوة 2؛ إجابة answer فارغة تُنشئ تذكرة إعادة تعيين صالحة لمدة 24 ساعة للحسابات التي ليس لديها سؤال أمان بدون أي معرفة سرية. |
| F-11 القوة الغاشمة على SimpleCaptcha | لم يُعثر على شيء (CVE-2019-6588 مشكلة كابتشا مختلفة — XSS) | جديد. PIN من 4 أرقام + لا إبطال + التفاف عداد الضيوف. |
| F-2 إلغاء تسلسل jabsorb في poller | لم يُعثر على شيء | جديد. sink مؤكَّد مباشرةً؛ التسليح معطَّل بحقن الحقول في LiferaySerializer (بحث مفتوح). |
| F-4 oracle SSRF في pingback | لم يُعثر على شيء | جديد. |
F-5 IDOR في مزامنة versionId | لم يُعثر على شيء | جديد. |
| F-6 RCE في محرك XSL | لم يُعثر على شيء (CVE-2020-13445 يغطي FreeMarker/Velocity فقط) | جديد. محرك XSL كان خارج كل إصلاح سابق لحقن القوالب. |
F-8 IDOR في Image_ | لم يُعثر على شيء | جديد. |
| F-13 قراءة cross-site في WCD | لم يُعثر على شيء | جديد. السبب الجذري هو إعداد افتراضي غير آمن (journal.article.view.permission.check.enabled=false) بالإضافة إلى مسار توصيل جديد (تجاوز معاملات الطلب في الـ portlet). |
| F-3 التفاف SAP في axis-extender | لم يُعثر على شيء | جديد. |
| F-9 ربط OpenID قبل التحقق | لم يُعثر على شيء | جديد. |
F-14 الثقة في ترويسة SM_USER | لم يُعثر على شيء | جديد. |
| F-15 تهريب معالج بيانات الأدوار في LAR | لم يُعثر على شيء | جديد. |
| F-16 / F-17 OpenSocial / WSRP | لم يُعثر على شيء | جديد، لكن الوحدات ليست في حزمة GA4 الافتراضية (Liferay-Releng-Bundle: false). |
| الجولة | ما تم تشغيله | المخرجات |
|---|
| 0 — حتمي | تدقيق تبعيات raptor-sca (727 تبعية)، 17 قاعدة Semgrep (1,098 نقطة ارتكاز)، نموذج التهديد، قائمة نقاط الدخول من web.xml، كتالوج CVEs كأساس معرفي سابق | SCA.md SEMGREP.md THREAT-MODEL.md ENTRYPOINTS.md PRIOR-ART.md |
| 1 — توليد | 25 وكيل معزول، واحد لكل شريحة مكوّن × عدسة فئة أخطاء، الاستدلال من المصدر الخام فقط (لا ملخصات سابقة — مضاد للترسيخ) | 45 مرشحًا في candidates/ |
| 2 — حكم | 22 وكيل مستقل يدحضون كل مرشح من المصدر الخام؛ الرفض يتطلب دليلًا مرئيًا في الكود ("لا تفترض أن الطبقة غير المرئية آمنة") | judge/ |
| 3 — تحقق مباشر | 9 وكلاء يهاجمون نسخة Docker GA4؛ كل ادعاء مدعوم بطلب/استجابة مُلتقطين؛ تنظيف إلزامي | verified/ |