
CVE-2024-51324(BYOVD)에 대한 석사 논문 연구. 4가지 작동 모드(SCANNER, LOADER, KILLER, CLEANUP), SHA-256 드라이버 검증 및 전체 학술 문서를 갖춘 고급 익스플로잇. 포트폴리오 작품으로 Windows 커널 드라이버 보안, IOCTL 리버스 엔지니어링 및 BYOVD 악용을 다룹니다.
자체 취약 드라이버 가져오기 (BYOVD) — 바이두 안티바이러스
BdApiUtil64.sys
세 가지 문서화되지 않은 커널 프리미티브: 프로세스 종료, 임의 파일 삭제, 및SectionObjectPointer우회를 통한 사용 중인 파일 삭제
영향받는 제품: Baidu Antivirus v5.2.3.116083 (BdApiUtil64.sys)
취약 드라이버를 커널에 로딩 중 (LOADER 모드)
이 저장소는 CVE-2024-51324에 대한 석사 논문 연구를 포함하며, 이는 Baidu Antivirus의 커널 드라이버 BdApiUtil64.sys의 자체 취약 드라이버 가져오기 (BYOVD) 취약점입니다.
NVD 기록은 CVSS v3.1 기본 점수 3.8 (Low) 와 벡터 AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N 및 CWE-269 (부적절한 권한 관리)를 할당합니다. 이 점수는 이 연구에서 문서화된 로컬 공격 현실을 반영하지 않습니다. 관리자가 드라이버를 로드하면 (소셜 엔지니어링 또는 로컬 권한 상승을 통해 한 번만 수행하면 되는 단계) 이후 모든 프로세스(샌드박스 또는 표준 사용자 프로세스 포함)는 추가 권한 검사 없이 IOCTL을 보낼 수 있습니다. 연구자가 평가한 CVSS v3.1 점수 7.8 (High) 와 벡터 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을 통한 정적 분석에 따르면 내부 메커니즘은 이전에 문서화된 것보다 더 중요합니다. 드라이버는 ZwOpenProcess 대신 PsLookupProcessByProcessId + ObOpenObjectByPointer(KernelMode)를 사용하여 SeAccessCheck를 완전히 우회합니다. 세 가지 IOCTL 프리미티브가 완전히 특성화되었으며, 그중 두 가지는 이전에 공개 문서화된 바가 없습니다.
| 항목 | 설명 |
|---|---|
| 기술적 수정 | ZwOpenProcess는 임포트 테이블에 없으며, 실제 메커니즘은 PsLookupProcessByProcessId + ObOpenObjectByPointer(KernelMode)로, 이는 SeAccessCheck를 무조건 우회합니다 |
| 세 가지 문서화된 프리미티브 | 프로세스 종료 (0x800024B4), 임의 파일 삭제 (0x80002648), 및 SectionObjectPointer 우회를 통한 사용 중인 파일 삭제 (0x8000264C) — 마지막 두 개는 이전에 공개 문서화된 바가 없습니다 |
| 네 가지 작동 모드 | LOADER, KILLER, SCANNER, CLEANUP — 전체 수명 주기 관리 |
| SHA-256 검증 | 로드 시도 전 드라이버 해시 확인 |
| PPL 경험적 테스트 | 프로세스 범주당 10회 시도, PPL이 유일한 런타임 완화임을 확인 |
| 포렌식 분석 | 정리 후에도 남는 이벤트 ID 7045; 이벤트 ID 1102는 로그 삭제 자가-범죄 증거 |
| 탐지 규칙 | 시그마 규칙 및 Sysmon 구성 (해시 기준 이벤트 ID 6 + 레지스트리 키 기준 이벤트 ID 13) |
| CVSS 재평가 | 공식 NVD 점수(3.8 Low)와 연구자 평가 로컬 악용 심각도(7.8 High) 간의 차이 문서화 |
CVE-2024-51324/
├── README.md
├── LICENSE
│
├── drivers/
│ └── BdApiUtil64.sys # 드라이버 (배포되지 않음)
│
├── exploit/
│ ├── exploit-explanation.md
│ └── byovd_killer.py # 주요 익스플로잇 — 4가지 작동 모드
│
└── 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 # 전체 Ghidra RE, 세 가지 프리미티브, PPL 테스트
└── 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
| 모드 | 명령어 | 권한 | 설명 |
|---|---|---|---|
| SCANNER | --scan | 모든 사용자 | 시스템 및 드라이버 상태 정보 |
| LOADER | --load | 관리자 | 커널 서비스 생성을 통해 드라이버 로드 |
| KILLER | --kill / --pid | 모든 사용자 | IOCTL을 통해 프로세스 종료 |
| CLEANUP | --cleanup | 관리자 | 드라이버 서비스 중지 및 삭제 |









Ghidra 11.0.3을 통한 BdApiUtil64.sys의 역공학은 이전의 모든 공개 출처보다 더 넓은 공격 표면을 식별했습니다:
| IOCTL | 핸들러 | 프리미티브 | 이전 문서화 |
|---|---|---|---|
0x800024B4 | FUN_000152b0 | 프로세스 종료 | 부분적 (메커니즘 부정확) |
0x80002648 | FUN_00013bb0 | 임의 파일 삭제 | 없음 |
0x8000264C | FUN_00013850 | 사용 중인 파일 삭제 (SectionObjectPointer 우회) | 없음 |
0x800024B4)디스패치 체인은 세 가지 수준으로 구성됩니다:
IOCTL 0x800024B4
└─ FUN_00028630 (IRP_MJ_DEVICE_CONTROL 디스패처)
└─ FUN_00015230 (래퍼: IOCTL 코드 및 버퍼 크기 = 4바이트 확인)
└─ FUN_000152b0 (종료 핸들러 — 취약점 핵심)
복원된 핸들러 (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 ← SeAccessCheck 우회
local_res18
);
ZwTerminateProcess(local_res18[0], 0);
}
KernelMode가 SeAccessCheck를 우회하는 이유:
ZwOpenProcess 경로:
NtOpenProcess → ObOpenObjectByName → SeAccessCheck
(DACL, 호출자 토큰, 무결성 수준 확인)
STATUS_ACCESS_DENIED 반환 가능
ObOpenObjectByPointer(KernelMode) 경로:
SeAccessCheck ← 호출되지 않음
→ PROCESS_ALL_ACCESS 핸들이 무조건 부여됨
ZwOpenProcess는 드라이버의 임포트 테이블에 없습니다. 이전 출처에 있는 ZwOpenProcess에 기반한 설명은 기술적으로 부정확합니다.
0x80002648)