"ऐसी कोई भी कमांड चलाएं जो कमांड के रूप में तर्कों की व्याख्या करने वाली कमांडों को अविश्वासित डेटा पास करेगी"


18

मैनुअलटल के मैनुअल से:

उदाहरण के लिए इन दो कमांड जैसे निर्माण करता है

# risky
find -exec sh -c "something {}" \;
find -execdir sh -c "something {}" \;

बहुत खतरनाक हैं। इसका कारण यह है कि '{}' का विस्तार एक फ़ाइल नाम के साथ किया जा सकता है, जिसमें शेल के लिए एक अर्धविराम या अन्य वर्ण हो सकते हैं। उदाहरण के लिए अगर कोई फ़ाइल बनाता है /tmp/foo; rm -rf $HOMEतो ऊपर दिए गए दो कमांड किसी के होम डायरेक्टरी को डिलीट कर सकते हैं।

तो इस कारण से कोई भी कमांड नहीं चलाएंगे जो कि अविश्वासित डेटा (जैसे कि फाई लेस के नाम) को कमांड देगा, जो तर्कों को कमांड के रूप में आगे व्याख्या की जाएगी (उदाहरण के लिए 'श')।

शेल के मामले में, इस समस्या के लिए एक चतुर समाधान है:

# safer
find -exec sh -c 'something "$@"' sh {} \;
find -execdir sh -c 'something "$@"' sh {} \;

यह दृष्टिकोण हर समस्या से बचने की गारंटी नहीं है, लेकिन यह शेल कमांड के पाठ में हमलावर की पसंद के डेटा को प्रतिस्थापित करने की तुलना में अधिक सुरक्षित है।

  1. क्या इस समस्या का कारण यह है find -exec sh -c "something {}" \;कि प्रतिस्थापन के लिए {}अयोग्य है और इसलिए इसे एक स्ट्रिंग के रूप में नहीं माना जाता है?
  2. समाधान में find -exec sh -c 'something "$@"' sh {} \;,

    • पहले {}बदल दिया गया है, लेकिन जब {}से अयोग्य है, "$@"तो मूल कमांड के समान समस्या नहीं है ? उदाहरण के लिए, "$@"विस्तार करने के लिए किया जाएगा "/tmp/foo;", "rm", "-rf", और "$HOME"?

    • क्यों {}नहीं बच गया या उद्धृत किया गया?

  3. क्या आप अन्य उदाहरण दे सकते हैं ( sh -cयदि इसके साथ या इसके बिना, यदि लागू हो; इसके साथ या findजिसके बिना आवश्यक नहीं हो सकता है) जहां एक ही तरह की समस्या और समाधान लागू होते हैं, और जो न्यूनतम उदाहरण हैं ताकि हम समस्या और समाधान पर ध्यान केंद्रित कर सकें संभव के रूप में थोड़ा ध्यान भंग? `Bash -c` द्वारा निष्पादित कमांड के लिए तर्क प्रदान करने के तरीके देखें

धन्यवाद।


जवाबों:


29

यह वास्तव में उद्धृत करने से संबंधित नहीं है, बल्कि तर्क प्रसंस्करण के लिए है।

जोखिम भरे उदाहरण पर विचार करें:

find -exec sh -c "something {}" \;
  • यह छह शब्दों में खोल, और विभाजन से पार्स किया गया है: find, -exec, sh, -c, something {}(कोट के किसी भी अधिक), ;। विस्तार करने के लिए कुछ भी नहीं है। खोल findउन छह शब्दों के साथ तर्क के रूप में चलता है।

  • जब findप्रक्रिया को पाता कुछ, कहते हैं foo; rm -rf $HOME, यह बदल देता है {}के साथ foo; rm -rf $HOMEरन, और shतर्क के साथ sh, -c, और something foo; rm -rf $HOME

  • shअब देखता है -c, और परिणामस्वरूप परस something foo; rm -rf $HOME( पहला गैर-विकल्प तर्क ) और परिणाम निष्पादित करता है।

अब सुरक्षित संस्करण पर विचार करें:

find -exec sh -c 'something "$@"' sh {} \;
  • खोल रन findतर्क के साथ find, -exec, sh, -c, something "$@", sh, {}, ;

  • अब जब findपाता foo; rm -rf $HOMEहै, यह बदल देता है {}फिर से, और चलाता है shतर्क के साथ sh, -c, something "$@", sh, foo; rm -rf $HOME

  • shदेखता है -c, और पार्स something "$@"कमांड को चलाने के लिए के रूप में, और shऔर foo; rm -rf $HOMEस्थितीय मानकों (के रूप में से शुरू$0 ), फैलता "$@"करने के लिए foo; rm -rf $HOME किसी एकल मान के रूप में , और रन somethingही तर्क के साथ foo; rm -rf $HOME

आप इसका उपयोग करके देख सकते हैं printf। एक नई निर्देशिका बनाएं, इसे दर्ज करें, और चलाएं

touch "hello; echo pwned"

निम्न प्रकार से पहला संस्करण चलाना

find -exec sh -c "printf \"Argument: %s\n\" {}" \;

पैदा करता है

Argument: .
Argument: ./hello
pwned

जबकि दूसरा संस्करण, के रूप में चलाते हैं

find -exec sh -c 'printf "Argument: %s\n" "$@"' sh {} \;

पैदा करता है

Argument: .
Argument: ./hello; echo pwned

सुरक्षित संस्करण में, क्यों {}नहीं बच गया या उद्धृत किया गया?
टिम

1
यह आमतौर पर उद्धृत करने की आवश्यकता नहीं है; इसे केवल एक शेल में उद्धृत करने की आवश्यकता होगी जहां इसका कुछ अन्य अर्थ है, और मुझे नहीं लगता कि आजकल के किसी भी मुख्य गोले के साथ ऐसा ही है।
स्टीफन किट

से gnu.org/software/findutils/manual/html_mono/... : "इन निर्माणों (दोनों ;और {}।) की जरूरत है (एक '\' के साथ) से बच गया हो या उन्हें खोल द्वारा विस्तार से बचाने के लिए उद्धृत" क्या आपका मतलब है कि यह बैश के लिए गलत है?
टिम

3
मेरा मतलब है कि यह सामान्य रूप से गोले के लिए गलत है। POSIX देखें । में उस विशेष बयान findutilsमैनुअल दिनांकों कम से कम 1996 तक वापस ... बेशक यह बोली के लिए कोई नुकसान करता है {}, या तो के रूप में '{}'या "{}", लेकिन यह आवश्यक नहीं है।
स्टीफन किट

@ समय आप एक सामान्य स्थिति का अनुभव कर रहे हैं, जहां आपका अंतर्ज्ञान इस तथ्य के लिए अभी तक हिसाब नहीं कर रहा है कि दो अलग-अलग प्रकार के तर्क-प्रसंस्करण यहां चल रहे हैं: कब / कैसे शेल पाठ की एक पंक्ति से तर्क देते हैं (जो वह जगह है जहां मामलों को उद्धृत करना) कच्चे ऑपरेटिंग सिस्टम के तर्क से अलग है (जहां उद्धरण सिर्फ नियमित वर्ण हैं)। शेल कमांड में find some/path -exec sh -c 'something "$@"' {} \;वास्तव में तर्क प्रसंस्करण / गुजरने की तीन परतें हैं, शेल किस्म के दो और बुनियादी कच्चे ऑपरेटिंग सिस्टम विविधता में से एक।
22

3

भाग 1:

find बस पाठ प्रतिस्थापन का उपयोग करता है।

हां, यदि आपने इसे अनइंस्टॉल किया, तो इस तरह:

find . -type f -exec sh -c "echo {}" \;

और एक हमलावर नामक एक फ़ाइल बनाने में सक्षम था ; echo owned, फिर यह निष्पादित करेगा

sh -c "echo ; echo owned"

जिसके परिणामस्वरूप echoतब शेल चालू होगा echo owned

लेकिन यदि आपने उद्धरण जोड़े हैं, तो हमलावर आपके उद्धरणों को समाप्त कर सकता है, इसके बाद दुर्भावनापूर्ण कमांड को एक फाइल बनाकर डाल सकता है '; echo owned:

find . -type f -exec sh -c "echo '{}'" \;

जो खोल चल रहा में परिणाम होगा echo '', echo owned

(यदि आपने एकल उद्धरणों के लिए दोहरे उद्धरण चिह्नों की अदला-बदली की है, तो हमलावर अन्य प्रकार के उद्धरणों का भी उपयोग कर सकता है।)


भाग 2:

में find -exec sh -c 'something "$@"' sh {} \;, {}शुरू में खोल से व्याख्या नहीं है, इसके साथ सीधे मार डाला है execve, तो खोल उद्धरण जोड़ने में सहायता नहीं होगा।

find -exec sh -c 'something "$@"' sh "{}" \;

कोई प्रभाव नहीं है, क्योंकि शेल चलने से पहले डबल कोट्स को स्ट्रिप्स करता है find

find -exec sh -c 'something "$@"' sh "'{}'" \;

उद्धरण में कहा गया है कि शेल विशेष रूप से व्यवहार नहीं करता है, इसलिए ज्यादातर मामलों में इसका मतलब है कि कमांड ऐसा नहीं करेगा जो आप चाहते हैं।

यह विस्तार करने के लिए होने /tmp/foo;, rm, -rf, $HOMEएक समस्या नहीं होनी चाहिए, क्योंकि उन लोगों के लिए तर्क हैं something, और somethingशायद आदेश पर अमल करने के लिए के रूप में अपने तर्कों का इलाज नहीं है।


भाग 3:

मुझे लगता है इसी तरह के विचार कुछ भी है कि उदाहरण के लिए अविश्वसनीय इनपुट का उपयोग करके (का हिस्सा) एक आदेश के रूप में यह चलता है, के लिए आवेदन xargsऔर parallel


xargsकेवल खतरनाक है अगर -Iया -Jउपयोग किया जाता है। सामान्य ऑपरेशन में, यह सूची के अंत में केवल तर्क-वितर्क कर रहा है, जैसा कि -exec ... {} +करता है।
चार्ल्स डफी

1
( parallelइसके विपरीत, उपयोगकर्ता से स्पष्ट अनुरोध के बिना डिफ़ॉल्ट रूप से एक शेल चलाता है, कमजोर सतह को बढ़ाता है; यह एक ऐसा मामला है जो बहुत चर्चा का विषय है; एक स्पष्टीकरण के लिए unix.stackexchange.com/questions/349483/… देखें) और सूची में शामिल लिंक । orgu.org/archive/html/bug-parallel/2015-05/msg00005.html )।
चार्ल्स डफी

@CharlesDuffy आपका मतलब है " कमजोर सतह को कम करना"। ओपी द्वारा सचित्र हमला वास्तव में GNU समानांतर के साथ डिफ़ॉल्ट रूप से काम नहीं करता है।
ओले तांगे

1
हाँ, मुझे पता है कि आपको SSH में समानता के लिए इसकी आवश्यकता है - यदि आपने parallelकिसी भी सॉकेट के दूसरे छोर पर एक दूरस्थ "रिसीवर" प्रक्रिया को नहीं चलाया है, जो एक सीधा शेल-कम करने में सक्षम है execv। यदि आपके जूते में उपकरण लागू हो रहा है, तो वास्तव में यही मैंने किया होगा। एक गैर-सक्रिय कार्यक्रम होने पर वर्तमान मूल्य के आधार पर अलग-अलग व्यवहार होता SHELLहै, शायद ही कम से कम-विस्मय हो।
चार्ल्स डफी

1
हां - मैं मानता हूं कि पाइप और पुनर्निर्देशन तब तक असंभव होना चाहिए जब तक उपयोगकर्ता स्पष्ट रूप से एक शेल शुरू नहीं करता है, जिस बिंदु पर उन्हें केवल स्पष्ट रूप से शुरू किए गए शेल का स्पष्ट व्यवहार मिलता है। यदि कोई केवल वही execvप्रदान कर सकता है , जो सरल और कम आश्चर्यजनक है, और ऐसा नियम जो स्थानों / रनटाइम वातावरणों में परिवर्तन नहीं करता है।
चार्ल्स डफी

3

1. क्या इस समस्या का कारण यह है find -exec sh -c "something {}" \;कि प्रतिस्थापन के लिए {}अयोग्य है और इसलिए इसे एक स्ट्रिंग के रूप में नहीं माना जाता है?

एक अर्थ में, लेकिन यहाँ उद्धृत करना मदद नहीं कर सकता । फ़ाइल नाम जो कि प्रतिस्थापित किया {}जा सकता है में उद्धरण सहित कोई भी वर्ण हो सकता है । उद्धरण के किसी भी रूप का उपयोग किया गया था, फ़ाइल नाम में वही हो सकता है, और उद्धरण का "ब्रेक आउट" हो सकता है।

2. "लेकिन चूंकि {}अयोग्य है, "$@"इसलिए मूल कमांड के समान समस्या नहीं है ? उदाहरण के लिए, "$@"इसका विस्तार किया जाएगा "/tmp/foo;", "rm", "-rf", and "$HOME"?

नहीं "$@", अलग-अलग शब्दों के रूप में स्थितीय मापदंडों में फैलता है, और उन्हें आगे विभाजित नहीं करता है । यहाँ, {}अपने आप में एक तर्क findहै, और findवर्तमान फ़ाइल नाम को भी एक अलग तर्क के रूप में पारित करता है sh। यह शेल स्क्रिप्ट में एक चर के रूप में सीधे उपलब्ध है, इसे शेल कमांड के रूप में संसाधित नहीं किया गया है।

... क्यों {}नहीं बच गया या उद्धृत किया गया?

यह ज्यादातर गोले में होने की जरूरत नहीं है। यदि आप दौड़ते हैं fish, तो यह होना चाहिए: fish -c 'echo {}'एक खाली लाइन को प्रिंट करता है। लेकिन इससे कोई फर्क नहीं पड़ता कि आप इसे उद्धृत करते हैं, शेल सिर्फ उद्धरण हटा देगा।

3. क्या आप अन्य उदाहरण दे सकते हैं ...

जब भी आप किसी फ़ाइल नाम (या किसी अन्य अनियंत्रित स्ट्रिंग) का विस्तार करते हैं, जैसा कि एक स्ट्रिंग के अंदर होता है जिसे किसी प्रकार के कोड (*) के रूप में लिया जाता है , तो मनमानी कमांड निष्पादन की संभावना होती है।

उदाहरण के लिए, यह $fसीधे पर्ल कोड का विस्तार करता है, और यदि फ़ाइल नाम में दोहरा उद्धरण होता है, तो यह समस्या पैदा करेगा। फ़ाइल नाम में उद्धरण पर्ल कोड में उद्धरण समाप्त हो जाएगा, और बाकी फ़ाइल नाम में कोई भी पर्ल कोड शामिल हो सकता है:

touch '"; print "HELLO";"'
for f in ./*; do
    perl -le "print \"size: \" . -s \"$f\""
done

(फ़ाइल नाम थोड़ा अजीब है क्योंकि पर्ल किसी भी चलाने से पहले पूरे कोड को आगे बढ़ाता है। इसलिए हमें एक पार्स त्रुटि से बचना होगा।)

हालांकि यह एक तर्क के माध्यम से इसे सुरक्षित रूप से पारित करता है:

for f in ./*; do
    perl -le 'print "size: " . -s $ARGV[0]' "$f"
done

(यह एक शेल से सीधे दूसरे शेल को चलाने के लिए समझ में नहीं आता है, लेकिन यदि आप ऐसा करते हैं, तो यह find -exec sh ...मामले के समान है )

(* कुछ प्रकार के कोड में SQL शामिल है, इसलिए अनिवार्य XKCD: https://xkcd.com/327/ plus स्पष्टीकरण: https://www.explainxkcd.com/wiki/index.php/Little_Bobby_Tables )


1

आपकी चिंता ठीक यही कारण है कि GNU समानांतर उद्धरण इनपुट:

touch "hello; echo pwned"
find . -print0 | parallel -0 printf \"Argument: %s\\n\" {}

यह नहीं चलेगा echo pwned

यह एक शेल चलाएगा, ताकि यदि आप अपनी कमांड का विस्तार करते हैं, तो आपको अचानक आश्चर्य नहीं मिलेगा:

# This _could_ be run without spawining a shell
parallel "grep -E 'a|bc' {}" ::: foo
# This cannot
parallel "grep -E 'a|bc' {} | wc" ::: foo

स्पॉनिंग-ए-शेल मुद्दे पर अधिक जानकारी के लिए देखें: https://www.gnu.org/software/parallel/parallel_design.html#Always-running-commands-in-a-shell


1
... यह कहा, find . -print0 | xargs -0 printf "Argument: %s\n"बस के रूप में सुरक्षित है (या बल्कि, Moreso, -print0एक के बाद से सही ढंग से newlines के साथ filenames संभालती है); समानांतर का हवाला एक समस्या के लिए एक समाधान है जो किसी भी समय मौजूद नहीं है
चार्ल्स डफी

लेकिन जैसे ही आप | wcकमांड में जोड़ते हैं, आपको इसे सुरक्षित बनाने के लिए हुप्स के माध्यम से कूदने की आवश्यकता होती है। जीएनयू समानांतर डिफ़ॉल्ट रूप से सुरक्षित है।
ओले तांगे

ITYM: यह हर चीज को ध्यान से उद्धृत करने की जटिल प्रक्रिया द्वारा शेल भाषा के हर क्विकर के लिए कवर करने की कोशिश करता है। यह लगभग उतना ही सुरक्षित नहीं है जितना कि डेटा को वेरिएबल्स में स्टोर करना, कोड के साथ इंटरमिक्स नहीं किया गया है। अब, अगर यह स्वतः ही sh {} ` foo {} | wcमें परिवर्तित sh -c 'foo "$1" | wcहो जाए , तो यह अलग हो सकता है।
इलकाचू १०'१ach
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.