CVE-2020-13517
An information disclosure vulnerability exists in the WinRing0x64 Driver IRP 0x9c406104 functionality of NZXT CAM 4.8.0. A specially crafted I/O request packet (IRP) can cause the disclosure of sensitive information. An attacker can send a malicious IRP to trigger this vulnerability.
NZXT CAM 4.8.0
6.5 - CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
CWE-269 - Improper Privilege Management
NZXT CAM is software designed as an all-in-one solution for computer hardware monitoring and performance. The software monitors fan speeds, CPU temperatures, network and RAM usage, as well as CPU/GPU frequencies for overclocking. It also has features for in-game overlays to track PC performance. The software also has an inventory for all devices that are installed on the PC at any given time.
The WinRing0x64 driver exists so that the NZXT CAM software can have access to the Windows Kernel as well as elevated privileges required to talk to PCI devices as well as making CPU/GPU configuration changes. This driver creates \Device\WinRing0_1_2_0
that is accessible to any user on the system and this driver is used for all elevated tasks.
Using the IRP 0x9c406104 gives a low privilege user direct access to the MmMapIoSpace
function that can read memory between 0xC_0000 and 0xF_FFFF. The memory pointed to by MmMapIoSpace
is physical memory of the device, this location in physical memory often stores BIOS information or the motherboards firmware. This access could be used for leak sensitive information.
00011520 uint64_t rbx = zx.q(arg4)
0001151d int64_t rax_6
0001151d if (arg2 != 0x10)
000115c1 label_115c1:
000115c1 rax_6 = 0xc000000d
00011532 else
00011532 uint64_t rax_2 = zx.q(*(arg1 + 0xc) * *(arg1 + 8))
00011538 if (rbx:0.d u< rax_2:0.d)
00011538 goto label_115c1
0001153e int64_t rcx = *arg1
00011548 if (rcx s< 0xc0000)
00011548 goto label_115c1
0001154a uint64_t rbp_1 = zx.q(rax_2:0.d)
00011557 if (rcx + rax_2 - 1 s> 0xfffff)
00011557 goto label_115c1
0001155f int64_t rax_4 = MmMapIoSpace(rcx, rbp_1, 0)
00011565 uint64_t rcx_1 = zx.q(*(arg1 + 8))
00011568 int64_t r12
00011568 r12:0.b = 0
0001156b uint64_t rcx_2 = zx.q(rcx_1:0.d - 1)
0001156b if (rcx_1:0.d == 1)
0001159a uint64_t rcx_6 = zx.q(*(arg1 + 0xc))
0001159d int32_t* rdi_3 = arg3
000115a0 int32_t* rsi_3 = rax_4
000115a3 for (; rcx_6 != 0; rcx_6 = rcx_6 - 1)
000115a3 *rdi_3 = *rsi_3
000115a3 rdi_3 = rdi_3 + 1
000115a3 rsi_3 = rsi_3 + 1
00011570 else
00011570 uint64_t rcx_3 = zx.q(rcx_2:0.d - 1)
00011570 if (rcx_2:0.d == 1)
0001158c uint64_t rcx_5 = zx.q(*(arg1 + 0xc))
0001158f int32_t* rdi_2 = arg3
00011592 int32_t* rsi_2 = rax_4
00011595 for (; rcx_5 != 0; rcx_5 = rcx_5 - 1)
00011595 *rdi_2 = *rsi_2
00011595 rdi_2 = rdi_2 + 2
00011595 rsi_2 = rsi_2 + 2
00011575 else if (rcx_3:0.d != 2)
0001157a r12:0.b = 1
0001157f else
0001157f uint64_t rcx_4 = zx.q(*(arg1 + 0xc))
00011582 int32_t* rdi_1 = arg3
00011585 int64_t rsi_1 = rax_4
00011588 for (; rcx_4 != 0; rcx_4 = rcx_4 - 1)
00011588 *rdi_1 = *rsi_1
00011588 rdi_1 = rdi_1 + 4
00011588 rsi_1 = rsi_1 + 4
000115ab MmUnmapIoSpace(rax_4, rbp_1)
000115b4 if (r12:0.b != 0)
000115b4 goto label_115c1
000115bb *arg5 = rbx:0.d
000115bd rax_6 = 0
000115e0 return rax_6
This proof of concept reads 0x1_0000 bytes of data starting from 0xF_0000 of physical memory. This is the beginning of the motherboard bios.
[+] Getting Device Driver Handle
[+] Device Name: \\.\WinRing0_1_2_0
[+] Device Handle: 0x94
[+] Setting Up Vulnerability Stage
[+] Allocating Memory For Buffer
[+] Memory Allocated: 0x0000026669513F50
[+] Allocation Size: 0x10
[+] Preparing Buffer Memory Layout
000F0000 00000000 00000004 00004000
0000CA9E 00000000 00000000 00000000 24454649 000253B9 00008307 010BF000 0C00F000 DA438018 00000000 000F05A0 6F400000 0198000E C7800000 0120000F 00000000 00000000 E4000000 00000000 E0000000 00004004 00000000 00000000 000FF800 00000000 FFFFFFFF...[output truncated]
2020-07-17 - Vendor Disclosure
2020-08-10 - Vendor acknowledged; Talos issued copy of reports
2020-11-30 - Public Release
Discovered by Carl Hurd of Cisco Talos.