2011-12-14 16 views
10

मैं निम्न उदाहरण कार्यक्रम है:निष्पादित करें ("/ bin/sh", 0, 0); एक पाइप में

#include <stdio.h> 

int 
main(int argc, char ** argv){ 
    char buf[100]; 

    printf("Please enter your name: "); 
    fflush(stdout); 
    gets(buf); 
    printf("Hello \"%s\"\n", buf); 

    execve("/bin/sh", 0, 0); 
} 

मैं और जब मैं किसी भी पाइप यह एकदम सही ढंग से काम करता है बिना चलने के लिए देता है एक sh शीघ्र:

bash$ ./a.out 
Please enter your name: warning: this program uses gets() which is unsafe. 
testName 
Hello "testName" 
$ exit 
bash$ 

लेकिन यह काम नहीं करता एक पाइप में, मुझे लगता है कि मुझे पता है कि ऐसा क्यों है, लेकिन मैं समाधान का पता नहीं लगा सकता। उदाहरण भागो।

bash$ echo -e "testName\npwd" | ./a.out 
Please enter your name: warning: this program uses gets() which is unsafe. 
Hello "testName" 
bash$ 

मैं समझ इस तथ्य यह है कि gets इस तरह से कि /bin/sh एक EOF प्राप्त करता है और promtly एक त्रुटि संदेश के बिना इस्तीफा में stdin खाली के साथ कुछ है।

लेकिन मैं इस बारे में कैसे प्राप्त करूं (यदि संभव हो तो कार्यक्रम को संशोधित किए बिना, और gets को हटा नहीं रहा है), ताकि मुझे एक पाइप के माध्यम से इनपुट की आपूर्ति करने के बावजूद एक प्रोमेट मिल जाए?

पीएस मैं एक FreeBSD (4.8) मशीन डी एस

+6

*** कभी नहीं *** 'प्राप्त' का उपयोग करें। यह ** हमेशा ** एक बफर ओवरफ्लो सुरक्षा छेद खोलता है। – ThiefMaster

+5

मुझे पता है;) ...यह मेरे विश्वविद्यालय में सुरक्षा प्रयोगशाला में एक कंप्यूटर पर एक बफर ओवरफ्लो प्रयास का हिस्सा है। शुद्ध रूप से अकादमिक। = डी –

उत्तर

10

आप इस तरह किसी भी संशोधन के बिना अपने कार्यक्रम चला सकते हैं:

(echo -e 'testName\n'; cat) | ./a.out 

इस तरह आप सुनिश्चित करें कि आपके कार्यक्रम के मानक इनपुट क्या echo आउटपुट के बाद खत्म नहीं होता। इसके बजाय, cat आपके कार्यक्रम में इनपुट की आपूर्ति जारी रखता है। उस बाद के इनपुट का स्रोत आपका टर्मिनल है क्योंकि यह cat से पढ़ता है।

यहाँ एक उदाहरण सत्र है: क्योंकि खोल के मानक इनपुट एक टर्मिनल से जुड़ा नहीं है, sh सोचता

bash-3.2$ cc stdin_shell.c 
bash-3.2$ (echo -e 'testName\n'; cat) | ./a.out 
Please enter your name: warning: this program uses gets(), which is unsafe. 
Hello "testName" 
pwd 
/home/user/stackoverflow/stdin_shell_question 
ls -l 
total 32 
-rwxr-xr-x 1 user group 9024 Dec 14 18:53 a.out 
-rw-r--r-- 1 user group 216 Dec 14 18:52 stdin_shell.c 
ps -p $$ 
    PID TTY   TIME CMD 
93759 ttys000 0:00.01 (sh) 
exit 

bash-3.2$ 

ध्यान दें कि यह सहभागी निष्पादित नहीं है और इसलिए शीघ्र प्रदर्शित नहीं करता है। हालांकि, आप सामान्य रूप से अपने आदेश टाइप कर सकते हैं।

+0

आह .. हाँ आप सही हैं, (मैं वास्तव में आपकी पोस्ट को देखने से पहले इस समाधान को ढूंढने में कामयाब रहा, लेकिन इसे यहां रखने के लिए धन्यवाद)। –

1

नहीं 100% यह (सटीक खोल के बारे में सुनिश्चित पर इस चला रहा हूँ इस्तेमाल किया जा रहा है और ओएस इन उत्तरों थोड़ा फेंक सकता है, मुझे विश्वास है कि FreeBSD /bin/sh के रूप में जीएनयू bash का उपयोग करता डिफ़ॉल्ट रूप से?), लेकिन

  • sh यह पता लगा रहा है कि इसका इनपुट एक tty नहीं है।

या

  • sh का संस्करण है कि जैसे गैर-सहभागी मोड में जाने सकता है भी अगर sh के रूप में कहा जाता है, की उम्मीद कर login इसके लिए एक -argv[0] पर पहले जोड़ें होगा। execve ("/bin/sh", { "-sh", NULL}, NULL) सेट अप करने से यह विश्वास हो सकता है कि इसे लॉगिन खोल के रूप में चलाया जा रहा है।
3

execve("/bin/sh", 0, 0); का उपयोग करना खोल के लिए क्रूर और असामान्य सजा है। यह इसे कोई तर्क या पर्यावरण नहीं देता है - यहां तक ​​कि अपने स्वयं के प्रोग्राम का नाम भी नहीं, न ही पैत या घर के रूप में ऐसे अनिवार्य पर्यावरण चर।

+2

अच्छी तरह से ... हाँ मैं पूरी तरह से सहमत हूं, लेकिन यह बस एक प्रयोग के रूप में प्रयोग किया जाता है। मैं इसे किसी प्रयोग योग्य कार्यक्रम के समान कुछ भी नहीं उपयोग करूंगा। –