2011-12-14 14 views
10

tôi có chương trình ví dụ sau:execve ("/ bin/sh", 0, 0); trong một ống

#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); 
} 

tôi và khi tôi chạy mà không có bất kỳ ống nó hoạt động như mong muốn và trả về một sh Promt:

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

Nhưng điều này không làm việc trong một đường ống, tôi nghĩ rằng tôi biết tại sao đó là, nhưng tôi không thể tìm ra một giải pháp. Ví dụ chạy dưới đây.

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

tôi con số này có cái gì để làm với thực tế rằng gets đổ stdin theo cách như vậy mà /bin/sh nhận EOF và promtly bỏ mà không có một thông báo lỗi.

Nhưng làm cách nào để tránh được điều này (mà không sửa đổi chương trình, nếu có thể và không xóa gets, nếu không) để tôi nhận được lời hứa ngay cả khi tôi cung cấp đầu vào thông qua đường ống?

P.S. Tôi đang chạy trên một máy FreeBSD (4.8) DS

+6

*** KHÔNG BAO GIỜ *** sử dụng 'get'. Nó ** luôn luôn ** mở một lỗ hổng bảo mật tràn bộ đệm. – ThiefMaster

+5

Tôi biết;) ...đây là một phần của nỗ lực tràn bộ đệm trên máy tính tại phòng thí nghiệm bảo mật tại trường đại học của tôi. Hoàn toàn học tập. = D –

Trả lời

10

Bạn có thể chạy chương trình của bạn mà không cần bất kỳ sửa đổi như sau:

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

Bằng cách này bạn đảm bảo rằng đầu vào tiêu chuẩn của chương trình của bạn không kết thúc sau những gì echo đầu ra. Thay vào đó, cat tiếp tục cung cấp đầu vào cho chương trình của bạn. Nguồn của đầu vào tiếp theo đó là thiết bị đầu cuối của bạn vì đây là nơi mà cat đọc từ đó.

Dưới đây là một phiên dụ:

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$ 

Lưu ý rằng vì đầu vào tiêu chuẩn vỏ của không kết nối với một thiết bị đầu cuối, sh nghĩ rằng nó không được thực hiện một cách tương tác và do đó không hiển thị dấu nhắc. Bạn có thể gõ lệnh của bạn bình thường, mặc dù.

+0

Ah .. vâng bạn là chính xác, (Tôi thực sự quản lý để tìm giải pháp này trước khi nhìn thấy bài viết của bạn, nhưng cảm ơn bạn đã đưa nó lên đây). –

1

Không chắc chắn 100% điều này (vỏ chính xác đang được sử dụng và hệ điều hành có thể ném các câu trả lời này một chút), tôi tin rằng FreeBSD sử dụng GNU bash theo mặc định là /bin/sh?), nhưng

  • sh có thể phát hiện thấy đầu vào của nó không phải là một tty.

hoặc

  • Phiên bản của bạn sh có thể đi vào chế độ không tương tác như thế còn nếu gọi là sh, mong login sẽ thêm vào trước một - vào argv[0] cho nó. Thiết lập execve ("/bin/sh", { "-sh", NULL}, NULL) có thể thuyết phục rằng nó đang được chạy dưới dạng một vỏ đăng nhập.
3

Sử dụng execve("/bin/sh", 0, 0); là hình phạt độc ác và bất thường cho vỏ. Nó cung cấp cho nó không có đối số hoặc môi trường nào cả - thậm chí không phải tên chương trình riêng của nó, thậm chí cả các biến môi trường bắt buộc như PATH hoặc HOME.

+2

well ... yeah Tôi đồng ý hoàn toàn, nhưng điều này chỉ đơn giản được sử dụng như một thử nghiệm. Tôi sẽ không bao giờ sử dụng điều này trong bất cứ điều gì tương tự như một chương trình có thể sử dụng. –