SUID vs. Linux Capabilities: Hai Hướng Tiếp Cận Hoàn Toàn Khác Nhau về Đặc Quyền
Nếu bạn đã quản lý server Linux một thời gian, chắc chắn bạn đã gặp các binary SUID — những file có bit s đặc biệt cho phép tiến trình chạy với quyền của chủ sở hữu file thay vì người gọi. Ví dụ điển hình: ping, passwd, sudo. Chúng hoạt động được, nhưng đi kèm một vấn đề càng suy nghĩ càng khó bỏ qua.
SUID là tất cả hoặc không có gì. Khi ping chạy với quyền root, nó nhận được toàn bộ đặc quyền root — truy cập filesystem, kiểm soát tiến trình, cấu hình mạng, tất cả mọi thứ — dù thực tế nó chỉ cần quyền mở một raw socket. Đó là bề mặt tấn công khổng lồ cho một công cụ chẩn đoán đơn thuần.
Capabilities ra đời để giải quyết đúng vấn đề này. Thay vì cấp toàn bộ đặc quyền root, bạn chia nhỏ những đặc quyền đó thành các đơn vị riêng biệt và chỉ gán những gì tiến trình thực sự cần. ping cần CAP_NET_RAW. Không gì thêm. Không cần SUID.
Các bản phân phối Ubuntu và Debian hiện đại đã ship ping theo cách này. Chạy lệnh này và bạn sẽ thấy:
getcap /usr/bin/ping
# Kết quả: /usr/bin/ping cap_net_raw=ep
Không có bit SUID. Chỉ duy nhất một capability nó cần. Đó là toàn bộ ý tưởng.
Ưu và Nhược Điểm: Capabilities vs. SUID
SUID — kẻ quen thuộc nhưng nhiều rủi ro
Ưu điểm:
- Cực kỳ đơn giản để thiết lập:
chmod u+s /path/to/binary - Được hỗ trợ trên mọi phiên bản Linux
- Không cần kernel module hay feature flag
- Hoạt động trong suốt — binary không cần biết về nó
Nhược điểm:
- Binary nhận toàn bộ đặc quyền UID 0 — nhiều hơn nhiều so với nhu cầu thực tế
- Bất kỳ lỗ hổng nào trong binary đó đều dẫn đến leo thang đặc quyền root hoàn toàn
- Khó kiểm tra:
find / -perm -4000cho ra danh sách nhưng không có ngữ cảnh về lý do - Áp dụng cho mọi người dùng có thể thực thi file — không có kiểm soát theo từng người dùng
Linux Capabilities — cách tiếp cận phẫu thuật chính xác
Ưu điểm:
- Nguyên tắc đặc quyền tối thiểu: chỉ cấp những gì cần thiết
- Nếu binary bị khai thác, kẻ tấn công chỉ nhận được các capability cụ thể đó — không phải root toàn diện
- Có thể kiểm tra với
getcap -r /— hiển thị chính xác những capability nào tồn tại và ở đâu - Chi tiết đến từng binary, hỗ trợ quản lý capability ở cấp thread trong code
- Tương thích với các framework bảo mật như AppArmor và SELinux
Nhược điểm:
- Không phải phần mềm nào cũng hiểu hoặc yêu cầu capabilities — các công cụ cũ có thể vẫn cần SUID
- Các cờ capability (
e,p,i) có đường cong học tập nhất định - Capabilities trên file được lưu trong extended attributes — một số filesystem hoặc công cụ backup có thể xóa chúng
- Các ngôn ngữ scripting (Python, Perl) không tự kế thừa file capabilities — cần binary wrapper
Khuyến Nghị: Khi Nào Dùng Gì
Đây là cách tôi suy nghĩ về vấn đề này trên các hệ thống production:
- Dùng capabilities cho các binary đã biên dịch cần một đặc quyền cụ thể: công cụ mạng (
tcpdump,ping), daemon đồng bộ thời gian, agent bắt gói tin - Giữ SUID cho các công cụ hệ thống mà mô hình đặc quyền đầy đủ là có chủ đích và đã được kiểm tra kỹ:
sudo,su,passwd— những công cụ này được thiết kế xoay quanh quyền root - Tránh hoàn toàn SUID cho bất cứ thứ gì bạn tự biên dịch hoặc công cụ bên thứ ba bạn đang triển khai — hãy dùng capabilities hoặc chạy với người dùng chuyên dụng ít đặc quyền cùng capabilities tối thiểu cần thiết
- Chạy service với người dùng chuyên dụng kết hợp capabilities — đây là mô hình sạch nhất cho các daemon
Ví dụ thực tế từ server Ubuntu 22.04 của tôi: tôi có một công cụ phân tích gói tin tùy chỉnh đang chạy với quyền root qua SUID wrapper. Chuyển sang người dùng hệ thống netmon chuyên dụng với chỉ CAP_NET_RAW và CAP_NET_ADMIN trên binary chỉ mất khoảng mười phút. Hành vi giống hệt. Bề mặt tấn công thu hẹp đáng kể. Đó là loại chiến thắng nhanh khiến việc hardening bớt cảm giác nhàm chán.
Hướng Dẫn Triển Khai
Cài đặt công cụ
Trên Debian/Ubuntu:
sudo apt install libcap2-bin
Trên RHEL/CentOS/AlmaLinux:
sudo dnf install libcap
Lệnh này cài cho bạn getcap, setcap, và capsh.
Hiểu các cờ capability
Khi bạn thấy kết quả như cap_net_raw=ep, các chữ cái sau = là các tập capability:
e— Effective (Hiệu lực): capability đang hoạt động ngay bây giờp— Permitted (Được phép): capability có thể được kích hoạti— Inheritable (Kế thừa): được truyền cho tiến trình con
Với hầu hết trường hợp, =ep là thứ bạn muốn — capability vừa được phép vừa có hiệu lực khi binary chạy.
Kiểm tra capabilities hiện có
# Kiểm tra một file cụ thể
getcap /usr/bin/ping
# Kiểm tra toàn bộ filesystem (chạy với quyền root)
getcap -r / 2>/dev/null
Lệnh quét đệ quy đó là thứ tôi chạy hàng quý trên server production. Đây là bước kiểm tra nhanh — nếu có gì đó xuất hiện mà bạn không thiết lập, đó là điều đáng điều tra.
Gán capabilities cho binary
Giả sử bạn có công cụ tùy chỉnh /usr/local/bin/netmon cần quyền truy cập raw socket:
# Cấp CAP_NET_RAW (quyền truy cập raw socket)
sudo setcap cap_net_raw=ep /usr/local/bin/netmon
# Xác minh
getcap /usr/local/bin/netmon
# Kết quả: /usr/local/bin/netmon cap_net_raw=ep
Cho công cụ bắt gói tin cũng cần thiết lập chế độ interface:
sudo setcap cap_net_raw,cap_net_admin=ep /usr/local/bin/netmon
Xóa capabilities
# Xóa tất cả capabilities khỏi binary
sudo setcap -r /usr/local/bin/netmon
# Xác minh đã sạch
getcap /usr/local/bin/netmon
# (không có kết quả = không có capabilities)
Thay thế SUID binary hiện có bằng capabilities
Ví dụ cụ thể: gỡ SUID khỏi tcpdump và chuyển sang dùng capabilities.
# Kiểm tra trạng thái hiện tại
ls -la /usr/bin/tcpdump
# -rwxr-sr-x hoặc -rwsr-xr-x tùy distro
# Xóa bit SUID
sudo chmod u-s /usr/bin/tcpdump
# Chỉ cấp những gì nó cần
sudo setcap cap_net_raw,cap_net_admin=ep /usr/bin/tcpdump
# Kiểm tra với người dùng thường
tcpdump -i eth0 -c 5
Capabilities cho service chạy với người dùng không phải root
Mô hình tôi hay dùng nhất: tạo người dùng chuyên dụng, gán capabilities cho binary, xong.
# Tạo người dùng hệ thống (không có login shell, không có thư mục home)
sudo useradd -r -s /usr/sbin/nologin netmon
# Gán capabilities cho binary
sudo setcap cap_net_raw=ep /usr/local/bin/netmon
# Chạy service với người dùng đó (trong systemd unit)
# [Service]
# User=netmon
# ExecStart=/usr/local/bin/netmon
# Xác minh tiến trình có đúng capabilities khi chạy
cat /proc/$(pgrep netmon)/status | grep Cap
Kết quả từ /proc/PID/status hiển thị bitmask capability. Để giải mã chúng:
capsh --decode=0000000000002000
# 0x0000000000002000=cap_net_raw
Tham chiếu các capability thông dụng
cap_net_raw— Raw socket và packet socket (ping, tcpdump)cap_net_admin— Cấu hình network interface, routing, iptablescap_net_bind_service— Bind vào cổng dưới 1024 mà không cần rootcap_sys_time— Đặt đồng hồ hệ thống (ntpd, chrony)cap_dac_override— Bỏ qua kiểm tra quyền đọc/ghi filecap_setuid/cap_setgid— Thay đổi UID/GID của tiến trìnhcap_sys_ptrace— Trace tiến trình tùy ý (debugger, strace)
Danh sách đầy đủ: man 7 capabilities
Lưu ý quan trọng: capabilities và script
Gán capabilities cho script Python hay Bash sẽ không hoạt động — kernel chỉ áp dụng file capabilities cho binary ELF, không phải script thông dịch. Có hai lựa chọn: viết một C wrapper nhỏ, hoặc dùng ambient capabilities qua directive AmbientCapabilities= của systemd trong unit file:
[Service]
User=netmon
AmbientCapabilities=CAP_NET_RAW
CapabilityBoundingSet=CAP_NET_RAW
ExecStart=/usr/bin/python3 /opt/netmon/monitor.py
Đây là cách tiếp cận sạch nhất cho service Python cần một capability duy nhất — không SUID, không chạy với quyền root.
Script kiểm tra nhanh
Thêm script này vào bộ công cụ của bạn — nó hiển thị cả SUID binary lẫn file có capabilities cạnh nhau:
#!/bin/bash
echo "=== Các Binary SUID ==="
find / -perm -4000 -type f 2>/dev/null | sort
echo ""
echo "=== Các File có Capabilities ==="
getcap -r / 2>/dev/null | sort
Chạy trước và sau mọi thay đổi hệ thống để có bức tranh rõ ràng về bề mặt đặc quyền của bạn. Trên hệ thống được cấu hình tốt, danh sách SUID nên ngắn và dễ đoán — và mọi entry trong danh sách capabilities phải có lý do được ghi chép đầy đủ.
Capabilities không phải phép màu. Bạn vẫn cần suy nghĩ kỹ về những gì mỗi binary thực sự cần — làm sai và bạn chỉ thay thế một binary quá nhiều đặc quyền bằng một binary khác. Nhưng khi dùng đúng cách, chúng là sự nâng cấp thực sự so với SUID, và các buổi kiểm tra hardening sẽ bớt cảm giác như đang khai quật khảo cổ.

