Cả hai system()
và 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
system()
và 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()
và 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).
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.
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
@ 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). –
@ 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
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.
- 1. Clojure: * out * vs System/out
- 2. NUnit vs Team System Unit Test
- 3. execve ("/ bin/sh", 0, 0); trong một ống
- 4. Tích hợp liên tục - với những gì để bắt đầu: CruiseControl.NET vs TeamCity vs Visual Studio Team System
- 5. Photoshop Undo System
- 6. system() với powershell trong vim
- 7. Các vấn đề trong Haskell's Type-System
- 8. Sự khác biệt giữa system() và shell()
- 9. Tai nạn gốc trong /system/lib/libart.so
- 10. Núi NoSQL DB như File System
- 11. ứng dụng JavaFX trong System Tray
- 12. Apple System Log time theo mili giây?
- 13. Góc-CLI: ở đâu là system-config.js
- 14. Wordpress Digg-Like Voting System Plugin
- 15. Chụp stdout từ lệnh system() tối ưu
- 16. convert System :: array thành std :: vector
- 17. Android Oreo Notification Crashes System UI
- 18. Tại sao đầu tiên arg để execve() phải là đường dẫn đến thực thi
- 19. subprocess.Popen execve() arg 3 chứa giá trị không phải là chuỗi
- 20. Visual Studio 2008 có thể hoạt động với Team System 2005 không?
- 21. Đối diện với Oracle "ALTER SYSTEM SET" Lệnh
- 22. Tại sao là $? luôn 0 sau khi system() được gọi?
- 23. RuntimeType: http: //schemas.datacontract.org/2004/07/System 'không được mong đợi
- 24. Không xác định tham chiếu đến 'boost :: system :: generic_category()'?
- 25. Android Emulator: qemu-system-i386.exe: goldfish_battery_read: Xấu bù đắp
- 26. Gradle Android Build System Các vấn đề NDK
- 27. Ẩn bàn điều khiển trong chức năng C system(), Win
- 28. .Net WinForm System Beep trên hệ điều hành 64 bit
- 29. ghi vào/system/framework trong trình giả lập
- 30. Rails 3 A/B Split Test System Không có Redis?
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
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