
दूरस्थ कोड निष्पादन DbGate में functionName इंजेक्शन के माध्यम से loadReader एंडपॉइंट में — CVSS 8.8
functionName इंजेक्शन के माध्यम से DbGate में रिमोट कोड एक्ज़ीक्यूशनगंभीरता: उच्च (CVSS 8.8)
CWE: CWE-94 — कोड जनरेशन का अनुचित नियंत्रण ('कोड इंजेक्शन')
प्रभावित: dbgate-api ≤ 7.1.8 (7.1.9 में पैच किया गया)
सलाह: GHSA-hv83-ggc4-v385
NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-48017
श्रेय: Romain Deperne
POST /runners/load-reader एंडपॉइंट एक functionName पैरामीटर लेता है और उसे
सीधे एक JavaScript टेम्पलेट स्ट्रिंग में इंटरपोलेट करता है जिसे फिर एक फोर्क किए गए प्रोसेस में निष्पादित किया जाता है — बिना किसी
सैनिटाइज़ेशन या वैलिडेशन के। कोई भी प्रमाणित उपयोगकर्ता (किसी विशेष अनुमति की आवश्यकता नहीं) इच्छित कॉल से बाहर निकल सकता है
और मनमाना JavaScript चला सकता है, जिससे सर्वर पर रिमोट कोड एक्ज़ीक्यूशन प्राप्त होता है।
फोर्क किया गया रनर सैंडबॉक्स के रूप में require = null सेट करता है, लेकिन process.binding("spawn_sync") पहुँच योग्य बना रहता है:
process.binding("spawn_sync") अभी भी पहुँच योग्य है और एक वास्तविक OS प्रोसेस स्पॉन करता है।
मैं गार्डेड और अनगार्डेड कोड-एक्ज़ीक्यूशन पथों के बीच के अंतर के लिए DbGate के रनर सबसिस्टम का ऑडिट कर रहा था।
runners.js:292 पर start() रनर उचित रूप से गेटेड है — यह
testStandardPermission('run-shell-script') को कॉल करता है और platformInfo.allowShellScripting की जाँच करता है।
loadReader() संकल्पनात्मक रूप से समान कार्य करता है (यह एक JS लोडर स्क्रिप्ट बनाता और चलाता है) लेकिन इसमें
उनमें से कोई भी जाँच नहीं है। मैंने डेटा फ़्लो का पता लगाया:
runners.js:353 loadReader({ functionName, props })
runners.js:366 loaderScriptTemplate(prefix, functionName, ...)
runners.js:64 `... ${compileShellApiFunctionName(functionName)}(${JSON.stringify(props)});`
packageTools.ts:33 return `dbgateApi.${functionName}` // ← no sanitization
functionName हमलावर-नियंत्रित है और निष्पादित टेम्पलेट स्ट्रिंग के अंदर आता है। इसके सामने केवल dbgateApi.
प्रीफ़िक्स है, और इसे बायपास किया जा सकता है: एक्सप्रेशन को toString(); से बंद करके,
पेलोड इंजेक्ट करके, और पीछे आने वाले (${props}) को // से कमेंट करके मान्य JS प्राप्त होता है।
फ़ाइल: packages/api/src/controllers/runners.js (loadReader → loaderScriptTemplate)
फ़ाइल: packages/tools/src/packageTools.ts:33 (compileShellApiFunctionName)
// packageTools.ts:33 — functionName flows in unsanitized
return `dbgateApi.${functionName}`;
// runners.js:64 — interpolated into the executed loader template
`const reader = await ${compileShellApiFunctionName(functionName)}(${JSON.stringify(props)});`
उत्पन्न (इंजेक्ट किया गया) स्क्रिप्ट:
const reader = await dbgateApi.toString();
process.binding("spawn_sync").spawn({ file:"/bin/sh", args:["/bin/sh","-c","id"], ... });
dbgateApi.toString//({});
compileShellApiFunctionName() को एक छोटे नाम को पूरी तरह योग्य API पथ (dbgateApi.<name>) में बदलने के लिए लिखा गया था, जो कि functionName को एक पहचानकर्ता (identifier) मानने की अंतर्निहित धारणा रखता है। हालाँकि, यह मान सीधे HTTP अनुरोध बॉडी से आता है। चूँकि इसे उस स्रोत में जोड़ा जाता है जिसे बाद में eval/fork किया जाता है, यह विश्वास की धारणा एक RCE है। require = null सैंडबॉक्स इसमें मदद नहीं करता — Node का आंतरिक process.binding("spawn_sync") इसे बायपास कर देता है।
फ़िक्स (7.1.9): लोडर स्क्रिप्ट में संकलित करने से पहले functionName को एक सख़्त पहचानकर्ता अनुमति-सूची के विरुद्ध सत्यापित करें।
poc/rce_loadreader_functionname_injection.py — वास्तविक एंडपॉइंट को एंड-टू-एंड चलाता है।
# with an existing JWT
python3 poc/rce_loadreader_functionname_injection.py http://localhost:3000 <JWT> 'id > /tmp/pwned'
# or log in first
python3 poc/rce_loadreader_functionname_injection.py http://localhost:3000 --login admin password 'id'
स्क्रिप्ट functionName पेलोड बनाती है, उसे POST /runners/load-reader पर भेजती है, और
इंजेक्ट किया गया spawn_sync कॉल फोर्क किए गए रनर प्रोसेस में कमांड निष्पादित करता है।
DbGate API होस्ट पर प्रमाणित RCE। DbGate एक डेटाबेस प्रबंधन GUI है जिसे अक्सर आंतरिक डेटाबेस तक व्यापक नेटवर्क पहुँच के साथ तैनात किया जाता है — इस पर कोड निष्पादन डेटा टियर में एक मजबूत पिवट है।
जिम्मेदारी से प्रकट किया गया। PoC फिक्स जारी होने के बाद प्रकाशित किया गया, डिफेंडर्स और डिटेक्शन इंजीनियरिंग के लिए।