Khai thác Driver lỗi mà không cần phần cứng - Góc nhìn từ BYOVD

Bài viết phân tích kỹ thuật về cách tương tác với các Windows kernel mode driver từ user mode mà không cần phần cứng gốc. Nghiên cứu này giúp xác định liệu lỗ hổng trong driver có thể khai thác được hay không khi mã nguồn bị chặn bởi các điều kiện phần cứng (hardware-gated), từ đó mở rộng khả năng tấn công BYOVD.
Windows Kernel Driver Analysis

1. Giới thiệu

Bài viết này cung cấp một phân tích kỹ thuật về số lượng Windows kernel mode drivers có thể tương tác từ user mode mà không cần phần cứng gốc mà chúng được phát triển để hỗ trợ. Công việc này được thúc đẩy bởi hoạt động nghiên cứu lỗ hổng hướng vào driver và nhu cầu đánh giá khả năng khai thác của các phát hiện cá biệt, vốn thường ảnh hưởng đến mã nguồn có khả năng tiếp cận bị giới hạn bởi phần cứng (hardware-gated). Phương pháp trình bày ở đây sẽ giúp bất kỳ ai xác định liệu một lỗ hổng Windows kernel mode driver cụ thể có thể tiếp cận được hay không — và do đó có khả năng khai thác được hay không — ngay cả khi không có phần cứng đi kèm.

Người đọc được kỳ vọng có kiến thức cơ bản về Windows driver, đặc biệt là về các device objects. Phần còn lại của bài viết được viết với giả định rằng người đọc đã quen thuộc với các khái niệm được mô tả trong bài viết giới thiệu: Anatomy of Access: Windows Device Objects from a Security Perspective.

Giống như bài viết giới thiệu, tài liệu này không tập trung vào bất kỳ loại lỗi cụ thể nào, mà tập trung vào bề mặt tấn công (attack surface) và kiến trúc Windows Plug and Play.

Tất cả các thử nghiệm được trình bày ở đây đều được thực hiện trên Windows 11 23H2 (winver 10.0.22631.3007).

Để biết thêm các nghiên cứu về mối đe dọa và tư vấn lỗ hổng mới nhất, vui lòng đăng ký Atos Cyber Shield blogs.

2. Giá trị tấn công của các kernel mode drivers

Ngoài tiềm năng leo thang đặc quyền cục bộ (Local Privilege Escalation) rõ rệt, các driver lỗi thường bị lạm dụng trong các cuộc tấn công BYOVD (Bring Your Own Vulnerable Driver) — một kỹ thuật hậu khai thác được những kẻ tấn công sử dụng để phá vỡ các hệ thống phòng thủ như các thành phần EDR.

Hai tiêu chí chính xác định liệu một lỗ hổng driver có phải là ứng cử viên sáng giá cho các cuộc tấn công BYOVD hay không: 1. Việc khai thác cho phép phá vỡ một cách có ý nghĩa các thành phần bảo mật chống giả mạo. Ví dụ bao gồm các lỗ hổng cấp kernel cho phép đọc/ghi bộ nhớ tùy ý, thực thi mã tùy ý hoặc lạm dụng tài nguyên tùy ý (ví dụ: ghi đè tệp, đóng handles hoặc chấm dứt tiến trình). 2. Khả năng khai thác của nó độc lập với các điều kiện hệ thống hiếm gặp, chẳng hạn như sự hiện diện của phần cứng cụ thể.

Mặc dù các cuộc tấn công kiểu BYOVD đã được ghi nhận đầy đủ trong nhiều năm qua với vô số báo cáo công khai, nhưng chưa có báo cáo nào xem xét cụ thể vai trò của việc giới hạn bởi phần cứng (hardware-gating) trong khả năng tiếp cận lỗ hổng driver.

3. Tạo và duy trì device object - Các mô hình phổ biến

Phân tích trong tài liệu này được cấu trúc xoay quanh các device objects, vì chúng là vector tấn công khả thi nhất. Tuy nhiên, các kỹ thuật được trình bày ở đây thực tế có tác động đến khả năng tiếp cận mã nguồn driver từ userland nói chung, không chỉ thông qua IRP.

Những trở ngại phổ biến nhất khi tấn công một driver thông qua device object của nó là: 1. Device object không được tạo. 2. Trạng thái nội bộ của driver không cho phép thực hiện hành vi lỗi mặc dù device object có thể truy cập được.

Cả hai kịch bản đều rất phổ biến khi xử lý một device driver được triển khai trên một hệ thống không có phần cứng vật lý tương ứng.

Trong phần còn lại của bài viết, tôi thường đề cập đến device stacks và device nodes. Mặc dù device nodedevice stack không giống nhau, nhưng các thuật ngữ này thường được sử dụng thay thế cho nhau vì mỗi device node có chính xác một device stack.

3.1 Tạo vô điều kiện khi load driver

Nhiều driver, đặc biệt là các driver không phải PnP, tạo các device objects của chúng trực tiếp từ bên trong hàm DriverEntry, hoặc từ một hàm khác được gọi trong chuỗi lệnh trực tiếp bắt nguồn từ DriverEntry.

CDO creation
Việc tạo CDO được gọi trực tiếp từ DriverEntry

Driver cũng xóa device object bằng cách gọi IoDeleteDevice, nhưng điều đó chỉ xảy ra khi DriverUnload được gọi (khi driver đang bị gỡ bỏ):

CDO cleanup
Dọn dẹp CDO từ DriverUnload

Các driver được xây dựng theo cách này có thể tương tác sau khi triển khai đơn giản chỉ với hai bước:

  • Tạo dịch vụ cho driver: sc.exe create SampleDrv type= kernel start= demand binPath= System32\drivers\SampleDrv.sys
  • Khởi chạy dịch vụ (driver sẽ load): sc.exe start SampleDrv

Nếu chúng ta nhìn vào một driver ngẫu nhiên từ loldrivers.io, chúng ta sẽ thấy lệnh triển khai của nó khớp với mô hình này:

LOL drivers deployment
Triển khai driver zam64.sys

3.2 Tạo và duy trì thiết bị có điều kiện

Thông thường, các thủ tục khởi tạo driver thực hiện các kiểm tra bổ sung. Ví dụ, các thành phần kernel mode của phần mềm bảo mật (EDR, anti-virus, giám sát, xác thực nâng cao, v.v.) có xu hướng kiểm tra các registry keys đặc thù của sản phẩm.

Các device driver thực tế (được tạo để điều khiển phần cứng vật lý) có xu hướng chỉ tạo các device objects của chúng khi có sự hiện diện của phần cứng đó. Nếu không có phần cứng, chúng sẽ: - Không cố gắng tạo bất kỳ device object nào, - Hoặc chúng sẽ xóa bất kỳ device object nào ngay sau khi tạo bằng cách gọi IoDeleteDevice.

3.3 Các callback đặc thù của PnP là vị trí chính của logic khởi tạo PnP driver

Trong các driver tương thích với PnP, logic khởi tạo mở rộng ra ngoài DriverEntry vào các routine sau: AddDevice và trình xử lý IRP_MJ_PNP.

3.3.1 AddDevice

Tất cả các driver tương thích PnP phải định nghĩa routine này. Nó chịu trách nhiệm tạo các Functional Device Objects (FDO)Filter Device Objects (filter DO) cho các thiết bị được liệt kê bởi trình quản lý PnP. AddDevice không được gọi từ bên trong DriverEntry, nghĩa là nó không tự động thực thi khi load driver. Thay vào đó, trình quản lý PnP chỉ gọi nó sau khi phát hiện một device node mới.

Việc gọi AddDevice là tối quan trọng vì:

  1. Nó cần thiết để driver khởi tạo đúng cách, giúp mã nguồn lỗi có thể tiếp cận được từ userland.
  2. Quan trọng hơn, mục đích của AddDevice là tạo một device object mới tương thích PnP và đính kèm nó vào device stack trên cùng của PDO.

3.3.2 IRP_MJ_PNP

IRP_MJ_PNP là mã IRP MajorFunction dành riêng cho các tương tác liên quan đến PnP. Các driver WDF (KMDF) đăng ký các callback thay đổi trạng thái PnP/Power thông qua WdfDeviceInitSetPnpPowerEventCallbacks.

3.4 Tương tác và thăm dò phần cứng chủ động

Chỉ một phần nhỏ mã nguồn driver thực sự tương tác với phần cứng vật lý thông qua các cơ chế như: Port I/O, Memory-Mapped I/O (MMIO), PCI configuration space, ACPI, DMA, và ngắt (interrupts).

4. Cách tiếp cận triển khai driver từ góc độ BYOVD

Trong phần này, chúng ta sẽ đánh giá mức độ ảnh hưởng đối với việc khởi tạo driver chỉ bằng cách vận hành từ userland (với quyền quản trị).

4.1 Triển khai đơn giản bằng sc.exe

Đây là bước tối thiểu để kích hoạt việc load driver. Tuy nhiên, cách này thường không đủ cho các PnP device objects vốn là bề mặt tấn công phổ biến hơn.

4.2 Tạo các thiết bị giả lập phần mềm với Hardware ID giả mạo

Sử dụng devcon.exe để tạo các device nodes với Hardware ID tùy ý để kích hoạt callback AddDevice. Điều này cho phép làm cho một số driver có thể tiếp cận được mà không cần phần cứng thực tế.

Named devices created
Các thiết bị định danh mới được tạo trong quá trình cài đặt devcon

4.3 Nhảy stack thiết bị (Jumping device stacks)

Việc làm cho một driver tương thích PnP có thể tiếp cận được bằng một thiết bị giả lập phần mềm là một ví dụ về việc xây dựng và truy cập một custom device stack. Điều này mở ra cách tương tác qua IRP với các driver chưa bao giờ được dự định để tương tác từ userland.

4.3.1 Filter restacking

Chúng ta có thể triển khai một filter driver bằng cách đặt nó lên trên một device stack của ổ đĩa (Disk Drive class) để có thể mở một handle và tương tác với nó.

Filter driver on disk stack
Chạy một gaming mouse filter trên đỉnh của disk stack

4.4 Thay thế driver cưỡng bức

Thay vì tạo thiết bị mới, chúng ta có thể ép buộc driver của mình được cài đặt cho một phần cứng hiện có trong hệ thống bằng cách sửa đổi các cấu trúc registry, bỏ qua cơ chế tệp INF.

5. Lời kết

Mặc dù các lỗ hổng nghiêm trọng vẫn còn phổ biến trong Windows kernel mode drivers, không phải tất cả driver lỗi đều có giá trị thực tế cho BYOVD do các rào cản về phần cứng. Tuy nhiên, bằng cách sử dụng các thiết bị giả lập hoặc thay thế driver cưỡng bức, nhiều rào cản này có thể bị vượt qua chỉ từ userland. Các nhà phòng thủ cần chú ý đến dấu vết forensic liên quan đến các kỹ thuật này để bảo vệ hệ thống tốt hơn.

Ghi chú: Bài viết này được đóng góp bởi Julian Horoszkiewicz từ Atos Threat Research Center.