Lỗ hổng Copy Fail và cách bảo vệ các container Podman không root

Phần mềm08 tháng 5, 2026·5 phút đọc

Bài viết phân tích lỗ hổng bảo mật CVE-2026-31431 (Copy Fail) và tác động của nó đối với các container Podman chạy ở chế độ không root (rootless). Chúng ta sẽ cùng xem xét cách khai thác lỗ hổng này và các biện pháp phòng thủ hiệu quả như giới hạn quyền hạn và cấu hình hệ thống tập tin chỉ đọc để giảm thiểu rủi ro.

Vào ngày 29 tháng 4, lỗ hổng bảo mật CVE-2026-31431, được đặt tên là Copy Fail, đã được công khai. Lỗ hổng này cho phép một người dùng cục bộ không có đặc quyền có thể lấy được shell root bằng cách chạy một đoạn mã Python do tác giả cung cấp.

Đây là một vấn đề đáng lo ngại vì các container Linux được sử dụng rộng rãi để chạy mọi thứ từ các dịch vụ công cộng, môi trường phát triển cho đến các tác vụ tích hợp liên tục (CI). Một container bị khai thác bởi Copy Fail có thể trở thành công cụ đắc lực cho nhiều loại tấn công khác nhau.

Tuy nhiên, điều thú vị nhất đối với tôi là cách lỗ hổng này hoạt động trong bối cảnh các container rootless (không có quyền root) của Podman — công cụ mà tôi đã chuyển sang sử dụng từ Docker cách đây một năm vì lý do bảo mật.

Tổng quan về container Rootless

Podman giúp việc chạy container dưới quyền người dùng không có đặc quyền trở nên cực kỳ đơn giản. Khác với Docker, nơi một daemon chạy dưới quyền root quản lý các tiến trình, Podman sử dụng mô hình fork/exec. Điều này có nghĩa là tiến trình container là một tiến trình con trực tiếp của lệnh podman run do người dùng khởi tạo.

Hãy xem xét một ví dụ về việc chạy máy chủ HTTP dưới quyền người dùng bar (UID 1001):

bar@debian:~$ podman run --rm -it --name http-server-1 -d -p 127.0.0.1:8000:8000/tcp localhost/http-server:latest

Khi kiểm tra tiến trình, chúng ta sẽ thấy python3 được sở hữu bởi người dùng bar trên máy chủ, mặc dù bên trong container nó có thể đang chạy dưới quyền root.

User Namespaces và quyền hạn

Podman sử dụng User Namespaces (không gian tên người dùng) cho các container rootless. Điều này cho phép các tiến trình có UID/GID khác nhau bên trong và bên ngoài container. Ví dụ, root bên trong container (UID 0) có thể được ánh xạ tới UID 1001 (người dùng bar) bên ngoài máy chủ.

Ngoài ra, Podman còn sử dụng Linux Capabilities (khả năng của Linux) để cấp các đặc quyền chi tiết cho tiến trình container. Chúng ta có thể loại bỏ (drop) hoặc thêm (add) các khả năng này khi xây dựng hình ảnh hoặc chạy container.

Kiểm tra lỗ hổng Copy Fail trên Podman

Để kiểm tra tác động của Copy Fail, tôi đã sử dụng một container chạy Python HTTP server và tải xuống đoạn mã khai thác (exploit) để xem liệu có thể leo thang đặc quyền hay không.

Rootless Rootful (Root trong container, User thường trên host)

Trong cấu hình này, tiến trình chạy dưới quyền root bên trong container nhưng là người dùng bar trên máy chủ. Khi chạy khai thác Copy Fail, chúng ta có thể lấy được shell root bên trong container. Tuy nhiên, phạm vi ảnh hưởng bị giới hạn bởi những gì người dùng bar có thể làm trên máy chủ.

Rootless Non-Root (User thường trong và ngoài container)

Đây là cấu hình an toàn hơn, nơi tiến trình container chạy dưới quyền một người dùng không có đặc quyền (ví dụ: foo) cả bên trong lẫn bên ngoài container.

Khi chạy khai thác Copy Fail trong cấu hình này, lỗ hổng vẫn hoạt động và cho phép chuyển đổi từ user foo sang root bên trong container. Điều này cho thấy container rootless không miễn nhiễm hoàn toàn với lỗ hổng này.

Các biện pháp giảm thiểu rủi ro

Mặc dù lỗ hổng có thể khai thác được, chúng ta vẫn có thể áp dụng nguyên tắc "phòng thủ theo chiều sâu" (defense in depth) để hạn chế tối đa thiệt hại.

Vô hiệu hóa việc cấp đặc quyền mới

Podman cho phép chạy container với tùy chọn --security-opt=no-new-privileges. Điều này ngăn chặn tiến trình container có được thêm bất kỳ đặc quyền nào so với ban đầu.

Khi áp dụng tùy chọn này và chạy lại khai thác, dù lỗ hổng vẫn thực thi, nhưng nó không thể chuyển đổi thành user root. Tiến trình vẫn nằm dưới quyền user foo mà không có bất kỳ khả năng (capabilities) nào.

Loại bỏ các Capabilities

Chúng ta cũng có thể sử dụng cờ --cap-drop=all để loại bỏ tất cả các quyền hạn của Linux khi khởi động container. Kết hợp với việc chạy dưới quyền user không có đặc quyền, biện pháp này ngăn chặn thành công việc leo thang lên root shell có đầy đủ quyền hạn.

Hệ thống tập tin chỉ đọc (Read-only)

Sử dụng cờ --read-only để gắn hệ thống tập tin root của container ở chế độ chỉ đọc là một cách tốt để ngăn chặn việc ghi dữ liệu độc hại vào hệ thống trong trường hợp bị tấn công. Tuy nhiên, bạn cần lưu ý rằng các thư mục tạm thời như /tmp vẫn có thể ghi được nếu không được cấu hình thêm.

Giới hạn tài nguyên và tệp tin thực thi

Sử dụng cgroups để giới hạn bộ nhớ, CPU và số lượng PID cho container. Ngoài ra, hãy sử dụng các hình ảnh (image) càng gọn nhẹ càng tốt (ví dụ: distroless hoặc Alpine) để giảm bề mặt tấn công, loại bỏ các trình bao (shell) hoặc trình quản lý gói không cần thiết.

Kết luận

Lỗ hổng Copy Fail là một ví dụ điển hình cho thấy tầm quan trọng của việc hiểu rõ cấu hình bảo mật của container. Mặc dù các container rootless của Podman cung cấp khả năng cô lập tốt hơn so với thiết lập mặc định của Docker, chúng không phải là "viên đạn bạc" giải quyết mọi vấn đề bảo mật.

Để bảo vệ hệ thống của bạn:

  1. Cập nhật kernel: Luôn áp dụng các bản vá bảo mật mới nhất cho kernel Linux.
  2. Chạy ở mức đặc quyền thấp nhất: Sử dụng user không có đặc quyền bên trong container và loại bỏ các capabilities không cần thiết.
  3. Áp dụng các biện pháp cứng hóa: Sử dụng no-new-privileges, hệ thống tập tin chỉ đọc và giới hạn tài nguyên.

Hiểu rõ chi tiết về hình ảnh container, user chạy tiến trình và các quyền hạn cần thiết là chìa khóa để xây dựng một hệ thống container an toàn và vững chắc.

Chia sẻ:FacebookX
Nội dung tổng hợp bằng AI, mang tính tham khảo. Xem bài gốc ↗