Các cuộc tấn công hủy tuần tự hóa—việc thao túng trái phép dữ liệu tuần tự hóa để thực thi mã độc—có thể gây ra thiệt hại nghiêm trọng cho các tổ chức. Các nhà phát triển và nhóm bảo mật phải chủ động xác định các lỗ hổng quan trọng cho thấy cách thức, thời điểm và địa điểm xảy ra cuộc tấn công.
Một ví dụ gần đây về mối đe dọa này là CVE-2023-34040, một vectơ tấn công deserialization trong Spring cho Apache Kafka có thể dẫn đến RCE (thực thi mã từ xa). Trên thực tế, sự phổ biến của các lỗ hổng deserialization được nêu bật trong danh sách OWASP Top 10, trong đó có "Deserialization of Untrusted Data" là một trong 10 rủi ro bảo mật ứng dụng web quan trọng nhất.
Các công cụ như OPSWAT MetaDefender Core™ với SBOM ( Software Công cụ Bill of Materials) rất cần thiết trong việc phát hiện và ngăn chặn các cuộc tấn công hủy tuần tự hóa. Chúng cho phép các nhà phát triển quét và phân tích mã của họ một cách hiệu quả, đảm bảo không bỏ sót bất kỳ lỗ hổng nào.
Trong blog này, các Nghiên cứu sinh của chúng tôi sẽ thảo luận chi tiết về CVE-2023-34040 và cách khai thác lỗ hổng này, cũng như cách bảo vệ các thành phần nguồn mở khỏi các mối đe dọa tương tự.
Giới thiệu về CVE-2023-34040
CVE-2023-34040 tiết lộ một vectơ tấn công giải tuần tự hóa trong Spring for Apache Kafka, có thể bị khai thác khi áp dụng cấu hình bất thường. Lỗ hổng này cho phép kẻ tấn công xây dựng một đối tượng tuần tự hóa độc hại trong một trong các tiêu đề bản ghi ngoại lệ giải tuần tự hóa, có thể dẫn đến RCE. Lỗ hổng ảnh hưởng đến Spring for Apache Kafka phiên bản 2.8.1 đến 2.9.10 và 3.0.0 đến 3.0.9.
Cụ thể, một ứng dụng/người dùng sẽ dễ bị tấn công trong các cấu hình và điều kiện cụ thể sau:
- Lớp ErrorHandlingDeserializer không được cấu hình cho khóa và/hoặc giá trị của bản ghi.
- Thuộc tính checkDeserExWhenKeyNull và/hoặc checkDeserExWhenValueNull của người dùng được đặt thành true.
- Các nguồn không đáng tin cậy được phép xuất bản lên chủ đề Kafka.
Apache Kafka
Apache Kafka, được phát triển bởi Apache Software Foundation, là một nền tảng phát trực tuyến sự kiện phân tán được thiết kế để thu thập, xử lý, phản hồi và định tuyến các luồng dữ liệu thời gian thực từ nhiều nguồn khác nhau, bao gồm cơ sở dữ liệu, cảm biến và mobile thiết bị.
Ví dụ, nó có thể truyền phát thông báo đến các dịch vụ phản hồi hoạt động của khách hàng, chẳng hạn như hoàn tất thanh toán sản phẩm hoặc thực hiện thanh toán.
Trong Apache Kafka, một sự kiện - còn được gọi là bản ghi hoặc thông điệp - đóng vai trò là đơn vị dữ liệu biểu diễn sự kiện xảy ra trong ứng dụng bất cứ khi nào dữ liệu được đọc hoặc ghi. Mỗi sự kiện bao gồm khóa, giá trị, dấu thời gian và tiêu đề siêu dữ liệu tùy chọn.
Khóa nhị phân (có thể là null) | Giá trị nhị phân (có thể là null) | ||||
Loại nén [không có, gzip, snappy, lz4, zstd] | |||||
Tiêu đề (tùy chọn)
| |||||
Phân vùng + Bù trừ | |||||
Dấu thời gian (do hệ thống hoặc người dùng đặt) |
Sự kiện được lưu trữ lâu dài và được tổ chức thành các chủ đề. Các ứng dụng khách hàng gửi (ghi) sự kiện đến các chủ đề Kafka được gọi là nhà sản xuất, trong khi các ứng dụng đăng ký (đọc và xử lý) sự kiện được gọi là người tiêu dùng.
Mùa xuân cho Apache Kafka
Để kết nối Apache Kafka với hệ sinh thái Spring, các nhà phát triển có thể sử dụng Spring cho Apache Kafka, giúp đơn giản hóa việc tích hợp trong các ứng dụng Java.
Spring for Apache Kafka cung cấp các công cụ và giao diện lập trình ứng dụng mạnh mẽ giúp đơn giản hóa quy trình gửi và nhận sự kiện với Kafka, cho phép các nhà phát triển thực hiện các tác vụ này mà không cần mã hóa nhiều và phức tạp.
Tuần tự hóa và Giải tuần tự hóa
Serialization là một cơ chế chuyển đổi trạng thái của một đối tượng thành một chuỗi hoặc một luồng byte. Ngược lại, deserialization là quá trình ngược lại, trong đó dữ liệu đã được serialization được chuyển đổi trở lại thành đối tượng hoặc cấu trúc dữ liệu ban đầu của nó. Serialization cho phép dữ liệu phức tạp được chuyển đổi để có thể lưu vào một tệp, gửi qua mạng hoặc lưu trữ trong cơ sở dữ liệu. Serialization và deserialization rất cần thiết cho việc trao đổi dữ liệu trong các hệ thống phân tán và thúc đẩy giao tiếp giữa các thành phần khác nhau của một ứng dụng phần mềm. Trong Java, writeObject() được sử dụng để serialization và readObject() được sử dụng để deserialization.
Vì quá trình khử tuần tự hóa cho phép chuyển đổi luồng byte hoặc chuỗi thành đối tượng, nên việc xử lý không đúng cách hoặc thiếu xác thực dữ liệu đầu vào có thể dẫn đến lỗ hổng bảo mật đáng kể, có khả năng dẫn đến tấn công RCE.
Phân tích lỗ hổng bảo mật
Theo mô tả của CVE, OPSWAT Các nghiên cứu sinh đã cấu hình checkDeserExWhenKeyNull và checkDeserExWhenValueNull thành true để kích hoạt lỗ hổng bảo mật. Bằng cách gửi một bản ghi có khóa/giá trị rỗng và tiến hành phân tích chi tiết bằng cách gỡ lỗi người dùng khi nhận được bản ghi Kafka từ nhà sản xuất, các nghiên cứu sinh sau đại học của chúng tôi đã phát hiện ra quy trình làm việc sau trong quá trình xử lý bản ghi:
Bước 1: Nhận hồ sơ (Tin nhắn)
Khi nhận được bản ghi, người dùng sẽ gọi phương thức invokeIfHaveRecords() , sau đó gọi phương thức invokeListener() để kích hoạt trình lắng nghe bản ghi đã đăng ký (một lớp được chú thích bằng chú thích @KafkaListener ) để xử lý thực tế các bản ghi.
Sau đó, invokeListener() sẽ gọi phương thức invokeOnMessage() .
Bước 2: Kiểm tra hồ sơ
Trong phương thức invokeOnMessage() , một số điều kiện được đánh giá dựa trên giá trị bản ghi và thuộc tính cấu hình, sau đó xác định bước tiếp theo sẽ được thực hiện.
Nếu một bản ghi có khóa hoặc giá trị null và các thuộc tính checkDeserExWhenKeyNull và/hoặc checkDeserExWhenValueNull được đặt rõ ràng thành true , phương thức checkDeser() sẽ được gọi để kiểm tra bản ghi.
Bước 3: Kiểm tra ngoại lệ từ tiêu đề
Trong checkDesr() , người dùng liên tục gọi getExceptionFromHeader() để truy xuất bất kỳ ngoại lệ nào từ siêu dữ liệu của bản ghi, nếu có, và lưu trữ kết quả trong một biến có tên là exception .
Bước 4: Trích xuất ngoại lệ từ tiêu đề
Phương thức getExceptionFromHeader() được thiết kế để trích xuất và trả về một ngoại lệ từ tiêu đề của bản ghi Kafka. Đầu tiên, nó sẽ truy xuất tiêu đề của bản ghi và sau đó lấy giá trị của tiêu đề, được lưu trữ trong một mảng byte.
Sau đó, nó chuyển tiếp mảng byte của giá trị tiêu đề đến phương thức byteArrayToDeserializationException() để xử lý thêm.
Bước 5: Giải tuần tự hóa dữ liệu
Trong byteArrayToDeserializationException() , hàm resolveClass() bị ghi đè để hạn chế việc giải tuần tự hóa chỉ đối với các lớp được phép. Cách tiếp cận này ngăn chặn việc giải tuần tự hóa bất kỳ lớp nào không được phép rõ ràng. Giá trị mảng byte của tiêu đề chỉ có thể được giải tuần tự hóa trong byteArrayToDeserializationException() nếu nó đáp ứng điều kiện được đặt trong resolveClass() , cho phép giải tuần tự hóa dành riêng cho lớp DeserializationException .
Tuy nhiên, lớp DeserializationException mở rộng lớp Exception chuẩn và bao gồm một hàm tạo có bốn tham số. Tham số cuối cùng, cause , biểu diễn ngoại lệ ban đầu kích hoạt DeserializationException , chẳng hạn như IOException hoặc ClassNotFoundException .
Lớp Throwable đóng vai trò là siêu lớp cho tất cả các đối tượng có thể được ném ra như các ngoại lệ hoặc lỗi trong Java. Trong ngôn ngữ lập trình Java, các lớp xử lý ngoại lệ như Throwable , Exception và Error có thể được giải tuần tự hóa an toàn. Khi một ngoại lệ được giải tuần tự hóa, Java cho phép lớp cha Throwable của các lớp được tải và khởi tạo với các kiểm tra ít đòi hỏi hơn so với các kiểm tra được áp dụng cho các lớp thông thường.
Dựa trên quy trình làm việc và phân tích toàn diện, nếu dữ liệu tuần tự hóa tương ứng với một lớp độc hại kế thừa từ lớp cha Throwable , nó có thể bỏ qua các kiểm tra điều kiện. Điều này cho phép hủy tuần tự hóa một đối tượng độc hại, có thể thực thi mã độc hại và có khả năng dẫn đến một cuộc tấn công RCE.
Khai thác
Như đã chỉ ra trong phân tích, việc khai thác lỗ hổng này đòi hỏi phải tạo dữ liệu độc hại được gửi đến người dùng thông qua bản ghi tiêu đề Kafka. Ban đầu, kẻ tấn công phải tạo một lớp độc hại mở rộng lớp Throwable và sau đó sử dụng chuỗi tiện ích để thực hiện lệnh thực thi mã từ xa. Tiện ích là các đoạn mã có thể khai thác trong ứng dụng và bằng cách kết nối chúng lại với nhau, kẻ tấn công có thể tiếp cận "tiện ích chìm" kích hoạt các hành động có hại.
Sau đây là lớp độc hại có thể được sử dụng để khai thác lỗ hổng này trong Spring for Apache Kafka:
Tiếp theo, một thể hiện của lớp độc hại được tạo và truyền như một đối số cho tham số nguyên nhân trong hàm tạo của lớp DeserializationException . Thể hiện DeserializationException sau đó được tuần tự hóa thành một luồng byte, sau đó được sử dụng làm giá trị trong tiêu đề của bản ghi Kafka độc hại.
Nếu kẻ tấn công lừa được nạn nhân sử dụng trình tạo độc hại của chúng, chúng có thể kiểm soát các bản ghi Kafka được gửi đến người dùng, tạo cơ hội xâm phạm hệ thống.
Khi người dùng dễ bị tổn thương nhận được bản ghi Kafka từ nhà sản xuất độc hại có chứa các khóa và giá trị null, cùng với một phiên bản tuần tự hóa độc hại trong tiêu đề bản ghi, người dùng sẽ xử lý bản ghi, bao gồm cả quy trình hủy tuần tự hóa. Điều này cuối cùng dẫn đến thực thi mã từ xa, cho phép kẻ tấn công xâm phạm hệ thống.
Giảm thiểu CVE-2023-34040 bằng SBOM trong MetaDefender Core
Để giảm thiểu hiệu quả các rủi ro liên quan đến CVE-2023-34040, các tổ chức cần có giải pháp toàn diện cung cấp khả năng hiển thị và kiểm soát các thành phần nguồn mở của mình.
SBOM, một công nghệ nền tảng trong MetaDefender Core , cung cấp một câu trả lời mạnh mẽ. Bằng cách hoạt động như một kho lưu trữ toàn diện tất cả các thành phần phần mềm, thư viện và các phụ thuộc đang sử dụng, SBOM cho phép các tổ chức theo dõi, bảo mật và cập nhật các thành phần nguồn mở của họ theo cách chủ động và hiệu quả.
Với SBOM, các nhóm an ninh có thể:
- Xác định nhanh các thành phần dễ bị tấn công: Xác định ngay các thành phần nguồn mở bị ảnh hưởng bởi các cuộc tấn công deserialization. Điều này đảm bảo hành động nhanh chóng trong việc vá hoặc thay thế các thư viện dễ bị tấn công.
- Đảm bảo vá lỗi và cập nhật chủ động: Liên tục theo dõi các thành phần nguồn mở thông qua SBOM để luôn đi trước các lỗ hổng giải tuần tự hóa. SBOM có thể phát hiện các thành phần lỗi thời hoặc không an toàn, cho phép cập nhật kịp thời và giảm nguy cơ bị tấn công.
- Duy trì sự tuân thủ và báo cáo: SBOM giúp các tổ chức đáp ứng các yêu cầu về tuân thủ vì khuôn khổ pháp lý ngày càng yêu cầu tính minh bạch trong chuỗi cung ứng phần mềm.
Bớt tư tưởng
Các lỗ hổng deserialization là mối đe dọa bảo mật đáng kể có thể được sử dụng để khai thác nhiều ứng dụng khác nhau. Các lỗ hổng này xảy ra khi một ứng dụng deserialization dữ liệu độc hại, cho phép kẻ tấn công thực thi mã tùy ý hoặc truy cập thông tin nhạy cảm. Lỗ hổng CVE-2023-34040 trong Spring for Apache Kafka đóng vai trò là lời nhắc nhở rõ ràng về mối nguy hiểm của các cuộc tấn công deserialization.
Để ngăn chặn các cuộc tấn công hủy tuần tự hóa, điều cần thiết là phải triển khai các công cụ tiên tiến như OPSWAT MetaDefender Core và công nghệ SBOM của nó. Các tổ chức có thể có được tầm nhìn sâu sắc vào chuỗi cung ứng phần mềm của họ, đảm bảo vá lỗ hổng kịp thời và tự bảo vệ mình trước bối cảnh mối đe dọa luôn thay đổi. Chủ động bảo mật các thành phần nguồn mở không chỉ là một biện pháp tốt nhất mà còn là điều cần thiết để bảo vệ các hệ thống hiện đại khỏi nguy cơ khai thác tiềm ẩn.