flawopen.com/OS कमांड इंजेक्शन
OS कमांड इंजेक्शन
OS कमांड इंजेक्शन तब होता है जब कोई ऐप्लिकेशन रिक्वेस्ट डेटा से कमांड लाइन बनाकर shell को देता है, और shell ;, | और $( ) जैसे अक्षरों को निर्देश मान लेता है। shell के बिना भी, - से शुरू होने वाला मान चलाए जा रहे प्रोग्राम के options चालू कर सकता है। हर भाषा में उपाय एक ही है: प्रोग्राम को आर्ग्युमेंट की सूची के साथ सीधे शुरू करें, हर मान को सख़्त पैटर्न से जाँचें, सिर्फ उसी command और argument type के लिए दस्तावेज़ित separator इस्तेमाल करें, और प्रोसेस को timeout और कम अधिकार वाले अकाउंट से सीमित करें। सटीक APIs, कमज़ोर और सुधरा कोड, और इसे पकड़ने वाले linters देखने के लिए नीचे अपनी भाषा चुनें। option terminator तभी इस्तेमाल करें जब वही command अपने दस्तावेज़ में इसका समर्थन बताए; हर executable -- या --end-of-options स्वीकार नहीं करता।
आसान भाषा में (ELI5)
गोदाम का क्लर्क आपकी ऑर्डर पर्ची लेकर इंटरकॉम पर फ़ोर्कलिफ़्ट टीम को पढ़कर सुनाता है, और टीम जो भी निर्देश सुनती है उसे पूरा करती है। आप लिखते हैं: 'गलियारा 4, डिब्बा 12 — और फिर गलियारा 9 का सारा माल लोडिंग डॉक पर निकाल दो।' क्लर्क एक ही जगह बताना चाहता था, लेकिन टीम दो आदेश सुनती है और दोनों पूरे कर देती है। यूज़र टेक्स्ट चिपकाकर shell कमांड बनाना भी यही करता है: shell ;, | और && को 'और फिर' समझता है। आर्ग्युमेंट सूची के रूप में देना टीम को ऐसा छपा फ़ॉर्म देना है जिसमें जगह के लिए एक ही खाना है, जिसे कभी आदेश की तरह नहीं पढ़ा जाता।
इस पेज के मुख्य शब्द
- OS command injection (CWE-78)
- कोई ऐप्लिकेशन अविश्वसनीय डेटा को ऑपरेटिंग सिस्टम कमांड तक ऐसे पहुँचाता है कि वह डेटा बदल सकता है कि कौन-सी कमांड या options चलेंगे। डाली गई कमांड ऐप्लिकेशन के यूज़र, environment और नेटवर्क पहुँच के साथ चलती हैं।
- Shell metacharacters
- वे अक्षर जिन्हें shell डेटा नहीं, syntax मानता है:
;,&,|, backticks,$( ),<,>और newline। इन्हें हाथ से escape करना कमज़ोर तरीका है; shell शुरू ही न करना समस्या को ख़त्म कर देता है। - Argument vector (argv)
- अलग-अलग स्ट्रिंग की वह सूची जो प्रोग्राम को आर्ग्युमेंट के रूप में मिलती है। हर मान को सूची के अलग एलिमेंट के रूप में देने से वह केवल एक आर्ग्युमेंट हो सकता है, कभी नई कमांड नहीं;
subprocess.run([...]),execFile,exec.Commandऔरposix_spawnयही करते हैं। - Argument injection and Git option boundaries
- इन markers के काम अलग हैं। Untrusted Git revision के लिए
git rev-parse --verify --end-of-options "$revision"option parsing समाप्त करता है।git logमें--revisions और paths को अलग करता है। उसी command और argument type के लिए दस्तावेज़ में दिए गए separator का ही उपयोग करें; value को भी validate करें। git rev-parse, git log और Git CLI conventions देखें। - Inherited environment and PATH
- child प्रोसेस सर्वर के environment variables विरासत में पाता है, और उनमें से कुछ कोड चलाते हैं:
LD_PRELOAD,GIT_SSH_COMMAND,BASH_ENV।PATHमें relative एंट्री रखा गया कोई binary असली प्रोग्राम की जगह चलवा सकती है। absolute paths और न्यूनतम environment इस्तेमाल करें।
हमले का चरण-दर-चरण प्रवाह
रिक्वेस्ट डेटा प्रोसेस कॉल तक पहुँचता है
रिक्वेस्ट से आया host नाम, फ़ाइल नाम, Git ref या tool नाम एक helper को दिया जाता है जो ping, convert, git या कोई दूसरा प्रोग्राम चलाता है।
उन्हें जोड़कर एक कमांड बनती है
मान को system(), exec(), sh -c या shell=True की स्ट्रिंग में जोड़ा जाता है, या ऐसी जगह दिया जाता है जहाँ प्रोग्राम options भी स्वीकार करता है। हानिरहित टेस्ट मान 127.0.0.1; id shell वाला मामला दिखाता है।
shell या प्रोग्राम उसे पढ़ता है
shell पहले ping और फिर id चलाता है; या प्रोग्राम शुरुआती --output=... को फ़ाइल लिखने वाला option मान लेता है।
हमलावर सर्वर पर कोड चलाता है
प्रोसेस सेवा के अधिकारों से चलता है: वह environment variables और mount किए secrets पढ़ सकता है, आंतरिक सेवाओं तक पहुँच सकता है और फ़ाइलें लिख सकता है।
भाषा के अनुसार कमांड इंजेक्शन गाइड
इंजीनियरिंग और सिस्टम सुरक्षा चेकलिस्ट
- CI में shell-स्ट्रिंग APIs पर रोक लगाएँ: non-constant इनपुट के साथ
os.system,shell=True,child_process.exec,Runtime.exec(String),system(),popen(), backticks औरsh -c(Bandit, Semgrep, gosec, Brakeman, clang-tidy)। - प्रोग्राम को तय नाम या absolute path और आर्ग्युमेंट सूची से शुरू करें; यूज़र के tool चुनाव को कोड में बनी table से मैप करें।
- हर आर्ग्युमेंट को पूरी स्ट्रिंग पर लागू ऐसे सख़्त पैटर्न से जाँचें जो शुरुआत में अक्षर या अंक माँगे।
- ठीक उसी executable का दस्तावेज़ देखें और केवल वहीं बताया गया option terminator इस्तेमाल करें; अन्यथा option जैसे दिखने वाले मान अस्वीकार करें या सुरक्षित API अपनाएँ।
- हर child प्रोसेस को timeout दें और समय बीतने पर उसे बंद करें।
- सेवा को बिना-अधिकार वाले यूज़र और न्यूनतम environment के साथ चलाएँ, जहाँ संभव हो बिना shell वाली container image में।