
Về CVE-2024-0517
CVE-2024-0517 là lỗ hổng bảo mật liên quan đến việc ghi ngoài vùng bộ nhớ được phép (out-of-bounds write) trong thành phần công cụ JavaScript V8 của Google Chrome (trước phiên bản 120.0.6099.224). Lỗ hổng này cho phép kẻ tấn công từ xa khai thác lỗi heap thông qua trang HTML được tạo thủ công. Vấn đề bảo mật này lần đầu tiên được báo cáo lần đầu bởi Toan (Suto) Pham của Qrious Secure.

Lỗ hổng bảo mật này phát sinh từ lỗi type confusion, xảy ra khi một ứng dụng phân bổ hoặc khởi tạo một tài nguyên như con trỏ, đối tượng hoặc biến bằng một kiểu, nhưng sau đó truy xuất tài nguyên đó bằng một kiểu không tương thích với kiểu ban đầu (CWE-843). Trong CVE này, type confusion được kích hoạt trong quá trình cấp phát bộ nhớ được gọi là folded allocation, được Maglev, một trình biên dịch tối ưu hóa cho thành phần JavaScript V8, sử dụng để tối ưu hóa bộ nhớ.
Bằng cách khai thác type confusion và viết mã độc bằng WebAssembly, kẻ tấn công có thể thực thi các lệnh trên máy của nạn nhân.
Các giai đoạn tấn công
Kẻ tấn công có thể lưu trữ một trang web chứa trang HTML được tạo và lừa người dùng truy cập trang web đó thông qua email lừa đảo hoặc mạng xã hội. Khi người dùng truy cập trang web bằng phiên bản Google Chrome tồn tại lỗ hổng bảo mật, mã độc được nhúng sẽ thực thi các lệnh tùy ý.

Thành phần JavaScript V8
Thành phần V8 được viết bằng C++ bởi Google và được phát hành vào ngày 2 tháng 9 năm 2008. V8 có nhiệm vụ biên dịch và thực thi mã nguồn JavaScript, xử lý việc cấp phát bộ nhớ cho các đối tượng và dọn dẹp các đối tượng không còn được sử dụng. V8 là thành phần cốt lõi của Google Chrome và có thể được nhúng vào bất kỳ ứng dụng C++ nào chẳng hạn như Node.js để thực thi JavaScript và hoặc WebAssembly.
Maglev và cơ chế cấp phát gộp (Folded Allocation)
Maglev, trình biên dịch tối ưu hóa trong V8, thực hiện nhiệm vụ cải thiện hiệu năng thực thi mã và cách thức quản lý cấp phát bộ nhớ. Maglev chỉ được kích hoạt khi đoạn mã được chạy với tần suất cao và được đánh dấu là “nóng”, cho thấy nhu cầu chuyển sang biên dịch JIT (just-in-time compilation) để đạt tốc độ thực thi cao hơn so với việc xử lý bằng bộ thông dịch cơ bản.
Thông thường, việc cấp phát xảy ra ở các vùng bộ nhớ không liền kề, dẫn đến việc sử dụng bộ nhớ thưa thớt và không hiệu quả. Để giải quyết vấn đề này, V8 sử dụng một kỹ thuật gọi là “folded allocation”, cho phép cấp phát nhiều biến một cách liên tục và đồng thời. Maglev cũng tối ưu hóa quá trình cấp phát bằng cách áp dụng folded allocation trong quá trình thực thi.

Thu gom rác theo thế hệ (Generational Garbage Collection-GC)
Để dọn dẹp các vùng bộ không còn sử dụng, V8 sử dụng kỹ thuật thu gom rác theo thế hệ (GC), chia bộ nhớ thành hai vùng: vùng cấp phát mới (young space) và vùng cấp phát cũ (old space). Ngoài ra, có hai trình thu gom rác: trình thu gom rác nhỏ (minor garbage collector), chịu trách nhiệm dọn dẹp vùng nhớ vừa cấp phát, và trình thu gom rác lớn (major garbage collector), xử lý việc dọn dẹp vùng cấp phát cũ. Vùng cấp phát mới là vùng bộ nhớ nơi các đối tượng mới được tạo ra sẽ được cấp phát ban đầu, còn vùng cấp phát cũ là nơi lưu trữ các đối tượng tồn tại lâu trong bộ nhớ. Các đối tượng tồn tại qua nhiều chu kỳ dọn rác của minor GC trong vùng cấp phát mới cuối cùng sẽ được thăng cấp sang vùng cấp phát cũ.

Phân tích lỗ hổng bảo mật
Tổng quan
Lỗ hổng bảo mật này phát sinh khi một đối tượng thuộc một lớp đối tượng kế thừa từ một lớp cơ sở mà không có hàm khởi tạo được định nghĩa một cách tường minh và có một đối tượng khác được tạo sau đó. Do folded allication, việc cấp phát đối tượng đầu tiên có thể được theo sau bởi việc cấp phát đối tượng thứ hai. Nếu một sự kiện như thu gom rác xảy ra giữa hai lần cấp phát này, lỗ hổng type confusion có thể phát sinh.
Phân tích nguyên nhân gốc rễ
Các nghiên cứu sinh của OPSWAT đã phân tích chi tiết luồng hoạt động của V8 trong quá trình phân bổ bộ nhớ và xác định rằng các hàm sau sẽ được gọi trong giai đoạn này:

Trong luồng hoạt động này, một vấn đề đã được xác định trong hàm TryBuildFindNonDefaultConstructorOrConstruct: Hàm BuildAllocateFastObject sử dụng current_raw_allocation_ (một con trỏ trỏ đến vùng nhớ được cấp phát cho nhiều biến cùng lúc) để xây dựng thực thể của lớp con, nhưng không xóa được thực thể này bằng cách đặt thành null.
Kết quả là, đối tượng tiếp theo được tạo luôn được cấp phát bộ nhớ ngay sau vùng nhớ được trỏ tới bởi current_raw_allocation_, bất kể có sự kiện nào xảy ra trước lần cấp phát thứ hai.

Nếu GC được gọi, vùng bộ nhớ bên cạnh vùng bộ nhớ liền kề với current_raw_allocation_ có thể được gán cho các đối tượng khác. Điều này có thể dẫn đến tình huống sau khi GC được kích hoạt và một đối tượng khác được tạo, hai con trỏ tham chiếu đến cùng một vùng bộ nhớ nhưng có các kiểu dữ liệu khác nhau, dẫn đến lỗ hổng type confusion.

Khai thác
Để khai thác lỗ hổng này, các nghiên cứu sinh của OPSWAT đã tạo ra các phiên bản WebAssembly chứa shellcode và cố gắng kích hoạt nhầm lẫn kiểu bằng GC để kiểm soát bộ nhớ và thực thi shellcode:

Kích hoạt Type Confusion
Trong quá trình khởi tạo, trước tiên chúng ta định nghĩa một mảng (_arrayObject) chứa các đối tượng rỗng. Tiếp theo, chúng ta xây dựng một thực thể của lớp con cũng như kích hoạt trình thu gom rác. Cuối cùng, chúng ta định nghĩa một mảng khác với số dấu phẩy động, có tên là _arrayDouble.

Quá trình này cần được thực thi nhiều lần để khiến cho V8 đánh dấu nó là "hot" và kích hoạt trình biên dịch Maglev. Chúng ta làm điều này bằng cách gọi hàm khởi tạo của lớp con trong một vòng lặp như sau:

Type confusion sẽ xảy ra sau khi khởi tạo các đối tượng này nhiều lần trong một vòng lặp.
Tạo các primitive đọc/ghi ở mức thấp
Sau khi kích hoạt type confusion thành công, việc thực thi shellcode đòi hỏi phải đọc bộ nhớ và ghi đè bộ nhớ tại một địa chỉ tùy ý. Để thực hiện việc này, cần tạo các primitives dùng để đọc và ghi vùng nhớ. Các primitive sẽ tận dụng metadata trong các đối tượng để cung cấp cho các vùng bộ nhớ có khả năng đọc/ghi tùy ý và chúng ta sẽ sử dụng các vùng đó để chạy mã tùy ý.

Các primitive dùng để đọc và ghi trong bước này sẽ cho phép chúng ta kiểm soát “jump table” của thể hiện WebAssembly ở bước tiếp theo.
Khởi tạo thực thể WebAssembly
Tiếp theo, chúng ta tạo hai thực thể WebAssembly: một để lưu trữ shellcode và một để kích hoạt shellcode. Để tránh ghi trực tiếp shellcode vào bộ nhớ của thực thể WebAssembly thông qua các primitive, chúng tôi định nghĩa một số hằng số dấu phẩy động trong thực thể WebAssembly.

Kiểm soát con trỏ “Jump table” của thực thể WebAssembly
Sử dụng các primtive; chúng tôi điều chỉnh jump table của thực thể WebAssembly thứ hai để bỏ qua một số byte của mã đã biên dịch của các hằng số trong thực thể WebAssembly đầu tiên để các hằng số dấu phẩy động sẽ được diễn giải thành shellcode theo ý định của chúng tôi:

Chạy thực thể WebAssembly để thực thi Shellcode
Cuối cùng, sau khi kích hoạt type confusion và sử dụng các primitive để kiểm soát các jump table của các thực thể WebAssembly, chúng tôi đã gọi hàm được xuất (exported function) của thực thể WebAssembly thứ hai, hàm này khiến cho shellcode trong thể hiện WebAssembly đầu tiên được thực thi.
Mã lệnh shellcode mà chúng tôi đang sử dụng được thiết kế để chấm dứt mọi tiến trình trên máy Linux, bằng lệnh sau:

Mã lệnh để thực thi lệnh này, được chuyển đổi từ số dấu phẩy động, sẽ như sau:

Mô phỏng lỗ hổng bảo mật
Để mô phỏng việc khai thác này trong một kịch bản thực tế, các nghiên cứu sinh của OPSWAT đã tạo ra một trang HTML có chủ đích.

Một email lừa đảo có nhúng liên kết đến website có chứa trang HTML độc hại này sẽ được gửi đến nạn nhân.

Nếu nạn nhân truy cập liên kết bằng phiên bản Google Chrome có lỗ hổng bảo mật, mã độc sẽ được thực thi, khiến tất cả các quy trình bị chấm dứt. Kết quả là người dùng sẽ bị đăng xuất, như được hiển thị bên dưới:

Khắc phục
MetaDefender Endpoint™ đã được sử dụng để chủ động giảm thiểu CVE này bằng cách tận dụng chức năng "Vulnerable Application" của nó. Giải pháp này xác định và hiển thị tất cả các CVE liên quan cho các ứng dụng Google Chrome trong môi trường thiết bị đầu cuối. Để vô hiệu hóa mối đe dọa, người dùng có thể nhanh chóng gỡ cài đặt Chrome hoặc áp dụng bản vá bảo mật mới nhất. Bằng cách triển khai bất kỳ biện pháp đối phó nào, CVE sẽ được kiểm soát hoàn toàn, giúp giảm đáng kể nguy cơ tấn công mạng thành công vào thiết bị đầu cuối.

Bảo vệ thiết bị đầu cuối thế hệ mới
Khám phá lý do tại sao các tổ chức, cơ quan và đơn vị trên toàn thế giới tin tưởng MetaDefender Endpoint để bảo vệ các thiết bị đầu cuối trọng yếu. Hãy trao đổi với chuyên gia ngay hôm nay để tìm hiểu thêm và tự mình trải nghiệm bản demo miễn phí.
Tham khảo
https://nvd.nist.gov/vuln/detail/CVE-2024-0517
https://cwe.mitre.org/data/def địnhs/843.html
https://blog.exodusintel.com/2024/01/19/google-chrome-v8-cve-2024-0517-out-of-bounds-write-code-execution/
https://jhalon.github.io/chrome-browser-exploitation-1/
https://wenderson.dev/blog/webgl-garbage-collection/
https://v8.dev/
https://github.com/Uniguri/CVE-nday/tree/master/Chrome/V8/CVE-2024-0517
