
wp2shell (CVE-2026-63030 & CVE-2026-60137) - पूर्ण RCE श्रृंखला
Searchlight Cyber की wp2shell सलाह से जुड़े, बिना प्रमाणीकरण वाले WordPress REST बैच रूट-कन्फ्यूजन SQL इंजेक्शन के लिए स्वतंत्र प्रूफ-ऑफ-कॉन्सेप्ट।
यह रिपॉज़िटरी Searchlight Cyber का आधिकारिक चेकर नहीं है। check SQLi पथ की पुष्टि करता है, read डेटाबेस पठन प्रदर्शित करता है, और shell प्रदान किए गए व्यवस्थापक क्रेडेंशियल के साथ या पहले SQLi-से-व्यवस्थापक ब्रिज का उपयोग करके प्लगइन-समर्थित कमांड शेल खोलता है।
Searchlight Cyber की सलाह में wp2shell RCE एक्सपोज़र के ये रेंज सूचीबद्ध हैं:
| संस्करण रेंज | स्थिति |
|---|---|
| <= 6.8.5 | प्रभावित नहीं |
| 6.9.0 – 6.9.4 | प्रभावित |
| 7.0.0 – 7.0.1 | प्रभावित |
REST बैच एंडपॉइंट (/batch/v1) बिना प्रमाणीकरण के होता है और एक ही कॉल में कई सब-रिक्वेस्ट चलाता है, यह भरोसा करते हुए कि प्रत्येक सब-रिक्वेस्ट की अपने आप में मान्यता और अनुमति जांच होती है।
serve_batch_request_v1() दो समानांतर ऐरे बनाता है — $matches (प्रत्येक सब-रिक्वेस्ट के लिए मिलान किया गया हैंडलर) और $validation (प्रत्येक सब-रिक्वेस्ट के लिए मान्यता परिणाम) — फिर डिस्पैच करते समय दोनों को समान ऑफसेट पर इंडेक्स करता है। जिस सब-रिक्वेस्ट का पथ wp_parse_url() में विफल रहता है, उसे $validation में जोड़ा जाता है लेकिन $matches में नहीं, इसलिए ऐरे चरण से बाहर हो जाते हैं और एक सब-रिक्वेस्ट को किसी अन्य सब-रिक्वेस्ट के हैंडलर के अंतर्गत डिस्पैच किया जाता है। यही रूट कन्फ्यूजन है।
PoC इस प्रिमिटिव को दो बार नेस्ट करता है:
POST /wp/v2/posts रिक्वेस्ट जिसमें requests बॉडी होती है, बैच हैंडलर के अंतर्गत ही डिस्पैच होती है। पोस्ट्स रिक्वेस्ट के रूप में मान्य होने के कारण, उसकी requests सूची की बैच स्कीमा के विरुद्ध कभी जाँच नहीं होती, इसलिए उसकी सब-रिक्वेस्ट GET का उपयोग कर सकती हैं — विधि अनुमति-सूची को दरकिनार कर दिया जाता है।GET /wp/v2/posts/999999 आइटम-रूट रिक्वेस्ट पोस्ट्स कलेक्शन क्वेरी पैरामीटर जैसे author_exclude, orderby, और per_page ले जाती है। 999999 आईडी का मौजूद होना आवश्यक नहीं है; यह केवल एक असंभावित पोस्ट आईडी है जिसका उपयोग आइटम रूट से मिलान के लिए किया जाता है, जिसकी स्कीमा उन केवल-कलेक्शन पैरामीटरों को मान्य नहीं करती। फिर डेसिंक उसी रिक्वेस्ट को पोस्ट्स get_items() के अंतर्गत डिस्पैच करता है, जहाँ author_exclude WP_Query के क्वेरी वेरिएबल से मैप होता है, जिसे कमजोर बिल्ड SQL में स्ट्रिंग के रूप में सम्मिलित करता है।परिणाम एक बूलियन- और टाइम-आधारित ब्लाइंड SQL इंजेक्शन है जो प्री-प्रमाणीकरण में पहुँच योग्य है। इस PoC में SQLi-से-व्यवस्थापक श्रृंखला में उपयोग किया जाने वाला UNION फेक-पोस्ट प्रिमिटिव भी शामिल है।
यहाँ लागू किया गया RCE पथ है:
wp_posts पंक्तियों का उपयोग करें। रेंडर ब्रिज /wp/v2/posts/999999 आइटम-रूट स्रोत का उपयोग करता है — वही रूट जिसका उपयोग SQLi read get_items() तक पहुँचने के लिए करता है।POST /wp/v2/users तक पहुँचने दें, जिससे एक जनरेटेड व्यवस्थापक बनता है।चरण 1–5 प्री-प्रमाणीकरण हैं; कमांड-निष्पादन चरण प्रमाणित व्यवस्थापक प्लगइन अपलोड है।
Python 3.8+ और मानक लाइब्रेरी। कोई तृतीय-पक्ष निर्भरता नहीं।
इसे रिपॉज़िटरी निर्देशिका से चलाएँ:
./wp2shell.py <command> <url> [options]
या अपने PATH पर wp2shell कमांड पाने के लिए pip install . चलाएँ।
पहले निष्क्रिय WordPress मार्कर और सार्वजनिक संस्करण संकेत प्रिंट करता है, फिर एक हानिरहित बैच मार्कर प्रोब भेजता है। एक कमजोर बैच कार्यान्वयन रूट-कन्फ्यूजन मार्कर पैटर्न parse_path_failed, block_cannot_read, और rest_batch_not_allowed के साथ HTTP 207 लौटाता है।
मार्कर प्रोब WordPress कोर फिक्स पर आधारित है। विकृत /// रिक्वेस्ट parse_path_failed बनाती है; एक /wp/v2/posts रिक्वेस्ट बैच-अनुमत स्पेसर के रूप में कार्य करती है; /wp/v2/block-renderer/... रूट बैच-अनुमत नहीं है लेकिन यदि उसका हैंडलर गुमनाम रूप से पहुँचा जाता है तो block_cannot_read लौटाता है; /batch/v1 rest_batch_not_allowed देता है। कमजोर बिल्डों पर पार्स त्रुटि बैच हैंडलर ऐरे को चरण से बाहर कर देती है, इसलिए स्पेसर रिक्वेस्ट ब्लॉक-रेंडरर हैंडलर के अंतर्गत डिस्पैच होती है। सही किए गए बिल्ड ऐरे को संरेखित रखते हैं, इसलिए क्राफ्ट किए गए प्रोब के लिए यह सटीक तीनों-पैटर्न दिखाई नहीं देना चाहिए।
डिफ़ॉल्ट रूप से, check वहीं रुक जाता है और SQLi पेलोड नहीं भेजता। जब आप सक्रिय SQLi पुष्टि भी चाहते हैं तो --confirm-sqli का उपयोग करें। पुष्टि पहले UNION रीड प्रिमिटिव आज़माती है और यदि UNION प्रतिबिंब उपलब्ध नहीं है तो युग्मित टाइमिंग प्रोब पर वापस आ जाती है।
संकेत स्वतंत्र हैं: संस्करण संकेत केवल एक संकेत है, मार्कर पैटर्न रूट कन्फ्यूजन दिखाता है, और --confirm-sqli दिखाता है कि पेलोड डेटाबेस तक पहुँचा। एक WAF पेलोड को अवरुद्ध कर सकता है, इसलिए विफल पुष्टि यह साबित नहीं करती कि बग अनुपस्थित है।
./wp2shell.py check http://target
./wp2shell.py check targets.txt # scan every URL in the file
./wp2shell.py read http://target # server fingerprint
./wp2shell.py read http://target --preset users # user logins and password hashes
./wp2shell.py read http://target --query "SELECT @@version"
डिफ़ॉल्ट रूप से निष्कर्षण --technique auto है, जो उपलब्ध विधियों को इस क्रम में आज़माता है:
UNION के माध्यम से एक फेक WP_Post पंक्ति बनाता है और उसका शीर्षक REST प्रतिक्रिया से ||HEX(value)|| के रूप में वापस पढ़ता है। पेलोड उसी /wp/v2/posts/999999 स्रोत रूट का उपयोग orderby=none और per_page=500 के साथ करता है ताकि फेक पंक्ति रेंडर की गई पोस्ट के रूप में बनी रहे। प्रति मान एक रिक्वेस्ट।EXTRACTVALUE/UPDATEXML प्रति रिक्वेस्ट ~15 बाइट लीक करते हैं, जब लक्ष्य MySQL त्रुटियों को प्रतिबिंबित करता है (जैसे WP_DEBUG_DISPLAY चालू)।X-WP-Total हेडर को सत्य/असत्य संकेत के रूप में पढ़ता है और किसी प्रतिबिंबित मान की आवश्यकता नहीं होती।किसी एक को --technique union|error|blind से बाध्य करें। ये रीड पथ डेटाबेस पंक्तियाँ नहीं लिखते।
--user और --password के साथ, shell प्रदान किए गए व्यवस्थापक क्रेडेंशियल से लॉग इन करता है और WordPress प्लगइन अपलोड व्यवहार का उपयोग करता है।
क्रेडेंशियल के बिना, shell पहले प्री-ऑथ SQLi-से-व्यवस्थापक ब्रिज चलाता है, जनरेटेड व्यवस्थापक के रूप में लॉग इन करता है, फिर प्लगइन शेल अपलोड करता है।
./wp2shell.py shell http://target --user admin --password '<recovered>' --cmd id
./wp2shell.py shell http://target --user admin --password '<recovered>' -i # interactive shell
./wp2shell.py shell http://target --cmd id # pre-auth bridge
./wp2shell.py shell http://target -i # pre-auth interactive
shell एक प्लगइन वेबशेल अपलोड करता है (यादृच्छिक पथ और प्रति-रन टोकन के पीछे लॉक) और उसका पथ प्रिंट करता है। अपलोड किया गया वेबशेल स्वचालित रूप से हटा दिया जाता है। जब प्री-ऑथ ब्रिज एक व्यवस्थापक बनाता है, तो शेल सत्र समाप्त होने के बाद वह जनरेटेड खाता स्वचालित रूप से हटा दिया जाता है।
WordPress 7.0.2 में अपडेट करें, या 6.9.5 यदि साइट 6.9 शाखा पर है। तब तक, एज पर /wp-json/batch/v1 और rest_route=/batch/v1 क्वेरी पैरामीटर दोनों को ब्लॉक करें, या rest_pre_dispatch फ़िल्टर के माध्यम से बैच एंडपॉइंट के लिए प्रमाणीकरण आवश्यक करें।
केवल अधिकृत सुरक्षा परीक्षण के लिए। इसका उपयोग केवल उन प्रणालियों के विरुद्ध करें जिनके स्वामी आप हैं या जिनके परीक्षण के लिए आपके पास स्पष्ट लिखित अनुमति है। कोई वारंटी प्रदान नहीं की जाती है और दुरुपयोग के लिए कोई दायित्व स्वीकार नहीं किया जाता है।
author__not_in| विकल्प | किस पर लागू होता है | विवरण |
|---|
--proxy URL | all | ट्रैफ़िक को HTTP प्रॉक्सी के माध्यम से रूट करें (उदाहरण के लिए, Burp)। |
--timeout N | all | रिक्वेस्ट टाइमआउट सेकंडों में। |
--sleep N | check | --confirm-sqli के लिए टाइमिंग फॉलबैक द्वारा उपयोग की जाने वाली देरी। |
--samples N | check | --confirm-sqli के लिए टाइमिंग फॉलबैक द्वारा उपयोग किए जाने वाले टाइमिंग जोड़े। |
--confirm-sqli | check | एक सक्रिय SQLi पुष्टि पेलोड भी भेजें। |
--preset | read | fingerprint या users। |
--technique | read | auto (डिफ़ॉल्ट), union (इन-बैंड, फेक पोस्ट बनाता है), error (इन-बैंड, दृश्यमान DB त्रुटियों की आवश्यकता है), या blind। |
--query | read | पढ़ने के लिए एक स्केलर SQL एक्सप्रेशन। |
--prefix | read | डेटाबेस टेबल उपसर्ग (डिफ़ॉल्ट wp_)। |
--max-length N | read | प्रति मान पढ़े जाने वाले अधिकतम वर्ण (डिफ़ॉल्ट 128)। |
--user / --password | shell | वैकल्पिक व्यवस्थापक क्रेडेंशियल; प्री-ऑथ ब्रिज का उपयोग करने के लिए दोनों छोड़ दें। |
--cmd | shell | चलाने के लिए कमांड (-i का उपयोग करते समय छोड़ दें)। |
-i / --interactive | shell | तैनाती के बाद एक इंटरैक्टिव शेल खोलें। |