TL;DR: This post looks at the CVE-2020-16938 (Bits Please) vulnerability. It also looks at how, even after the patch has been applied, an attacker (with System level privileges) can re-enable the weakness as a type of persistent backdoor.
CVE-2020-16938
A few days ago a friend shared a link to a recent tweet from @jonasLyk of Secret Club:
Although this issue only has a CVSS score of 5.5 (a medium by most scales), it has some pretty significant implications. In unpatched versions of
Windows 10 and Windows Server version 2004 (released May 2020), low privilege users can get a handle to disks with the FILE_READ_DATA
permission. Assuming the disk is not encrypted, it is possible to bypass file access controls and read files directly from the disk. This vulnerability could facilitate several offensive actions beyond just Data Collection (TA0009), including Privilege Escalation via Valid Accounts (T1078).
Although the patch fixes this vulnerability, I felt that having the ability to enable a NinjaCopy style attack for users with low privileges was an interesting idea for a persistent backdoor (of sorts). I wanted to see how difficult it would be to re-enable normal users to read (and write) directly to disks.
Patch Reversing
To try to better understand the root cause of the vulnerability, I thought it would first help to take a look at the patch. To extract the files in the patch, you can use the following commands:
mkdir patch_ouptut
expand -F:* <patch>.msu .\patch_output
mkdir .\patch_output\cab_output
expand -F:* <path>.cab .\patch_output\cab_output
The KB4579311 security update contains a very large number of files. Searching for files with 'disk' in the name turned up several candidates. The first file I took a look at (because INF files don't require any reversing tools to review) was c_diskdrive.inf
. A quick search of this filename led me to a tweet by James Forshaw (@tiraniddo) with Google Project Zero. It was the first hit, and it was directly related to this vulnerability (what luck):
The DiskDrive Setup Class
Device Setup Classes optimize driver installation for devices installed in the same manner. While the documentation I could find was limited, the file located at %systemroot%\INF\c_diskdrive.inf
appears directly related to the Device Setup Class for the DiskDrive
class. Note that the Class GUID {4d36e967-e325-11ce-bfc1-08002be10318} in the INF file matches that of the DiskDrive
class found in HKLM\SYSTEM\ControlSet\Control\Class\{4d36e967-e325-11ce-bfc1-08002be10318}
. The values of its subkeys (some of which are only visible to the System user) also match values in the INF.
One line in c_diskdrive.inf
is of relevance to the vulnerability. Under the [ClassInstall_AddReg]
section, there is an attribute that specifies a security descriptor (what James was referencing in the above tweet). Looking in the registry (as a System user) the Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4d36e967-e325-11ce-bfc1-08002be10318}\Properties
key holds a REG_BINARY value with the name Security
.
Using PowerShell, it is possible to confirm that the binary Security descriptor in the Registry value matches the security descriptor in the c_diskdrive.inf
file. Note that the following must be run as the System user (e.g., psexec -is powershell.exe
):
$binarySD = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4d36e967-e325-11ce-bfc1-08002be10318}\Properties").Security
([wmiclass]"Win32_SecurityDescriptorHelper").BinarySDToSDDL($binarySD).SDDL
Security Descriptor Definition Language (SDDL)
A Security Descriptor holds the security information for secureable objects. Information includes owner and group information, and optionally a Discretionary Access Control List (DACL) to set permissions and a System Access Control List (SACL) to control logging. On disk (and in memory) this is a binary format, but the Security Descriptor Definition Language makes it possible to represent Security Descriptors as strings.
To make things easy, I will break down the vulnerable security descriptor here:
D:P(A;;GA;;;BA)(A;;GA;;;SY)(A;;GR;;;WD)(A;;GRGW;;;UD)
- D: specifies that the following text describes a DACL.
- P Sets SE_DACL_PROTECTED which "Prevents the DACL of the security descriptor from being modified by inheritable ACEs".
- (A;;GA;;;BA) This gives built-in administrators (BA) Generic All (GA) acess (A) to the object.
- (A;;GA;;;SY) This gives local system (SY) Generic All (GA) access (A) to the object.
- (A;;GR;;;WD) This gives everyone (WD) Generic Read (GR) acess (A) to the object. This is what causes the vulnerability.
- (A;;GRGW;;;UD) This gives user-mode drivers (UD) Read and Write (GRGW) access (A) to the object.
Although reading SDDL strings isn't easy, PowerShell makes them easier to decode:
(ConvertFrom-SddlString "D:P(A;;GA;;;BA)(A;;GA;;;SY)(A;;GR;;;WD)(A;;GRGW;;;UD)").DiscretionaryAcl
After the patch, c_diskdrive.inf
uses the following SDDL:
D:P(A;;GA;;;BA)(A;;GA;;;SY)(A;;GX;;;WD)(A;;GX;;;RC)(A;;GRGW;;;UD)
.
Here is what has changed:
- (A;;GX;;;WD) This gives everyone (WD) Generic Execute (GX) access (A) to the object instead of Generic Read.
- (A;;GX;;;RC) This adds a new entry that gives Restricted Code (RC) Generic Execute (GX) access (A) to the object.
The removal of the Generic Read permission for Everyone appears to have fixed the issue.
More Bits Please
Although the patch fixes this issue, I wanted to see how a user with high privileges could make the Disk Setup Class use a weak security descriptor once again. Giving normal users the ability to read directly from disks will enable non-elevated processes (less suspicious in many cases) to access sensitive files. Also, with write enabled, direct disk access could act as a type of persistent backdoor. It is important to call out that re-enabling raw disk access is just an interesting technique and it does not take advantage of CVE-2020-16938 or the patch. It requires System level privileges...and an attacker with that level of access can do about anything to the system.
To try to re-enable direct read access to the disk, I first tried to change the security descriptor in c_diskfile.inf
and then rebooted the system. When this did not work, I tried to manually re-install the class driver using pnputil
and rundll32.exe setupapi.dll
, but this was also unsuccessful.
Next, I decided to just try to change the Security value in the registry directly. After some searching, I found an easy way to convert the desired SDDL into a binary format using PowerShell. Note that the following commands must be run as a System user:
# Update the SDDL to give GA access to everyone (WD)
$binarySD = ([wmiclass]"Win32_SecurityDescriptorHelper").SDDLToBinarySD("D:P(A;;GA;;;BA)(A;;GA;;;SY)(A;;GA;;;WD)(A;;GWGR;;;UD)").BinarySD
Set-ItemProperty -Force -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4d36e967-e325-11ce-bfc1-08002be10318}\Properties" -Name "Security" -Value $binarySD
After a reboot, low privilege users can directly access disk devices installed via the DiskDrive Setup Class (with Generic All
permissions). This change survives subsequent reboots, but will probably not survive any future changes to the DiskDrive setup class.
Mitigation
Enabling disk encryption helps protect the contents of the underlying disk. With disk encryption enabled, even with full read or write access to the underlying disk, an attacker will have to find a way to decrypt the contents of the disk.
Additional Credit
Post Image Photographer: @bohed