Linux bỏ qua bit setuid¹ trên tất cả các tệp thực thi được giải thích (nghĩa là các tệp thực thi bắt đầu bằng một #!
dòng). Câu hỏi thường gặp comp.unix.questions giải thích các vấn đề bảo mật với tập lệnh shell setuid. Những vấn đề này có hai loại: liên quan đến shebang và liên quan đến vỏ; Tôi đi vào chi tiết hơn dưới đây.
Nếu bạn không quan tâm đến bảo mật và muốn cho phép các tập lệnh setuid, trong Linux, bạn sẽ cần vá kernel. Kể từ hạt nhân 3.x, tôi nghĩ bạn cần thêm một cuộc gọi install_exec_creds
vào load_script
chức năng, trước khi gọi đến open_exec
, nhưng tôi chưa thử nghiệm.
Setuid shebang
Có một điều kiện chủng tộc vốn có theo cách shebang ( #!
) thường được thực hiện:
- Nhân mở tệp thực thi và thấy rằng nó bắt đầu bằng
#!
.
- Hạt nhân đóng thực thi và thay vào đó mở trình thông dịch.
- Hạt nhân chèn đường dẫn đến tập lệnh vào danh sách đối số (as
argv[1]
) và thực thi trình thông dịch.
Nếu tập lệnh setuid được cho phép với triển khai này, kẻ tấn công có thể gọi một tập lệnh tùy ý bằng cách tạo một liên kết tượng trưng đến tập lệnh setuid hiện có, thực thi nó và sắp xếp để thay đổi liên kết sau khi kernel đã thực hiện bước 1 và trước khi trình thông dịch chuyển sang mở đối số đầu tiên của nó. Vì lý do này, hầu hết các thông báo bỏ qua bit setuid khi họ phát hiện ra một shebang.
Một cách để bảo mật việc triển khai này là cho kernel khóa tệp script cho đến khi trình thông dịch đã mở nó (lưu ý rằng điều này phải ngăn chặn không chỉ hủy liên kết hoặc ghi đè tệp, mà còn đổi tên bất kỳ thư mục nào trong đường dẫn). Nhưng các hệ thống unix có xu hướng né tránh các khóa bắt buộc và các liên kết tượng trưng sẽ làm cho một tính năng khóa chính xác đặc biệt khó khăn và xâm lấn. Tôi không nghĩ có ai làm theo cách này.
Một vài hệ thống unix (chủ yếu là OpenBSD, NetBSD và Mac OS X, tất cả đều yêu cầu cài đặt kernel) để triển khai setuid shebang an toàn bằng cách sử dụng một tính năng bổ sung: đường dẫn đề cập đến tệp đã được mở trên bộ mô tả tệp N (vì vậy mở là gần tương đương với ). Nhiều hệ thống unix (bao gồm cả Linux) có nhưng không có tập lệnh setuid./dev/fd/N
/dev/fd/N
dup(N)
/dev/fd
- Nhân mở tệp thực thi và thấy rằng nó bắt đầu bằng
#!
. Giả sử mô tả tệp cho tệp thực thi là 3.
- Nhân mở trình thông dịch.
- Nhân chèn
/dev/fd/3
danh sách đối số (dưới dạng argv[1]
) và thực thi trình thông dịch.
Trang shebang của Sven Mascheck có rất nhiều thông tin về shebang trên các đơn vị, bao gồm hỗ trợ setuid .
Thông dịch viên Setuid
Giả sử bạn đã quản lý để làm cho chương trình của bạn chạy bằng root, vì hệ điều hành của bạn hỗ trợ setuid shebang hoặc vì bạn đã sử dụng trình bao bọc nhị phân gốc (chẳng hạn như sudo
). Bạn đã mở một lỗ hổng bảo mật? Có lẽ . Vấn đề ở đây không phải là về diễn giải so với các chương trình được biên dịch. Vấn đề là hệ thống thời gian chạy của bạn có hoạt động an toàn hay không nếu được thực thi với các đặc quyền.
Bất kỳ thực thi nhị phân gốc được liên kết động nào theo cách được giải thích bởi trình tải động (ví dụ /lib/ld.so
), tải các thư viện động theo yêu cầu của chương trình. Trên nhiều thông báo, bạn có thể định cấu hình đường dẫn tìm kiếm cho các thư viện động thông qua môi trường ( LD_LIBRARY_PATH
là tên chung cho biến môi trường) và thậm chí tải các thư viện bổ sung vào tất cả các nhị phân đã thực hiện ( LD_PRELOAD
). Các Invoker của chương trình có thể thực thi mã tùy ý trong bối cảnh của chương trình bằng cách đặt một đặc biệt crafted libc.so
trong $LD_LIBRARY_PATH
(giữa chiến thuật khác). Tất cả các hệ thống lành mạnh bỏ qua các LD_*
biến trong thực thi setuid.
Trong các shell như sh, csh và các dẫn xuất, các biến môi trường sẽ tự động trở thành các tham số shell. Thông qua các thông số như PATH
, IFS
, và nhiều hơn nữa, các Invoker của kịch bản có nhiều cơ hội để thực thi mã tùy ý trong bối cảnh các kịch bản shell của. Một số shell đặt các biến này thành mặc định lành mạnh nếu chúng phát hiện ra rằng tập lệnh đã được gọi với các đặc quyền, nhưng tôi không biết rằng có bất kỳ triển khai cụ thể nào mà tôi sẽ tin tưởng.
Hầu hết các môi trường thời gian chạy (cho dù là bản địa, mã byte hoặc giải thích) có các tính năng tương tự. Rất ít người thực hiện các biện pháp phòng ngừa đặc biệt trong các tệp thực thi setuid, mặc dù các mã chạy mã gốc thường không làm gì lạ hơn liên kết động (điều này có các biện pháp phòng ngừa).
Perl là một ngoại lệ đáng chú ý. Nó rõ ràng hỗ trợ các tập lệnh setuid một cách an toàn. Trong thực tế, tập lệnh của bạn có thể chạy setuid ngay cả khi hệ điều hành của bạn bỏ qua bit setuid trên tập lệnh. Điều này là do các tàu perl có trình trợ giúp gốc setuid thực hiện các kiểm tra cần thiết và khôi phục trình thông dịch trên các tập lệnh mong muốn với các đặc quyền mong muốn. Điều này được giải thích trong hướng dẫn perlsec . Nó đã từng là các tập lệnh peru setuid cần thiết #!/usr/bin/suidperl -wT
thay vì #!/usr/bin/perl -wT
, nhưng trên hầu hết các hệ thống hiện đại, #!/usr/bin/perl -wT
là đủ.
Lưu ý rằng việc sử dụng trình bao bọc nhị phân riêng không làm gì để ngăn chặn những vấn đề này . Trong thực tế, nó có thể làm cho tình hình tồi tệ hơn , bởi vì nó có thể ngăn môi trường thời gian chạy của bạn phát hiện ra rằng nó được gọi với các đặc quyền và bỏ qua cấu hình thời gian chạy của nó.
Trình bao bọc nhị phân riêng có thể làm cho tập lệnh shell an toàn nếu trình bao bọc vệ sinh môi trường . Kịch bản phải lưu ý không đưa ra quá nhiều giả định (ví dụ về thư mục hiện tại) nhưng điều này sẽ đi. Bạn có thể sử dụng sudo cho điều này với điều kiện là nó được thiết lập để vệ sinh môi trường. Các biến trong danh sách đen dễ bị lỗi, vì vậy luôn có danh sách trắng. Với sudo, đảm bảo rằng env_reset
tùy chọn được bật, setenv
tắt và điều đó env_file
và env_keep
chỉ chứa các biến vô hại.
TL, DR:
- Setuid shebang không an toàn nhưng thường bị bỏ qua.
- Nếu bạn chạy một chương trình với các đặc quyền (thông qua sudo hoặc setuid), hãy viết mã gốc hoặc perl hoặc khởi động chương trình với một trình bao bọc vệ sinh môi trường (chẳng hạn như sudo với
env_reset
tùy chọn).
¹ Thảo luận này áp dụng như nhau nếu bạn thay thế “setgid” cho “setuid”; cả hai đều bị bỏ qua bởi nhân Linux trên các tập lệnh