A while ago Jonas Lykkegaard disclosed a zeroday that could be used to create files in the SYSTEM folder. CVE-2020-16885 got assigned for this vulnerability, and was since patched with KB4580346. This vulnerability was very convenient for Dynamic-link library (DLL) side-loading, which I will show in this blog post. Below you can find his original Twitter message.
The screenshot he posted shows everything that is needed to exploit and I wanted to verify this.
So what is NtCreateFile?
NtCreateFile is a function within
NTDLL.dll and is used to either create a new file or directory, or open an existing file, device, directory, or volume. Microsoft has documented this function quite well too.
And what is STORVSP?
Hyper-V STORVSP stands for ‘Storage Virtual Service Provider’ and is a paravirtualised device hosted in the Kernel. There are some good BlackHat presentations available on Hyper-V where one of them shows the flow for STORVSP. Note that STORVSP operates in Kernel mode on the I/O stack.
Verifying the vulnerability
But does the exploit work? For a quick test you can download FileTest. The image below shows the values Jonas used in his Twitter message where the expected outcome is that a file called
test.txt is created in the
After the ‘NtCreateFile’ button is pressed, the file was indeed created, and as a low privileged user I also had full control over it.
This meant that the vulnerability found by Jonas worked (Microsoft has since patched the vulnerability before this blog post was made public). I validated this vulnerability against multiple Windows features that make use of Hyper-V too, namely:
- Windows Sandbox
- Windows Credential Guard
Windows Subsystem for Linux does not seem to be vulnerable, but Windows Credential Guard seems to enable all the Hyper-V features.
Low privileged users were allowed to create files with
\Device\STORVSP\vSMB\??\C:\Windows\System32\ as filename. Since STORVSP is in Kernel mode and there was no check on privileges, it was possible to place files in protected folders like the SYSTEM folder.
Chaining with DLL side-loading
This arbitrary write vulnerability was all you needed to perform a DLL side-loading attack. DLL side-loading is a popular attack method that takes advantage of how Microsoft Windows handles loading DLL’s.
If your program doesn’t specify the absolute path to a DLL, a search is conducted by Windows to try to find that DLL and load it. If
SafeDllSearchMode is enabled, the search order is as follows:
- The directory from which the application was loaded.
- The system directory. Use the
GetSystemDirectoryfunction to get the path of this directory.
- The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
- The Windows directory. Use the
GetWindowsDirectoryfunction to get the path of this directory.
- The current directory.
- The directories that are listed in the
PATHenvironment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.
For this attack a spoofed (malicious) DLL file is (most commonly) placed in a Windows ‘SYSTEM’ directory so that the operating system loads it instead of the legitimate file.
Let’s chain Jonas’ finding with DLL side-loading.
For testing purposes, the following things are necessary to prepare:
- VM with Windows 10 x64 with low privileged user;
- Hyper-V enabled;
- Defender disabled (just easier for working with msfvenom payloads);
- File Test;
- SysInternals – Procmon.
Finding a missing DLL to load
You do not want to create files randomly, but instead create one that you know your target searches for. The first step is to determine if the target tries to load DLL files (hopefully as
AUTHORITY\SYSTEM) that cannot be found. This can be done with Procmon which is part of the SysInternals suite.
The filters I used in Procmon were:
The result would be different per target, but in this example you see that
webio.dll is searched for by
NT AUTHORITY\SYSTEM, but cannot be found.
UpdateNotificationMgr.exe runs when the
RunUpdateNotificationMgr task is started. This is a task that can be started as a low privileged user, but runs as ‘SYSTEM’ user.
We can now use the arbitrary write vulnerability to create the missing DLL file. Start FileTest as a restricted user and place the correct parameters according to the screenshot of Jonas to create
webio.dll in the
That looks good as the status is
STATUS_SUCCESS. Let’s validate if the file was created:
Great. The file is created, but do we have permissions to edit this file as a restricted user?
Oh yeah baby, Full control!
Creating the payload
You may have noticed that the created file is empty. This is ok. Since we have full control over the file we can modify it after creation. For the contents of the malicious DLL file, I used MSFvenom for a quick payload. MSFvenom is part of MetaSploit and can be used to create and encode payloads. The steps below show how a payload could be created. Keep in mind that payloads created by MSFvenom are often found by endpoint security solutions.
Creating a payload and saving it to
dll_payload.txt using msfvenom may look something like this for a simple command that adds a new local administrator:
msfvenom -p windows/x64/exec -a x64 cmd='cmd.exe /k "net user /add ntcreatefile OCDyear2020! && net localgroup administrators ntcreatefile /add"' Exitfunc=thread -f dll -o dll_payload.txt
Placing the content of the payload in the DLL, we can
type it to our file in System32:
type c:\tmp\dll_payload.txt > C:\Windows\System32\UNP\webio.dll
A quick recap
We have found a way to load a DLL file with the
NT AUTHORITY\SYSTEM user rights. We used the vulnerability to create the file and we used MSFvenom to create the payload. Let’s run the task now to see what happens.
net users in the command prompt verifies that the user is created and is a member of the local administrators group.
An official patch for this vulnerability exists as KB4580346. For the period that this vulnerability did not have a patch though, detection was the next best thing. While testing, Microsoft Defender did not detect the creation of a file in a ‘SYSTEM’ folder by a profile that was not in an administrators group. Firing up the Event Viewer and looking for Hyper-V STORVSP events also did not show any results either. None of the Hyper-V logs were showing events that might lead to detection.
What you could do was to monitor ‘SYSTEM’ folders for the creation of files by a profile that was not in an administrator group. This would not be a perfect detection since DLL files can be loaded from locations other than the ‘SYSTEM’ folder, but perhaps this would be an interesting case to try.
Overall, this was fun :) Thank you Jonas for your time to chat about this finding.