
Root-cause विश्लेषण, passive version checker, और CVE-2026-18322 के लिए lab PoC, जो Smart Popup by Supsystic WordPress plugin में एक unauthenticated privilege escalation है।
CVE-2026-18322 पर सुरक्षा शोध, जो WordPress प्लगइन Smart Popup by Supsystic
(popup-by-supsystic) में एक अनधिप्रमाणित विशेषाधिकार-वृद्धि भेद्यता है। इस रिपॉज़िटरी में
अपस्ट्रीम स्रोत डिफ़ से प्राप्त मूल-कारण विश्लेषण, निकाले गए पैच, प्रभावित इंस्टॉलेशनों की
पहचान के लिए एक डिटेक्शन टूल (निष्क्रिय संस्करण फिंगरप्रिंटर) और शोषण PoC के लिए एक लैब
शामिल है।
यह भेद्यता सार्वजनिक और पैच की गई है। यह कार्य रक्षात्मक उपयोग के लिए प्रकाशित है: ऑपरेटरों को प्रभावित होस्ट खोजने और उनका उपचार करने में सहायता करना।
| संस्करण सीमा | स्थिति |
|---|---|
< 1.13.0 | भेद्य |
>= 1.13.0 | ठीक किया गया |
1.13.0 (31.07.2026 को जारी) पहला पैच किया गया रिलीज़ है; यह नीचे वर्णित श्रृंखला की सभी तीन कड़ियों को ठीक करता है। विश्लेषण का §1 देखें।
तीन स्वतंत्र कमज़ोरियाँ मिलकर अनधिप्रमाणित प्रशासक निर्माण बनाती हैं:
1. एक अनुमति-मैप टकराव — havePermissions() ने दो अनुमति मैप को array_merge() से
संयोजित किया। दोनों स्ट्रिंग कुंजी PPS_USERLEVELS ('userlevels') का उपयोग करते हैं, और
array_merge() स्ट्रिंग कुंजियों को अधिलेखित कर देता है, इसलिए बेस कंट्रोलर की छोटी
डिफ़ॉल्ट सूची ने पॉपअप मॉड्यूल की सूची को पूरी तरह बदल दिया — save और नौ अन्य विधियों से
प्रशासक प्रतिबंध को चुपचाप हटा दिया:
$permissions = $mod->getController()->getPermissions(); // [... 'save' ...]
$permissionsBase = $mod->getController()->getBasePermissions(); // ['getListForTbl','removeGroup','clear']
$permissions = array_merge($permissions, $permissionsBase); // base wins — 'save' is gone
जाँच खुली विफल होती है: मैप में अनुपस्थित क्रिया को कभी अस्वीकार नहीं किया जाता।
2. अजनबियों को भेजा गया पुन: प्रयोज्य nonce — save को अभी भी pps_nonce की आवश्यकता
थी, लेकिन सदस्यता पुष्टिकरण ईमेल में वही nonce क्रिया अंतर्निहित थी। लॉग-आउट उपयोगकर्ताओं
के लिए WordPress nonce uid=0 पर कुंजीबद्ध होता है, इसलिए अनाम ग्राहक के लिए बनाया गया टोकन
किसी भी अनाम हमलावर के लिए सत्यापित होता है।
3. कोई सर्वर-साइड भूमिका अनुमतिसूची नहीं — createWpSubscriber() ने कॉन्फ़िगर की गई भूमिका
को सीधे WP_User::set_role() को पास कर दिया। प्लगइन की सुरक्षित भूमिका सूची (जो
administrator को बाहर रखती है) केवल एडमिन ड्रॉपडाउन प्रस्तुत करते समय लागू की गई थी — एक
केवल-UI नियंत्रण।
श्रृंखलाबद्ध: nonce पाने के लिए सदस्यता लें → popup::save के विरुद्ध इसे पुन: चलाएँ ताकि
sub_wp_create_user_role=administrator सेट हो जाए → सदस्यता प्रवाह को ट्रिगर करें → स्थायी
एडमिन खाता।
फ़ाइल/पंक्ति संदर्भों के साथ पूर्ण वॉकथ्रू: docs/ANALYSIS.md।
poc/cve_2026_18322_check.py निर्धारित करता है कि कोई साइट प्रभावित संस्करण चलाती है या नहीं।
यह कभी शोषण का प्रयास नहीं करता: यह सादे HTTP GET जारी करता है और वह संस्करण पढ़ता है जो
इंस्टॉल अपने बारे में प्रकाशित करता है।
git clone <this-repo> && cd CVE-2026-18322
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
requests अनुशंसित है लेकिन वैकल्पिक — टूल मानक लाइब्रेरी पर वापस चला जाता है।
# Single target
python3 poc/cve_2026_18322_check.py https://example.com
# With supporting evidence
python3 poc/cve_2026_18322_check.py https://example.com -v
# Many targets, concurrently, exporting results
python3 poc/cve_2026_18322_check.py -f targets.txt -t 20 --json results.json
python3 poc/cve_2026_18322_check.py -f targets.txt --csv results.csv --only-vulnerable
# Through a proxy, ignoring TLS errors (lab use)
python3 poc/cve_2026_18322_check.py https://staging.internal -k --proxy http://127.0.0.1:8080
लक्ष्य तर्कों के रूप में या -f के माध्यम से दिए जा सकते हैं (- stdin पढ़ता है)। एक
नंगा होस्टनाम https:// माना जाता है।
$ python3 poc/cve_2026_18322_check.py https://example.com -v
[VULNERABLE] https://example.com/ (Smart Popup by Supsystic 1.11.2) < 1.13.0 affected by CVE-2026-18322; upgrade to 1.13.0+
- asset-version: plugin asset enqueued with ?ver=1.11.2 (https://example.com/)
- homepage-reference: references /plugins/popup-by-supsystic/ (https://example.com/)
- readme: plugin readme.txt is publicly readable (https://example.com/wp-content/plugins/popup-by-supsystic/readme.txt)
- readme-stable-tag: Stable tag: 1.11.2 (.../readme.txt)
| स्थिति | अर्थ |
|---|---|
VULNERABLE | प्लगइन < 1.13.0 पर पाया गया |
NOT_VULNERABLE | प्लगइन >= 1.13.0 पर पाया गया |
PLUGIN_DETECTED_VERSION_UNKNOWN | प्लगइन मौजूद, संस्करण निर्धारित नहीं — मैन्युअल रूप से सत्यापित करें |
PLUGIN_NOT_DETECTED | प्लगइन का कोई प्रमाण नहीं (अनुपस्थिति का प्रमाण नहीं) |
ERROR | लक्ष्य अगम्य या विकृत |
एग्ज़िट कोड: 0 = कोई भेद्य लक्ष्य नहीं, 1 = कम से कम एक भेद्य, 2 = उपयोग त्रुटि।
दो निष्क्रिय संकेत, दोनों सार्वजनिक संसाधनों के सादे HTTP GET:
?ver=PPS_VERSION के साथ एनक्यू करता है
(classes/frame.php:410,473), इसलिए होमपेज अक्सर सटीक संस्करण लीक कर देता है।readme.txt — Stable tag: आधिकारिक है और संभावित रूप से पुराने कैश्ड एसेट पर
प्राथमिकता लेता है; चेंजलॉग फ़ॉलबैक के रूप में कार्य करता है।होमपेज स्कैन नाम बदले गए wp-content निर्देशिकाओं (जैसे Bedrock का /app/) को भी खोजता है
ताकि readme लुकअप साइट के वास्तविक लेआउट का अनुसरण करे।
डिटेक्शन टूल शोषण का प्रयास नहीं करता। इस CVE के लिए कोई हथियारबंद एक्सप्लॉइट यहाँ प्रकाशित नहीं है: पूरी श्रृंखला चलाने वाला एकमात्र कोड स्थानीय लैब तक कठोरता से सीमित है (नीचे देखें)।
निष्क्रिय चेकर केवल संस्करण फिंगरप्रिंटिंग करता है। इसका HttpClient GET के अतिरिक्त कोई
HTTP क्रिया उजागर नहीं करता — निर्माण द्वारा लागू और टेस्ट सूट में प्रमाणित, इसलिए यह
गलती से भी स्थिति-परिवर्तनकारी अनुरोध जारी नहीं कर सकता। यह कभी popup::save को कॉल नहीं
करता, sub_wp_create_user_role पैरामीटर नहीं भेजता, सदस्यता फ़ॉर्म सबमिट नहीं करता,
पुष्टिकरण ईमेल ट्रिगर नहीं करता, या किसी उपयोगकर्ता, पॉपअप, या सेटिंग को बनाता या संशोधित
नहीं करता। यह दो सार्वजनिक संसाधन पढ़ता है — होमपेज और readme.txt — और कुछ नहीं।
इस सुरक्षा की एक कीमत है, स्पष्ट रूप से कही गई: निर्णय उतना ही अच्छा है जितना होस्ट द्वारा प्रकाशित संस्करण मेटाडेटा। व्यापार-समझौते और विफलता मोड: §9।
lab/exploit_full_chain.py यहाँ का एकमात्र कोड है जो वास्तविक हमला करता है, और यह एक
WordPress प्रशासक बनाता है। यह इसलिए प्रकाशित है ताकि विश्लेषण पर भरोसा करने के बजाय
पुनरुत्पादित किया जा सके — एक प्राधिकरण बग के बारे में दावा जिसे प्रदर्शित नहीं किया जा सकता,
वह एक कथन है, निष्कर्ष नहीं। यह lab/ में डिस्पोज़ेबल स्टैक के लिए लिखा गया है और
किसी और चीज़ के लिए नहीं: