2014-12-12 21 views
8

Cả hai system()execve() có thể được sử dụng để thực thi lệnh khác bên trong chương trình. Tại sao trong các chương trình set-UID, system() là nguy hiểm, trong khi execve() là an toàn?system() vs execve()

Trả lời

9

system()execve() hoạt động theo nhiều cách khác nhau. system() sẽ luôn gọi trình bao và trình bao này sẽ thực hiện lệnh dưới dạng một quy trình riêng biệt (đây là lý do tại sao bạn có thể sử dụng ký tự đại diện và các tiện ích vỏ khác trong dòng lệnh khi sử dụng system()).

execve() (và các chức năng khác trong họ exec()) thay thế quy trình hiện tại bằng tiến trình được sinh ra trực tiếp (chức năng execve() không trả về, trừ trường hợp không thành công). Thực tế, việc triển khai thực hiện system() phải sử dụng một chuỗi các cuộc gọi fork(), execve()wait() để thực hiện chức năng của nó.

Tất nhiên cả hai đều nguy hiểm tùy thuộc vào những gì đang được thực hiện khi quy trình có quyền ưu tiên gốc. Tuy nhiên, system() mang lại một số nguy hiểm do lớp vỏ bổ sung nó sử dụng để mở các lỗ hổng bảo mật phòng khi nó gọi vỏ gốc như trong trường hợp câu hỏi của bạn (tức là quá trình có bit suid).

+0

Vì vậy, khi sử dụng execve() .. bạn đề cập đến nó thay thế quá trình hiện tại .. liệu quá trình này có còn được thiết lập không? – Jake

+0

Có.Quá trình "mới" được khởi tạo bằng cách thực thi kế thừa một số thuộc tính của một thay thế, như các trình mô tả, ổ cắm, v.v. và uid hiệu quả là một trong số chúng, nhưng có những tình huống mà uid thay đổi trong quá trình thực thi, như nếu tập tin thực thi được chỉ ra bởi tham số thực hiện có tập bit suid. Trong trường hợp này, uid được thay đổi thành chủ sở hữu tệp vì nó được xác định trong hệ thống tệp. – Marcelo

12

system sẽ gọi trình bao (sh) để thực thi lệnh được gửi dưới dạng đối số. Vấn đề với system vì hành vi vỏ phụ thuộc vào người dùng chạy lệnh. Một ví dụ nhỏ:

Tạo một file test.c:

#include <stdio.h> 

int main(void) { 
    if (system ("ls") != 0) 
     printf("Error!"); 
    return 0; 
} 

Sau đó:

$ gcc test.c -o test 

$ sudo chown root:root test 

$ sudo chmod +s test 

$ ls -l test 
-rwsr-sr-x 1 root root 6900 Dec 12 17:53 test 

Tạo một kịch bản gọi là ls trong thư mục hiện tại của bạn:

$ cat > ls 
#!/bin/sh 

/bin/sh 

$ chmod +x ls 

Bây giờ là:

$ PATH=. ./test 
# /usr/bin/id 
uid=1000(cuonglm) gid=1000(cuonglm) euid=0(root) egid=0(root) groups=0(root), 
24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),105(scanner), 
110(bluetooth),111(netdev),999(docker),1000(cuonglm) 
# /usr/bin/whoami 
root 

Rất tiếc, bạn có một trình bao có đặc quyền gốc.

execve không gọi là trình bao. Nó thực thi chương trình được truyền cho nó như là đối số đầu tiên. Chương trình phải là tệp thực thi nhị phân hoặc tập lệnh bắt đầu bằng dòng shebang.

+0

Không nói 'system()' là không có vấn đề nhưng sẽ không ở trên được giải quyết bằng cách sử dụng đường dẫn tuyệt đối trong thực thi nhị phân? – Bratchley

+1

@ JoelDavis, không, bạn cần ít nhất là để xóa toàn bộ môi trường, cung cấp các giá trị mặc định sane cho một vài envvars (PATH, HOME ...), nếu cần bảo quản một số env vars sau khi khử trùng (TERM, DISPLAY, LANG. ..) đảm bảo fds 0, 1, 2 đang mở ... Về cơ bản, hãy làm gì sudo. Thậm chí sau đó, tôi sẽ không đến đó. Đừng gọi một shell trong bối cảnh leo thang đặc quyền nếu có thể tránh được. Lưu ý rằng 'ls' có thể làm những điều kỳ lạ với môi trường của nó, vì vậy ngay cả khi không có' system() ', bạn có lẽ nên khử trùng môi trường. Khi sử dụng setuids bạn muốn giảm thiểu những gì được thực hiện như là root (thường không thực hiện các lệnh). –

+3

@ JoelDavis: Không, bạn vẫn gặp sự cố, ngay cả khi bạn sử dụng đường dẫn đầy đủ. Nếu bạn sử dụng '/ bin/ls', người dùng có thể thêm'/'vào' $ IFS', làm cho trình bao chia '/ bin/ls' thành' bin' và 'ls'. Bây giờ, một thực thi được gọi là 'bin' trong thư mục hiện tại có thể làm điều tương tự như' ls' trong câu trả lời của tôi. – cuonglm

0

Ngoài các vấn đề bảo mật được đo lường với system(), quá trình sinh sản thừa hưởng môi trường của chương trình chính. Điều này có thể rất khó khi sử dụng suid, ví dụ: khi quá trình gọi đặt số LD_LIBRARY_PATH biến môi trường.

Với exec() -gia đình, chương trình gọi có thể đặt môi trường chính xác những gì cần thiết (và an toàn) cho chương trình được gọi trước khi gọi exec().

Và dĩ nhiên, vỏ được gọi là system() có thể có vấn đề về bảo mật.

Các vấn đề liên quan