Dẫn nhập
Như chúng ta đã biết, một hệ thống phần mềm không bao giờ hoạt động trong môi trường chân không mà là hoạt động từ một hay nhiều chương trình được hỗ trợ tính toán trên một môi trường lớn nào đó, thường là bao gồm các thành phần như : hệ điều hành, kiến trúc phần cứng, mạng, tập tin hệ thống, cơ sở dữ liệu và người dùng. Khi một chương trình vận hành, nó không tồn tại trong chân không như vậy: nó dựa vào một chuỗi các giả định về môi trường chung quanh (đã nêu trên). Nhiều lỗi phần mềm không chỉ đến từ dữ liệu độc hại mà còn từ việc ai đó thao túng môi trường hoạt động của chương trình. Khi lập trình viên hiểu chưa đủ hoặc tin tưởng quá mức vào những môi trường đó, hệ thống dễ bị mắc điểm yếu. Có một thuật ngữ dùng để mô tả cách thức loại tấn công trên là Tấn Công Môi Trường (Environmental Attacks). Vì vậy, bảo mật cần cả việc kiểm tra dữ kiện của môi trường, không chỉ là xử lý dữ liệu đầu vào.
Một ví dụ kinh điển là /tmp race: nếu một chương trình tạo file tạm trong thư mục công khai như /tmp mà không cẩn thận, kẻ tấn công có thể đặt một symbolic link vào đúng lúc, đúng chỗ để chuyển hướng file tạm sang vị trí khác (ví dụ file hệ thống), điều này rất nguy hiểm khi chương trình chạy với quyền root.
Viễn cảnh bảo mật ấy thật đáng để xem xét kỹ, nhưng nếu bài viết này tập trung vào trình bày một cách tổng thể về Environmental Attacks thì sẽ rất dài dòng và nhàm chán. Một thuật ngữ khá thú vị xuất hiện ở đoạn vừa nêu trên là “symbolic link”, một thứ gì đó mà kẻ tấn công có thể dùng để tác động lên cả môi trường của chương trình và thậm chí là thay đổi tài nguyên hệ thống. Trong bài viết này sẽ đào sâu về khái niệm ấy và những vấn đề bảo mật cơ bản đi kèm với nó. Vậy symbolic link là gì ?
Symbolic Link là gì
Symbolic Links, thường được gọi là symlinks (đây là tên gọi mà tôi sẽ gọi xuyên suốt bài viết) hoặc link mềm, cho phép người dùng tạo một file hoặc thư mục trỏ đến một file hoặc thư mục khác. Ví dụ, nếu một người quản trị viên tạo một symlink có tên là /home trỏ đến thư mục /mnt/all/diskc, và khi người dùng làm việc với các file trên thư mục gốc là /home thì nó sẽ tự động chuyển hướng đến thư mục diskc. Tương tự, một người dùng có thể tạo một symbolic link trong thư mục cá nhân của mình với tên là link_to_hosts trỏ đến file hệ thống /etc/hosts. Khi người đó mở file link_to_hosts để đọc, thực chất họ đang mở /etc/hosts, chỉ là nhìn bề ngoài thì giống như file này nằm ngay trong thư mục cá nhân của họ. Symlink được tạo thông qua hàm hệ thống symlink(), thực chất là một file rất nhỏ trong hệ thống. Hãy tưởng tượng symbolic link như một tấm bảng chỉ đường. Nó không chứa dữ liệu thật của file, mà chỉ ghi lại “đường đi” đến file khác. Khi bạn bảo hệ điều hành mở file đó, kernel nhìn vào bảng chỉ đường này, đi theo chỉ dẫn đến file gốc, rồi tiếp tục xử lý như bình thường. Nội dung bên trong symbolic link vì thế chỉ là một chuỗi (tên đường dẫn). Nói cho dễ hiểu: symlink không phải bản sao của file, mà là một “lời nhắn” cho kernel: đi sang chỗ kia để lấy dữ liệu.
Các ứng dụng của symlink
1.Ứng dụng của symlink trong quản lý thư viện & dependency: Các thư viện chia sẻ (shared libraries) thường có nhiều phiên bản (ví dụ libfoo.so.1.2.3). Để dễ cập nhật/rollback, hệ thống đặt một symlink “không đổi” (ví dụ libfoo.so.1 hoặc libfoo.so) trỏ tới file phiên bản thực tế. Khi cập nhật, chỉ cần thay target của symlink thay vì sửa mọi chương trình.
2.Một ứng dụng thời thượng trong Quản lý file lớn và dữ liệu huấn luyện ML/AI: Symlink là công cụ tiện lợi để liên kết dự án với dữ liệu huấn luyện lớn (trỏ tới dataset nằm trên ổ khác hoặc mount cloud), giúp tiết kiệm dung lượng, dễ chia sẻ giữa nhiều project và nhanh chóng chuyển giữa các phiên bản (ví dụ data/current trỏ đến data/v2).
Các trường hợp bảo mật thực tế
Bây giờ ta hãy phân tích những trường hợp thực tế liên quan đến Symlink để giúp bạn có thể hình dung ra sự nguy hiểm của loại lỗi này. Trường hợp đầu tiên ta có một bài report trên hackerone : https://hackerone.com/reports/945122. Bài report một dịch vụ syncagentsrv của Acronis có thể lợi dụng lỗi Symlink khiến chương trình tạo/ghi một file ở bất kỳ nơi nào của hệ thống. Cụ thể dịch vụ bị lỗi là syncagentsrv lưu ở ("C:\Program Files (x86)\CommonFiles\Acronis\SyncAgent\syncagentsrv.exe"). Khi dịch vụ này chạy, các thông tin về log của nó được lưu ở C:\ProgramData\Acronis\SyncAgent\logs\syncagent.log, không có bất kì một cơ chế bảo vệ nào ngay cả khi xóa nó đi nữa thì cũng không ảnh hưởng gì vì nó sẽ được tạo lại bởi dịch vụ. Một điều mà tác giả biết nữa là phần mềm có file WptsExtensions.dll - đại loại là một plugin để mở rộng tính năng của phần mềm. Một giả thuyết cực kì sáng tạo của tác giả khi đặt câu hỏi : “Sẽ ra sao nếu file log đó được thay thế bằng một Symlink trỏ đến một tài nguyên có quyền cao trong hệ thống cụ thể là file WptsExtensions.dll ?”. Đi theo giả thuyết trên tác giả đã thực hiện các bước sau : 1. Xóa file log đi; 2. Bằng lệnh thực thi tự tạo CreateSymlink.exe mà anh có thể tạo một symlink cùng tên với file log trỏ đến WptsExtensions.dll. Và mọi chuyện kết thúc khi anh ta tùy chỉnh file đó thành một con shell remote sau đó reboot lại hệ thống. Một câu chuyện về leo thang đặc quyền (Privilege Escalation). Một trường hợp thứ hai đó là bài report liên quan đến sản phẩm GitLab (một nền tảng quản lý mã nguồn và DevOps phổ biến) : https://hackerone.com/reports/378148 . Đây là một lỗ hổng thuộc loại symlink traversal leading to arbitrary file read/write (duyệt symlink dẫn đến đọc/ghi file tùy ý), tương tự như lỗ hổng symlink attack trong báo cáo Acronis mà chúng ta đã thảo luận trước đó. Lỗ hổng này xảy ra trong quá trình import project, cho phép kẻ tấn công lợi dụng symbolic links để truy cập và thao tác file ngoài thư mục dự định, dẫn đến rủi ro bảo mật nghiêm trọng. Lỗ hổng chính là symlink traversal (duyệt qua symbolic links mà không kiểm tra đường dẫn thực tế), cho phép kẻ tấn công tạo hoặc theo dõi symlink để đọc/ghi file ở các vị trí nhạy cảm trên server GitLab. Cụ thể:
- Trong quá trình import project từ repository bên ngoài (như GitHub hoặc local repo), GitLab sao chép file và thư mục mà không resolve đầy đủ các symlink.
- Kẻ tấn công có thể tạo một repository chứa symlink trỏ đến file hệ thống hoặc file config nhạy cảm (ví dụ: /etc/passwd trên Linux hoặc file config của GitLab).
- Khi GitLab import, nó sẽ đọc/ghi dữ liệu qua symlink, dẫn đến arbitrary file read (đọc file tùy ý) hoặc arbitrary file write (ghi file tùy ý) trên server. Trong bài report này, tác giả rất thông minh khi chọn ghi vào .ssh/authorized_keys.
Kết luận
Hãy tưởng tượng symlink như một bóng ma trong gương: nó phản chiếu thực tại, nhưng nếu bạn tin tưởng mù quáng, bạn sẽ lạc lối vào mê cung của những rủi ro không lường trước. Là lập trình viên, quản trị viên hay chỉ đơn giản là người dùng, chúng ta không thể thờ ơ với môi trường xung quanh. Hãy kiểm tra kỹ lưỡng mọi đường dẫn, resolve mọi symlink trước khi hành động, và luôn cập nhật các bản vá. Cuối cùng, trong hành trình khám phá này, hy vọng bạn không chỉ nắm được kiến thức, mà còn cảm nhận được sức hút kỳ lạ của thế giới bảo mật: nơi mà sự khôn ngoan của kẻ tấn công gặp gỡ trí tuệ của người bảo vệ, tạo nên những câu chuyện bất tận. Và nhớ nhé, lần tới khi bạn tạo một symlink, hãy tự hỏi: "Liệu đường dẫn này có dẫn tôi đến nơi an toàn, hay chỉ là một ảo mộng nguy hiểm? Không chỉ có dữ liệu đầu vào, mà còn là môi trường nữa".