Một chuỗi khai thác mới được công bố trên GitLab đã tiết lộ cách hai lỗ hổng an toàn bộ nhớ (memory-safety flaws) tồn tại lâu năm trong thư viện phân tích cú pháp JSON viết bằng Ruby, Oj, có thể được kết hợp để đạt được remote code execution (RCE) trên các cài đặt GitLab mặc định. Sự phát hiện này phơi bày một lỗ hổng GitLab RCE nghiêm trọng, đe dọa mã nguồn, bí mật Rails và các dịch vụ nội bộ của hệ thống.
Kẻ tấn công có thể lợi dụng những điểm yếu này để chiếm quyền điều khiển hệ thống, dẫn đến rò rỉ dữ liệu nhạy cảm và các hậu quả an ninh mạng nghiêm trọng khác. Đây là một cảnh báo mạnh mẽ về tầm quan trọng của việc kiểm tra và vá lỗi bảo mật định kỳ.
Phát Hiện Lỗ Hổng Oj Ruby JSON Parser
Trong khuôn khổ Sáng kiến Phòng thủ Mở (Open Defense Initiative), nhà nghiên cứu Yuhang Wu từ Depthfirst đã sử dụng hệ thống phân tích tự động để quét Oj. Oj là một trình phân tích cú pháp JSON hiệu suất cao dựa trên C, được sử dụng rộng rãi trong các ứng dụng Ruby, bao gồm cả GitLab.
Cơ Chế Phát Hiện Ban Đầu
Quá trình quét đã phát hiện 18 lỗ hổng được ưu tiên, trong đó có bảy lỗi an toàn bộ nhớ. Đáng chú ý, hai trong số các lỗ hổng này đã âm thầm tồn tại trong Oj gần năm năm trước khi được vũ khí hóa thành một chuỗi khai thác hoàn chỉnh, cho thấy mức độ khó khăn trong việc phát hiện các lỗi cấp thấp.
Việc phát hiện những lỗ hổng này thông qua phân tích tự động nhấn mạnh giá trị của các công cụ hiện đại trong việc tìm kiếm các điểm yếu ẩn giấu trong mã nguồn, đặc biệt là trong các thư viện phụ thuộc phức tạp.
Chi Tiết Các Lỗ Hổng Gốc
Hai lỗ hổng cốt lõi bao gồm một lỗi ghi chồng ngăn xếp (unchecked nesting-stack write) trong hàm Oj::Parser.usual.parse và một lỗi thu hẹp độ dài khóa 16-bit không an toàn (unsafe 16-bit key-length narrowing) làm rò rỉ con trỏ heap. Các lỗi này, dù đơn lẻ có vẻ không nghiêm trọng, nhưng khi kết hợp lại, chúng tạo ra một mối đe dọa đáng kể.
Riêng lẻ, lỗi ghi chồng ngăn xếp chỉ cung cấp khả năng ghi một byte lặp lại. Trong khi đó, lỗi thu hẹp độ dài khóa chỉ tiết lộ một đoạn bộ nhớ cố định 29 byte. Tuy nhiên, sự kết hợp khéo léo giữa chúng đã mở ra cánh cửa cho việc chiếm quyền điều khiển hoàn toàn.
Khi được kết hợp với thao tác bộ cấp phát heap cẩn thận, các lỗ hổng này đã cấp cho kẻ tấn công toàn quyền kiểm soát một con trỏ callback và một cách để đánh bại ASLR (Address Space Layout Randomization). Điều này cuối cùng cho phép thực thi mã tùy ý với quyền của người dùng hệ thống “git”, dẫn đến một lỗ hổng GitLab RCE.
Chuỗi Khai Thác Dẫn Đến Lỗ Hổng GitLab RCE
GitLab tạo ra các bản diff dễ đọc cho các tệp Jupyter Notebook (.ipynb) bằng cách sử dụng một gem tích hợp có tên ipynbdiff. Trước khi tạo bản diff này, gem sẽ phân tích cú pháp từng bản sửa đổi notebook bằng trình phân tích cú pháp gốc của Oj để xác thực rằng JSON chứa trường “cells”. Đây là điểm khởi đầu quan trọng cho chuỗi remote code execution này.
Điểm Yếu trong GitLab Jupyter Notebook Diff
Vì một tệp notebook về cơ bản là một tài liệu JSON, bất kỳ người dùng đã xác thực nào có thể đẩy commit và xem commit diff đều có thể đưa các cấu trúc JSON độc hại vào lời gọi hàm phân tích cú pháp đó. Khả năng này biến một tính năng thông thường thành một vector tấn công tiềm năng.
Việc không kiểm soát chặt chẽ đầu vào JSON từ người dùng đã xác thực, ngay cả khi họ không có đặc quyền cao, đã tạo ra một kẽ hở nghiêm trọng. Điều này cho phép kẻ tấn công khai thác mà không cần đến các phương pháp phức tạp như khai thác zero-day thông thường.
Quy Trình Khai Thác Kỹ Thuật Chi Tiết
Chuỗi khai thác hoạt động bằng cách đẩy hai tệp notebook được tạo đặc biệt trong một yêu cầu commit-diff duy nhất. Tệp đầu tiên, với độ sâu lồng ghép quá lớn, đã lạm dụng lỗi ghi chồng ngăn xếp không được kiểm tra để chuyển hướng một con trỏ bộ đệm nội bộ.
Sau đó, các hoạt động heap tiếp theo đã làm cho bộ nhớ của một Ruby Array chồng lấn với một con trỏ callback của trình phân tích cú pháp. Điều này cho phép kẻ tấn công chèn một địa chỉ tùy chọn vào p->start, kiểm soát luồng thực thi của chương trình.
Một lỗi rò rỉ con trỏ heap thứ hai, được tuồn ra trong một khóa đối tượng JSON quá khổ và được hiển thị trong đầu ra HTML của diff, đã cung cấp cho kẻ tấn công địa chỉ cần thiết. Địa chỉ này dùng để tính toán vị trí bộ nhớ của các thư viện cốt lõi như libc và libruby, từ đó đánh bại các biện pháp bảo vệ ASLR.
Vì Puma (máy chủ ứng dụng Ruby của GitLab) chạy nhiều luồng chia sẻ một thể hiện trình phân tích cú pháp gốc trên mỗi worker, cả hai tệp được tạo đều được xử lý bởi cùng một trình phân tích cú pháp dễ bị tổn thương trong một yêu cầu duy nhất. Điều này cho phép tệp thứ hai kích hoạt callback bị hỏng và thực thi lệnh shell thông qua system(), hoàn tất quy trình remote code execution.
Vượt Qua Cơ Chế Phòng Thủ Hiện Đại
Không giống như các vấn đề remote code execution trước đây của GitLab dựa vào giả mạo yêu cầu phía máy chủ (server-side request forgery – SSRF) chống lại các phiên bản Redis nội bộ, chuỗi này đã hoàn toàn bỏ qua các biện pháp phòng thủ SSRF hiện đại của GitLab. Nó tấn công một phụ thuộc bộ nhớ không an toàn gốc được nhúng trong mã Ruby vốn an toàn bộ nhớ. Đây là một điểm đáng chú ý, cho thấy các kỹ thuật tấn công ngày càng tinh vi và nhắm vào các lớp thấp hơn của hệ thống.
Tác Động và Mức Độ Nghiêm Trọng của Cuộc Tấn Công
Bất kỳ thành viên dự án nào có quyền push và xem diff thông thường đều có thể kích hoạt chuỗi khai thác mà không cần quyền quản trị viên, quyền truy cập CI/CD hoặc tương tác của nạn nhân. Điều này khiến lỗ hổng GitLab RCE này đặc biệt nguy hiểm cho các phiên bản GitLab tự quản lý được chia sẻ hoặc đa người thuê, nơi có nhiều người dùng với các cấp độ truy cập khác nhau.
Quyền Hạn Bị Chiếm Đoạt và Dữ Liệu Rò Rỉ
Khai thác thành công cho phép các lệnh được thực thi dưới tài khoản “git”, tài khoản này cung cấp năng lượng cho các worker của Puma trên GitLab. Điều này có thể làm lộ mã nguồn kho lưu trữ, bí mật ứng dụng Rails, thông tin đăng nhập dịch vụ và bất kỳ dịch vụ nội bộ nào có thể truy cập từ máy chủ GitLab.
Kết quả là có rủi ro bảo mật cao về đánh cắp dữ liệu, giả mạo mã nguồn và di chuyển ngang (lateral movement), theo báo cáo của Depthfirst. Phạm vi tác động rất rộng, từ việc xâm phạm tính toàn vẹn của mã đến việc chiếm đoạt dữ liệu nhạy cảm.
Điều Kiện Khai Thác Dễ Dàng
Việc khai thác không yêu cầu tương tác từ phía nạn nhân hoặc đặc quyền cao. Chỉ cần một tài khoản có khả năng đẩy commit và xem diff là đủ để kích hoạt chuỗi khai thác, biến nó thành một mối đe dọa đáng kể đối với bất kỳ tổ chức nào sử dụng GitLab.
Lộ Trình Vá Lỗi và Khuyến Nghị Bảo Mật
GitLab.com đã được vá tại thời điểm công bố, và khách hàng Dedicated không yêu cầu hành động nào. Tuy nhiên, các nhà vận hành phiên bản tự quản lý (self-managed) trên các phiên bản bị ảnh hưởng phải nâng cấp ngay lập tức để khắc phục lỗ hổng GitLab RCE này và đảm bảo an toàn thông tin.
Diễn Biến Vá Lỗi Chi Tiết
Mã phân tích cú pháp Oj dễ bị tổn thương đã được hợp nhất vào tháng 8 năm 2021. GitLab bắt đầu sử dụng lời gọi phân tích cú pháp bị ảnh hưởng vào tháng 7 năm 2022 thông qua phiên bản GitLab 15.2.0.
Nhà nghiên cứu đã báo cáo các lỗi cốt lõi của Oj vào ngày 21 tháng 5 năm 2026. Oj đã hợp nhất các bản sửa lỗi vào ngày 27 tháng 5, sau khi các lỗ hổng đã tồn tại trong 1.753 ngày, với phiên bản Oj 3.17.3 được phát hành vào ngày 4 tháng 6.
Chuỗi cụ thể của GitLab đã được báo cáo vào ngày 5 tháng 6, được xác nhận vào ngày 8 tháng 6, và được vá vào ngày 10 tháng 6 năm 2026, trên các bản phát hành 19.0.2, 18.11.5 và 18.10.8. Đây là một nỗ lực khẩn cấp và phối hợp để triển khai bản vá bảo mật một cách nhanh chóng.
Hướng Dẫn Cập Nhật và Kiểm Tra Phụ Thuộc
Các nhóm bảo mật đang chạy GitLab tự quản lý nên ưu tiên vá lỗi lên các bản phát hành đã sửa ở trên. Đồng thời, cần kiểm tra cây phụ thuộc Ruby để tìm các tiện ích mở rộng C gốc. Mã không an toàn bộ nhớ bên trong một gem đáng tin cậy có thể phá vỡ các đảm bảo an toàn bộ nhớ của toàn bộ ngăn xếp ứng dụng Ruby.
Cập nhật phiên bản GitLab của bạn là bước quan trọng nhất để bảo vệ hệ thống khỏi các mối đe dọa tương tự. Kiểm tra và quản lý cẩn thận các thư viện phụ thuộc là một phần không thể thiếu của chiến lược an ninh mạng hiệu quả, đặc biệt là khi đối mặt với các lỗ hổng memory-safety.
Bài Học Từ Lỗ Hổng Memory-Safety trong Ruby
Nỗ lực nghiên cứu tương tự đã tạo ra chín CVE được công bố cho Oj ngoài hai lỗi được sử dụng trong chuỗi này. Các CVE này bao gồm tràn bộ đệm ngăn xếp và heap, nhiều điều kiện sử dụng sau giải phóng (use-after-free) trong các callback SAJ và các trình lặp tài liệu, một lỗi memcpy với kích thước âm, và một lỗi tràn số nguyên tệp lớn. Điều này nhấn mạnh mức độ sâu sắc mà rủi ro hỏng bộ nhớ có thể ẩn chứa bên trong các tiện ích mở rộng gốc được đóng gói với các ứng dụng Ruby vốn được coi là “an toàn”. Phát hiện này cung cấp cái nhìn sâu sắc về các nguy cơ tiềm ẩn có thể dẫn đến một lỗ hổng GitLab RCE.
Sự cố này tái khẳng định tầm quan trọng của việc kiểm tra kỹ lưỡng các thư viện và thành phần bên thứ ba, đặc biệt là những thành phần được viết bằng các ngôn ngữ có khả năng gây ra lỗi an toàn bộ nhớ. Ngay cả trong một môi trường được cho là an toàn như Ruby, các thư viện C gốc vẫn có thể mang lại rủi ro đáng kể, đòi hỏi sự cảnh giác liên tục từ các chuyên gia an ninh mạng để duy trì an toàn thông tin.










